wake-up-neo.com

Wie erhalten Sie Assembler-Ausgabe von C/C++ - Quelle in gcc?

Wie macht man das?

Wenn ich analysieren möchte, wie etwas kompiliert wird, wie bekomme ich den ausgegebenen Assembly-Code?

313
Doug T.

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.

365

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).

160
PhirePhly

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)
44
Cr McDonough

Verwenden Sie den Schalter -S 

g++ -S main.cpp

oder auch mit gcc

gcc -S main.c

Siehe auch this

22
Doug T.

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.

12
Dark Shikari

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.)

8
METADATA

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!

7
Dan Lenski

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.

7
Chris Jefferson

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

6
Antonin GAVREL

Verwenden Sie die Option -S:

gcc -S program.c
6
Jeremy Ruten

Wenn Sie nach einer LLVM-Baugruppe suchen:

llvm-gcc -emit-llvm -S hello.c
6
mcandre

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.

4
Anonymous

 Output of these commnads

Gehen Sie wie folgt vor, um den Assembly-Code eines beliebigen C-Programms unter Windows anzuzeigen/auszudrucken 

konsole/Terminal/Eingabeaufforderung:

  1. Schreiben Sie ein C-Programm in einen C-Code-Editor wie Codeblocks und speichern Sie es mit der Erweiterung .c

  2. Kompilieren Sie und führen Sie es aus.

  3. 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.

2

-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.

1
Pizearke

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
1
Abhishek D K

Hier ist eine Lösung für C mit gcc:

gcc -S program.c && gcc program.c -o output
  1. 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.

  2. 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: -}

0
Himanshu Pal