Verwenden Sie GCC, um eine lesbare Baugruppe zu erstellen?


256

Ich habe mich gefragt, wie man GCC benutzt in meiner C-Quelldatei verwenden soll, um eine mnemonische Version des Maschinencodes zu sichern, damit ich sehen kann, in was mein Code kompiliert wird. Sie können dies mit Java tun, aber ich konnte mit GCC keinen Weg finden.

Ich versuche, eine C-Methode in Assembly neu zu schreiben, und zu sehen, wie GCC dies tut, wäre eine große Hilfe.


25
Beachten Sie, dass "Bytecode" normalerweise den Code bedeutet, der von einer VM wie JVM oder der CLR von .NET verwendet wird. Die Ausgabe von GCC wird besser als "Maschinencode", "Maschinensprache" oder "Assemblersprache" bezeichnet
Javier

2
Ich habe eine Antwort mit Godbolt hinzugefügt, da es ein sehr leistungsfähiges Werkzeug ist, um schnell zu experimentieren, wie sich verschiedene Optionen auf Ihre Codegenerierung auswirken.
Shafik Yaghmour



Weitere Tipps, wie Sie die ASM-Ausgabe für den Menschen lesbar machen können, finden Sie auch unter: Entfernen von „Rauschen“ aus der Ausgabe der GCC / Clang-Baugruppe?
Peter Cordes

Antworten:


335

Wenn Sie mit Debug-Symbolen kompilieren, können Sie objdumpeine besser lesbare Demontage erstellen.

>objdump --help
[...]
-S, --source             Intermix source code with disassembly
-l, --line-numbers       Include line numbers and filenames in output

objdump -drwC -Mintel ist nett:

  • -rZeigt Symbolnamen bei Umzügen an (so wie putsin der folgenden callAnleitung dargestellt).
  • -R zeigt dynamisch verknüpfte Verschiebungen / Symbolnamen (nützlich für gemeinsam genutzte Bibliotheken)
  • -C entwirrt C ++ - Symbolnamen
  • -w ist der "breite" Modus: Die Maschinencode-Bytes werden nicht in Zeilenumbruch gebracht
  • -Mintel: Verwenden Sie GAS / binutils MASM-ähnliche .intel_syntax noprefixSyntax anstelle von AT & T.
  • -S: Verschachteln Sie die Quellleitungen mit der Demontage.

Sie könnten so etwas alias disas="objdump -drwCS -Mintel"in Ihre setzen~/.bashrc


Beispiel:

> gcc -g -c test.c
> objdump -d -M intel -S test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
#include <stdio.h>

int main(void)
{
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   83 e4 f0                and    esp,0xfffffff0
   6:   83 ec 10                sub    esp,0x10
    puts("test");
   9:   c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
  10:   e8 fc ff ff ff          call   11 <main+0x11>

    return 0;
  15:   b8 00 00 00 00          mov    eax,0x0
}
  1a:   c9                      leave  
  1b:   c3                      ret

3
Gibt es einen Schalter, um nur die Intel-Anweisungen abzurufen?
James

3
All dies sind Intel-Anweisungen, da sie auf Intel-Prozessoren ausgeführt werden: D.
toto

12
@toto Ich denke, er meint Intel-Syntax anstelle von AT & T-Syntax
Amok

7
Auf die Zwischenobjektdatei kann mit der Schaltfolge verzichtet werden -Wa,-adhln -g to gcc. Dies setzt voraus, dass der Assembler Gas ist, und dies ist möglicherweise nicht immer der Fall.
Marc Butler

8
@ James Ja, liefern -Mintel.
Fuz

106

Wenn Sie GCC die Flagge geben -fverbose-asm, wird es

Fügen Sie zusätzliche Kommentarinformationen in den generierten Assemblycode ein, um ihn besser lesbar zu machen.

[...] Die hinzugefügten Kommentare umfassen:

  • Informationen zur Compilerversion und zu den Befehlszeilenoptionen,
  • die mit der Montageanleitung verknüpften Quellcodezeilen in der Form FILENAME: LINENUMBER: CONTENT OF LINE,
  • Hinweise, welche übergeordneten Ausdrücke den verschiedenen Assembler-Anweisungsoperanden entsprechen.

