Come si ottiene l'output dell'assemblatore dalla sorgente C / C ++ in gcc?


Risposte:


422

Usa l' -Sopzione per gcc (o g ++).

gcc -S helloworld.c

Ciò eseguirà il preprocessore (cpp) su helloworld.c, eseguirà la compilazione iniziale e quindi si arresterà prima che venga eseguito l'assemblatore.

Per impostazione predefinita, questo genererà un file helloworld.s. Il file di output può essere comunque impostato utilizzando l' -oopzione.

gcc -S -o my_asm_output.s helloworld.c

Ovviamente questo funziona solo se hai la fonte originale. Un'alternativa se hai solo il file oggetto risultante è quella di usare objdump, impostando l' --disassembleopzione (o -dper il modulo abbreviato).

objdump -S --disassemble helloworld > helloworld.dump

Questa opzione funziona meglio se l'opzione di debug è abilitata per il file oggetto ( -gal momento della compilazione) e il file non è stato rimosso.

La corsa file helloworldti darà alcune indicazioni sul livello di dettaglio che otterrai usando objdump.


3
Mentre questo è corretto, ho trovato più utili i risultati della risposta di Cr McDonough.
Rhys Ulerich,

3
un uso aggiuntivo: objdump -M intel -S --disassemble helloworld> helloworld.dump per ottenere il dump dell'oggetto nella sintassi Intel compatibile con nasm su linux.
touchStone

2
Se hai una sola funzione per ottimizzare / controllare, puoi provare i compilatori C ++ interattivi online, ad esempio godbolt
fiorentinoing,

1
@touchStone: GAS non.intel_syntax è compatibile con NASM . È più simile a MASM (ad esempio mov eax, symbolè un carico, a differenza di NASM dove è un mov r32, imm32indirizzo), ma non è totalmente compatibile con MASM. Lo consiglio vivamente come un bel formato da leggere, soprattutto se ti piace scrivere nella sintassi NASM. objdump -drwC -Mintel | lesso gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | lesssono utili. (Vedi anche Come rimuovere il "rumore" dall'uscita dell'assieme GCC / clang? ). -masm=intelfunziona anche con clang.
Peter Cordes,

3
Uso miglioregcc -O -fverbose-asm -S
Basile Starynkevitch,

173

Questo genererà il codice assembly con il codice C + numeri di riga intrecciati, per vedere più facilmente quali righe generano quale codice:

# create assembler code:
g++ -S -fverbose-asm -g -O2 test.cc -o test.s
# create asm interlaced with source lines:
as -alhnd test.s > test.lst

Trovato in Algorithms for programmers , pagina 3 (che è la 15a pagina complessiva del PDF).


3
(In realtà è sulla pagina (numerata) 3 (che è la 15a pagina del PDF))
Grumdrig

1
Purtroppo assu OS X non si conoscono questi flag. Se così fosse, però, si potrebbe probabilmente una riga questo utilizzando -Wapassare alcuna opzione al as.
Grumdrig,

23
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lstsarebbe la versione abbreviata di questo.
legends2k

4
Puoi anche usare gcc -c -g -Wa,-ahl=test.s test.cogcc -c -g -Wa,-a,-ad test.c > test.txt
phuclv il

1
Un post sul blog che spiega questo in modo più dettagliato, inclusa la versione a un comando come legends e Lu'u pubblicata. Ma perchè -O0? È pieno di carichi / negozi che rendono difficile tenere traccia di un valore e non ti dice nulla sull'efficienza del codice ottimizzato.
Peter Cordes,

51

La seguente riga di comando proviene dal blog di Christian Garbin

g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt

Ho eseguito G ++ da una finestra DOS su Win-XP, contro una routine che contiene un cast implicito

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'

L'output è assemblato codice generato assemblato con il codice C ++ originale (il codice C ++ viene mostrato come commenti nel flusso asm generato)

  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)

@Paladin - Non necessariamente. L'OP stava per ottenere l'equivalente in output dell'assemblatore del codice sorgente C / C ++, questo ottiene il Listato, che sono d'accordo è più utile per capire cosa sta facendo il compilatore e l'ottimizzatore. Ma ciò causerebbe l'assemblaggio dell'assemblatore stesso, poiché non si aspetta i numeri di riga e la compilazione di byte al di fuori delle istruzioni di assemblaggio.
Jesse Chisholm l'

