Wie macht man das?
Wenn ich analysieren möchte, wie etwas kompiliert wird, wie bekomme ich den ausgegebenen Assembly-Code?
Verwenden Sie die -S
-Option für gcc (oder g ++).
gcc -S helloworld.c
Dadurch wird der Präprozessor (cpp) über helloworld.c ausgeführt, die erste Kompilierung wird durchgeführt und dann angehalten, bevor der Assembler ausgeführt wird.
Standardmäßig wird eine Datei helloworld.s
ausgegeben. Die Ausgabedatei kann weiterhin mit der Option -o
festgelegt werden.
gcc -S -o my_asm_output.s helloworld.c
Dies funktioniert natürlich nur, wenn Sie die ursprüngliche Quelle haben. Eine Alternative, wenn Sie nur die resultierende Objektdatei haben, verwenden Sie objdump
, indem Sie die Option --disassemble
(oder -d
für die abgekürzte Form) festlegen.
objdump -S --disassemble helloworld > helloworld.dump
Diese Option funktioniert am besten, wenn die Debugging-Option für die Objektdatei (-g
zur Kompilierzeit) aktiviert ist und die Datei nicht entfernt wurde.
Wenn Sie file helloworld
ausführen, erhalten Sie einen Hinweis auf den Detaillierungsgrad, den Sie mit objdump erhalten.
Dadurch wird der ASM-Code mit den verwobenen C-Code + Zeilennummern generiert, um einfacher zu sehen, welche Zeilen welchen Code generieren.
# create assembler code:
c++ -S -fverbose-asm -g -O2 test.cc -o test.s
# create asm interlaced with source lines:
as -alhnd test.s > test.lst
Gefunden in Algorithmen für Programmierer , Seite 3 (dies ist die insgesamt 15. Seite der PDF-Datei).
Die folgende Befehlszeile stammt aus Christian Garbins Blog
g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
Ich habe G ++ in einem DOS-Fenster unter Windows XP ausgeführt, gegen eine Routine, die eine implizite Umwandlung enthält
c:\gpp_code>g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
horton_ex2_05.cpp: In function `int main()':
horton_ex2_05.cpp:92: warning: assignment to `int' from `double'
Die Ausgabe hat einen zusammengesetzten generierten Code, der mit dem ursprünglichen C++ - Code durchsetzt wurde (der C++ - Code wird im generierten ASM-Stream als Kommentar angezeigt)
16:horton_ex2_05.cpp **** using std::setw;
17:horton_ex2_05.cpp ****
18:horton_ex2_05.cpp **** void disp_Time_Line (void);
19:horton_ex2_05.cpp ****
20:horton_ex2_05.cpp **** int main(void)
21:horton_ex2_05.cpp **** {
164 %ebp
165 subl $128,%esp
?GAS LISTING C:\DOCUME~1\CRAIGM~1\LOCALS~1\Temp\ccx52rCc.s
166 0128 55 call ___main
167 0129 89E5 .stabn 68,0,21,LM2-_main
168 012b 81EC8000 LM2:
168 0000
169 0131 E8000000 LBB2:
169 00
170 .stabn 68,0,25,LM3-_main
171 LM3:
172 movl $0,-16(%ebp)
Wenn das, was Sie sehen möchten, von der Verknüpfung der Ausgabe abhängt, kann objdump für die Ausgabeobjektdatei/ausführbare Datei zusätzlich zu den zuvor genannten gcc -S nützlich sein. Hier ist ein sehr nützliches Skript von Loren Merritt, das die standardmäßige objdump-Syntax in die besser lesbare Nasm-Syntax konvertiert:
#!/usr/bin/Perl -w
$ptr='(BYTE|Word|DWORD|QWORD|XMMWORD) PTR ';
$reg='(?:[er]?(?:[abcd]x|[sd]i|[sb]p)|[abcd][hl]|r1?[0-589][dwb]?|mm[0-7]|xmm1?[0-9])';
open FH, '-|', '/usr/bin/objdump', '-w', '-M', 'intel', @ARGV or die;
$prev = "";
while(<FH>){
if(/$ptr/o) {
s/$ptr(\[[^\[\]]+\],$reg)/$2/o or
s/($reg,)$ptr(\[[^\[\]]+\])/$1$3/o or
s/$ptr/lc $1/oe;
}
if($prev =~ /\t(repz )?ret / and
$_ =~ /\tnop |\txchg *ax,ax$/) {
# drop this line
} else {
print $prev;
$prev = $_;
}
}
print $prev;
close FH;
Ich vermute, dass dies auch für die Ausgabe von gcc -S verwendet werden kann.
Nun, wie jeder gesagt hat, verwenden Sie die Option -S. . Wenn Sie die Option -save-temps verwenden, können Sie auch vorverarbeitete Dateien ( .i), Assembly-Dateien (. S) und Objektdateien (*. O). (Holen Sie sich jeden von ihnen mit -E, -S und -c.)
Wie jeder darauf hingewiesen hat, verwenden Sie die Option -S
für GCC. Ich möchte auch hinzufügen, dass die Ergebnisse (stark!) Variieren können, abhängig davon, ob Sie Optimierungsoptionen hinzufügen (-O0
für keine, -O2
für agressive Optimierung).
Insbesondere bei RISC-Architekturen transformiert der Compiler den Code bei der Optimierung oft fast unkenntlich. Es ist beeindruckend und faszinierend, die Ergebnisse zu betrachten!
Schauen Sie sich die -S-Flagge an.
Es lohnt sich auch, die '-fdump-tree'-Familie von Flaggen zu betrachten, insbesondere' -fdump-tree-all ', mit der Sie einige der Zwischenformen von gcc sehen. Diese sind oft lesbarer als Assembler (zumindest für mich) und zeigen Ihnen, wie Optimierungsdurchgänge durchgeführt werden.
Ich sehe diese Möglichkeit nicht unter den Antworten, wahrscheinlich weil die Frage aus dem Jahr 2008 stammt, aber 2018 können Sie die Online-Website von Matt Goldbolt nutzen https://godbolt.org
Sie können auch lokal git clone und sein Projekt ausführen https://github.com/mattgodbolt/compiler-Explorer
Verwenden Sie die Option -S:
gcc -S program.c
Wenn Sie nach einer LLVM-Baugruppe suchen:
llvm-gcc -emit-llvm -S hello.c
Von: http://www.delorie.com/djgpp/v2faq/faq8_20.html
gcc -c -g -Wa, -a, -ad [andere GCC-Optionen] foo.c> foo.lst
als Alternative zu PhirePhlys Antwort Oder verwenden Sie einfach -S wie jeder gesagt hat.
Gehen Sie wie folgt vor, um den Assembly-Code eines beliebigen C-Programms unter Windows anzuzeigen/auszudrucken
konsole/Terminal/Eingabeaufforderung:
Schreiben Sie ein C-Programm in einen C-Code-Editor wie Codeblocks und speichern Sie es mit der Erweiterung .c
Kompilieren Sie und führen Sie es aus.
Nach erfolgreicher Ausführung wechseln Sie zu dem Ordner, in dem Sie Ihren gcc-Compiler installiert haben, und geben Sie die
folgenden Befehl, um eine '.s'-Datei der' .c'-Datei zu erhalten
C:\gcc> gcc -S vollständiger Pfad der C-Datei ENTER
Ein Beispielbefehl (wie in meinem Fall)
C:\gcc> gcc -S D:\Aa_C_Certified\alternate_letters.c
Dies gibt eine ".s" -Datei der ursprünglichen ".c" -Datei aus
4 Geben Sie danach den folgenden Befehl ein
C;\gcc> cpp dateiname.s ENTER
Beispielbefehl (wie in meinem Fall)
C;\gcc> cpp alternate_letters.s
Dadurch wird der gesamte Assembly-Sprachcode Ihres C-Programms gedruckt/ausgegeben.
-save-temps
Dies wurde unter https://stackoverflow.com/a/17083009/895245 erwähnt, aber lassen Sie mich es weiter veranschaulichen. Wenn Sie das tun:
_gcc -save-temps -c -o main.o main.c
_
haupt c
_#define INC 1
int myfunc(int i) {
return i + INC;
}
_
und jetzt enthält das aktuelle Arbeitsverzeichnis neben der normalen Ausgabe _main.o
_ auch die folgenden Dateien:
_main.i
_ ist ein Bonus und enthält die gewünschte vorbesessene Datei:
_# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "main.c"
int myfunc(int i) {
return i + 1;
}
_
_main.s
_ enthält die gewünschte generierte Assembly:
_ .file "main.c"
.text
.globl myfunc
.type myfunc, @function
myfunc:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
addl $1, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size myfunc, .-myfunc
.ident "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
.section .note.GNU-stack,"",@progbits
_
Wenn Sie dies für eine große Anzahl von Dateien tun möchten, sollten Sie stattdessen Folgendes verwenden:
_ -save-temps=obj
_
dadurch werden die Zwischendateien im selben Verzeichnis wie die Ausgabe des Objekts _-o
_ anstelle des aktuellen Arbeitsverzeichnisses gespeichert, wodurch mögliche Konflikte mit Basisnamen vermieden werden.
Der Vorteil dieser Option gegenüber _-S
_ besteht darin, dass sie einfach zu jedem Build-Skript hinzugefügt werden kann, ohne dass der Build selbst stark beeinträchtigt wird.
Eine weitere coole Sache bei dieser Option ist, wenn Sie _-v
_ hinzufügen:
_gcc -save-temps -c -o main.o -v main.c
_
es zeigt tatsächlich die expliziten Dateien, die unter _/tmp
_ anstelle von hässlichen temporären Dateien verwendet werden, sodass Sie leicht genau wissen können, was gerade vor sich geht, einschließlich der Schritte Vorverarbeitung/Kompilierung/Zusammenstellung:
_/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s
_
Getestet unter Ubuntu 19.04 AMD64, GCC 8.3.0.
Verwenden Sie "-S" als Option. Es zeigt die Assembly-Ausgabe im Terminal an.
vor kurzem wollte ich die Assembly jeder Funktion in einem Programm kennenlernen
so habe ich es gemacht.
$ gcc main.c // main.c source file
$ gdb a.exe // gdb a.out in linux
(gdb) disass main // note here main is a function
// similary it can be done for other functions
Hier ist eine Lösung für C mit gcc:
gcc -S program.c && gcc program.c -o output
Hier speichert der erste Teil die Assembly-Ausgabe des Programms in demselben Dateinamen wie Program, aber mit einer geänderten .s -Erweiterung können Sie es als normale Textdatei öffnen.
Der zweite Teil hier kompiliert Ihr Programm für die tatsächliche Verwendung und generiert eine ausführbare Datei für Ihr Programm mit einem angegebenen Dateinamen.
Das oben verwendete program.c ist der Name Ihres Programms und output ist der Name der ausführbaren Datei, die Sie generieren möchten.
Übrigens, es ist mein erster Beitrag zu StackOverFlow: -}