Aber dann würde ich den gesamten Schalter verlieren, für den objdump- objdump -drwCS -Mintelalso wie kann ich so etwas wie verbosemit verwenden objdump? Damit ich Kommentare in asm-Code haben kann, wie -fverbose-asmin gcc?
Hirte

1
@Herdsman: das kannst du nicht. Das zusätzliche Material, das -fverbose-asmhinzugefügt wird, besteht aus Kommentaren in der asm-Syntax der Ausgabe und nicht aus Anweisungen, die zusätzliche Elemente in die .oDatei einfügen. Es wird alles zum Zeitpunkt der Montage verworfen. Sehen Sie sich die asm-Ausgabe des Compilers an, anstatt sie zu zerlegen, z. B. auf godbolt.org, wo Sie sie einfach mit der Maus über die Mauszeile und die farbliche Hervorhebung der entsprechenden Quell- / asm-Zeilen abgleichen können. Wie entferne ich "Rauschen" von der Ausgabe der GCC / Clang-Baugruppe?
Peter Cordes

75

Verwenden Sie den Schalter -S (Hinweis: Großbuchstabe S) zu GCC, und der Assemblycode wird an eine Datei mit der Erweiterung .s ausgegeben. Zum Beispiel der folgende Befehl:

gcc -O2 -S foo.c

belässt den generierten Assemblycode in der Datei foo.s.

Direkt von http://www.delorie.com/djgpp/v2faq/faq8_20.html gerippt (aber fehlerhaft entfernt -c)


35
Sie sollten -c und -S nicht mischen, sondern nur eine davon verwenden. In diesem Fall überschreibt einer den anderen, wahrscheinlich abhängig von der Reihenfolge, in der sie verwendet werden.
Adam Rosenfield

4
@AdamRosenfield Gibt es einen Hinweis zu 'sollte -c und -S nicht mischen'? Wenn es wahr ist, sollten wir den Autor daran erinnern und es bearbeiten.
Tony

5
@Tony: gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Options "Sie können ... eine der Optionen -c, -S oder -E verwenden, um anzugeben, wo gcc aufhören soll. ""
Nate Eldredge

1
Wenn Sie alle Zwischenausgänge möchten, verwenden Sie gcc -march=native -O3 -save-temps. Sie können weiterhin die -cErstellung von Objektdateien beenden, ohne zu versuchen, eine Verknüpfung herzustellen, oder was auch immer.
Peter Cordes

2
-save-tempsist interessant, da es auf einmal den exakten Code generiert, der generiert wird, während die andere Option, den Compiler aufzurufen, das -Szweimalige Kompilieren und möglicherweise mit verschiedenen Optionen bedeutet. Aber -save-temps Dumps alle im aktuellen Verzeichnis, was irgendwie chaotisch ist. Es sieht so aus, als wäre es eher als Debug-Option für GCC gedacht als als ein Tool zur Überprüfung Ihres Codes.
Stéphane Gourichon

50

Die Verwendung des -SWechsels zu GCC auf x86-basierten Systemen erzeugt standardmäßig einen Speicherauszug der AT & T-Syntax, der mit dem -masm=attSchalter wie folgt angegeben werden kann:

gcc -S -masm=att code.c

Wenn Sie dagegen einen Speicherauszug in Intel-Syntax erstellen möchten, können Sie den -masm=intelSchalter folgendermaßen verwenden:

gcc -S -masm=intel code.c

(Beide erzeugen Dumps von code.cin ihre verschiedenen Syntax, jeweils in die Datei code.s)