Usa almeno -O2, o qualsiasi altra opzione di ottimizzazione utilizzi effettivamente quando costruisci il tuo progetto, se vuoi vedere come gcc ottimizza il tuo codice. (O se usi LTO, come dovresti, devi smontare l'output del linker per vedere cosa ottieni veramente.)
Peter Cordes,

27

Utilizzare l'opzione -S

g++ -S main.cpp

o anche con gcc

gcc -S main.c

Vedi anche questo


7
Consulta le FAQ: "È anche perfettamente corretto porre e rispondere alla tua domanda di programmazione". Il punto è che ora StackOverflow contiene domande e risposte come risorsa per gli altri.
Steve Jessop,

E forse qualcun altro verrà e ti sorprenderà con una risposta migliore, anche se a volte la mia potrebbe essere un po 'prolissa ...
PhirePhly,

C'è anche la risposta al tuo pulsante di domanda.
Ciro Santilli 24 冠状 病 六四 事件 法轮功

13

Se ciò che si desidera vedere dipende dal collegamento dell'output, anche objdump sul file / eseguibile dell'oggetto di output può essere utile in aggiunta al summenzionato gcc -S. Ecco uno script molto utile di Loren Merritt che converte la sintassi objdump predefinita nella sintassi nasm più leggibile:

#!/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;

Sospetto che questo possa essere utilizzato anche sull'output di gcc -S.


2
Tuttavia, questo script è un trucco sporco che non converte completamente la sintassi. Ad esempio, mov eax,ds:0x804b794non è molto NASMish. Inoltre, a volte toglie solo informazioni utili: movzx eax,[edx+0x1]lascia al lettore di indovinare se l'operando di memoria fosse byteo word.
Ruslan,

Per prima cosa disassemblare la sintassi NASM, usa Nebbia di Agnerobjconv . Puoi farlo disassemblare in stdout con il file di output = /dev/stdout, in modo da poter eseguire il pipe lessper la visualizzazione. C'è anche ndisasm, ma smonta solo i binari piatti e non conosce i file oggetto (ELF / PE).
Peter Cordes,

9

Come tutti hanno sottolineato, utilizzare l' -Sopzione per GCC. Vorrei anche aggiungere che i risultati possono variare (selvaggiamente!) A seconda che si aggiungano o meno le opzioni di ottimizzazione ( -O0per nessuno, -O2per l'ottimizzazione aggressiva).

In particolare sulle architetture RISC, il compilatore spesso trasforma il codice quasi al di là del riconoscimento nel fare l'ottimizzazione. È impressionante e affascinante guardare i risultati!


9

Bene, come dicevano tutti, usa l'opzione -S. Se si utilizza l'opzione -save-temps, è anche possibile ottenere file preelaborati ( .i), file assembly ( .s) e file oggetto (*. O). (prendine ognuno usando -E, -S e -c.)


8

Come accennato in precedenza, guarda la bandiera -S.

Vale anche la pena guardare la famiglia di flag '-fdump-tree', in particolare '-fdump-tree-all', che ti permette di vedere alcune delle forme intermedie di gcc. Questi possono spesso essere più leggibili dell'assemblatore (almeno per me) e farti vedere come funzionano i passaggi di ottimizzazione.


8

Se stai cercando un assemblaggio LLVM:

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


8

-save-temps

Questo è stato menzionato su https://stackoverflow.com/a/17083009/895245 ma lasciatemi esemplificare ulteriormente.

Il grande vantaggio di questa opzione -Sè che è molto facile aggiungerlo a qualsiasi script di build, senza interferire molto nella build stessa.

Quando lo fai:

gcc -save-temps -c -o main.o main.c

main.c

#define INC 1

int myfunc(int i) {
    return i + INC;
}

e ora, oltre al normale output main.o, la directory di lavoro corrente contiene anche i seguenti file:

  • main.i è un bonus e contiene il file prestampato:

    # 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 contiene l'assemblaggio generato desiderato:

        .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

Se vuoi farlo per un gran numero di file, considera invece di usare:

 -save-temps=obj

che salva i file intermedi nella stessa directory -odell'output dell'oggetto anziché nella directory di lavoro corrente, evitando così potenziali conflitti di nome di base.

Un'altra cosa interessante di questa opzione è se aggiungi -v:

gcc -save-temps -c -o main.o -v main.c

mostra in realtà i file espliciti utilizzati al posto dei brutti temporanei sotto /tmp, quindi è facile sapere esattamente cosa sta succedendo, che include i passaggi di pre-elaborazione / compilazione / assemblaggio:

/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

Testato in Ubuntu 19.04 amd64, GCC 8.3.0.




3

Uscita di questi comandi

Ecco i passaggi per visualizzare / stampare il codice assembly di qualsiasi programma C su Windows

console / terminale / prompt dei comandi:

  1. Scrivi un programma C in un editor di codice C come i blocchi di codice e salvalo con estensione .c

  2. Compilalo ed eseguilo.

  3. Una volta eseguito correttamente, vai alla cartella in cui hai installato il tuo compilatore gcc e dai il

    seguente comando per ottenere un file '.s' del file '.c'

    C: \ gcc> gcc -S percorso completo del file C INVIO

    Un comando di esempio (come nel mio caso)

    C: \ gcc> gcc -SD: \ Aa_C_Certified \ alternate_letters.c

    Questo genera un file '.s' del file '.c' originale

4 Successivamente, digitare il comando seguente

C; \ gcc> cpp nomefile.s INVIO

Esempio di comando (come nel mio caso)

C; \ gcc> cpp alternate_letters.s

Ciò stamperà / produrrà l'intero codice in linguaggio Assembly del tuo programma C.


2

Usa "-S" come opzione. Visualizza l'output dell'assemblaggio nel terminale.


Per visualizzare nel terminale, utilizzare gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less. -Sda solo crea foo.s.
Peter Cordes,

2

recentemente ho voluto conoscere l'assemblaggio di ciascuna funzione in un programma,
è così che l'ho fatto.

$ 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

2

Ecco una soluzione per C usando gcc:

gcc -S program.c && gcc program.c -o output
  1. Qui la prima parte memorizza l'output dell'assembly del programma con lo stesso nome di file di Program ma con un'estensione .s modificata , è possibile aprirlo come qualsiasi normale file di testo.

  2. La seconda parte qui compila il tuo programma per l'utilizzo effettivo e genera un eseguibile per il tuo Programma con un nome file specificato.

Il programma.c usato sopra è il nome del programma e l' output è il nome dell'eseguibile che si desidera generare.

A proposito, è il mio primo post su StackOverFlow: -}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.