Um ähnliche Effekte mit objdump zu erzielen, sollten Sie den Schalter --disassembler-options= intel/ attswitch verwenden, ein Beispiel (mit Code-Dumps, um die Unterschiede in der Syntax zu veranschaulichen):

 $ objdump -d --disassembler-options=att code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    0x4(%esp),%ecx
 80483c8:   83 e4 f0                and    $0xfffffff0,%esp
 80483cb:   ff 71 fc                pushl  -0x4(%ecx)
 80483ce:   55                      push   %ebp
 80483cf:   89 e5                   mov    %esp,%ebp
 80483d1:   51                      push   %ecx
 80483d2:   83 ec 04                sub    $0x4,%esp
 80483d5:   c7 04 24 b0 84 04 08    movl   $0x80484b0,(%esp)
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    $0x0,%eax
 80483e6:   83 c4 04                add    $0x4,%esp 
 80483e9:   59                      pop    %ecx
 80483ea:   5d                      pop    %ebp
 80483eb:   8d 61 fc                lea    -0x4(%ecx),%esp
 80483ee:   c3                      ret
 80483ef:   90                      nop

und

$ objdump -d --disassembler-options=intel code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    ecx,[esp+0x4]
 80483c8:   83 e4 f0                and    esp,0xfffffff0
 80483cb:   ff 71 fc                push   DWORD PTR [ecx-0x4]
 80483ce:   55                      push   ebp
 80483cf:   89 e5                   mov    ebp,esp
 80483d1:   51                      push   ecx
 80483d2:   83 ec 04                sub    esp,0x4
 80483d5:   c7 04 24 b0 84 04 08    mov    DWORD PTR [esp],0x80484b0
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    eax,0x0
 80483e6:   83 c4 04                add    esp,0x4
 80483e9:   59                      pop    ecx
 80483ea:   5d                      pop    ebp
 80483eb:   8d 61 fc                lea    esp,[ecx-0x4]
 80483ee:   c3                      ret    
 80483ef:   90                      nop

Was zum ... gcc -S -masm=intel test.cbei mir nicht genau funktioniert hat, ich habe eine Kreuzung aus Intel- und AT & T-Syntax wie folgt: mov %rax, QWORD PTR -24[%rbp]statt dieser : movq -24(%rbp), %rax.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

1
Netter Tipp. Es sollte beachtet werden, dass dies auch funktioniert, wenn eine parallele Ausgabe von .ound ASM-Dateien durchgeführt wird, dh via-Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm
underscore_d

Könnte -MOption verwenden, es ist das gleiche wie --disassembler-optionsaber viel kürzer, zBobjdump -d -M intel a.out | less -N
Eric Wang

34

godbolt ist ein sehr nützliches Tool. Die Liste enthält nur C ++ - Compiler. Sie können jedoch das -x cFlag verwenden, um den Code als C zu behandeln. Anschließend wird nebeneinander eine Assembly-Liste für Ihren Code erstellt, und Sie können die ColouriseOption zum Generieren verwenden Farbige Balken zeigen visuell an, welcher Quellcode der generierten Assembly zugeordnet ist. Zum Beispiel der folgende Code:

#include <stdio.h>

void func()
{
  printf( "hello world\n" ) ;
}

Verwenden Sie die folgende Befehlszeile:

-x c -std=c99 -O3

und Colourisewürde Folgendes erzeugen:

Geben Sie hier die Bildbeschreibung ein


Es wäre schön zu wissen, wie Godbolt-Filter funktionieren: .LC0, .text, // und Intel. Intel ist einfach, -masm=intelaber was ist mit dem Rest?
Z Boson

Ich denke, es wird hier erklärt stackoverflow.com/a/38552509/2542702
Z Boson

Godbolt unterstützen C (zusammen mit einer Menge anderer Sprachen wie Rust, D, Pascal ...). Es ist nur so, dass es viel weniger C-Compiler gibt, also ist es immer noch besser, C ++ - Compiler mit-x c
phuclv

23

Haben Sie gcc -S -fverbose-asm -O source.cdann versucht , in die generierte source.sAssembler-Datei zu schauen ?

Der generierte Assembler-Code geht in source.s(Sie können diesen mit -o Assembler-Dateinamen überschreiben ); Die -fverbose-asmOption fordert den Compiler auf, einige Assembler-Kommentare auszugeben, die den generierten Assembler-Code "erklären". Die -OOption fordert den Compiler auf, ein wenig zu optimieren (es könnte mit -O2oder mehr optimieren -O3).

Wenn Sie verstehen möchten, was gccpassiert -fdump-tree-all, versuchen Sie es, aber seien Sie vorsichtig: Sie erhalten Hunderte von Dump-Dateien.

Übrigens ist GCC durch Plugins oder mit MELT (einer domänenspezifischen Hochsprache zur Erweiterung von GCC, die ich 2017 aufgegeben habe) erweiterbar.


Erwähnen Sie vielleicht, dass die Ausgabe in sein wird source.s, da viele Leute einen Ausdruck auf der Konsole erwarten würden.
RubenLaguna

1
@ecerulm: -S -o-Dumps zu stdout. -masm=intelist hilfreich, wenn Sie die NASM / YASM-Syntax verwenden möchten. (aber es wird qword ptr [mem]nicht nur verwendet , sondern qwordähnelt eher Intel / MASM als NASM / YASM). gcc.godbolt.org macht einen guten Job beim Aufräumen des Speicherauszugs : Optional werden nur Kommentarzeilen, nicht verwendete Beschriftungen und Assembler-Anweisungen entfernt.
Peter Cordes

2
Ich habe vergessen zu erwähnen: Wenn Sie nach "ähnlich wie die Quelle, aber ohne das Rauschen beim Speichern / Neuladen nach jeder Quellzeile" suchen, dann -Ogist dies sogar noch besser als -O1. Es bedeutet "Optimieren für das Debuggen" und macht asm ohne zu viele knifflige / schwer zu verfolgende Optimierungen, die alles tun, was die Quelle sagt. Es ist seit gcc4.8 verfügbar, aber Clang 3.7 hat es immer noch nicht. IDK, ob sie sich dagegen entschieden haben oder was.
Peter Cordes

19

Sie können dafür gdb wie objdump verwenden.

Dieser Auszug stammt aus http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64


Hier ist ein Beispiel für eine gemischte Quelle + Assembly für Intel x86:

  (gdb) disas / m main
Speicherauszug des Assembler-Codes für die Funktion main:
5 {
0x08048330:% ebp drücken
0x08048331: mov% esp,% ebp
0x08048333: sub $ 0x8,% esp
0x08048336: und $ 0xfffffff0,% esp
0x08048339: sub $ 0x10,% esp

6 printf ("Hallo. \ N");
0x0804833c: movl $ 0x8048440, (% esp)
0x08048343: Rufen Sie 0x8048284 an 

7 return 0;
8}
0x08048348: mov $ 0x0,% eax
0x0804834d: verlassen
0x0804834e: ret

Ende des Assembler-Dumps.


Verwenden Sie den set disassembly-flavor intelBefehl , um den Disassembler von GDB auf Intel-Syntax umzustellen .
Ruslan

13

Verwenden Sie den Schalter -S (Hinweis: Großbuchstabe S) zu GCC, und der Assemblycode wird an eine Datei mit der Erweiterung .s ausgegeben. Zum Beispiel der folgende Befehl:

gcc -O2 -S -c foo.c


4

Ich habe gcc keinen Versuch gegeben, aber im Fall von g ++. Der folgende Befehl funktioniert für mich. -g für Debug-Build und -Wa, -adhln wird an Assembler zur Auflistung mit Quellcode übergeben

g ++ -g -Wa, -adhln src.cpp


Es funktioniert auch für gcc! -Wa, ... steht für Befehlszeilenoptionen für den Assembler-Teil (nach der C / ++ - Kompilierung in gcc / g ++ ausführen). Es wird als intern aufgerufen (as.exe in Windows). Siehe> als --help als Kommandozeile, um weitere Hilfe zu sehen
Hartmut Schorrig

0

Verwenden Sie -Wa, -adhln als Option für gcc oder g ++, um eine Listenausgabe an stdout zu erstellen.

-Wa, ... steht für Befehlszeilenoptionen für den Assembler-Teil (nach der C / ++ - Kompilierung in gcc / g ++ ausführen). Es wird als intern aufgerufen (as.exe in Windows). Sehen

> als --help

als Befehlszeile, um weitere Hilfe für das Assembler-Tool in gcc anzuzeigen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.