Domanda

Come si fa?

Se voglio analizzare come viene compilato qualcosa, come posso ottenere il codice assembly emesso?

È stato utile?

Soluzione

Usa l'opzione -S su gcc (o g ++).

gcc -S helloworld.c

Questo eseguirà il preprocessore (cpp) su helloworld.c, eseguirà la compilazione iniziale e poi si fermerà prima che venga eseguito l'assemblatore.

Per impostazione predefinita, verrà generato un file helloworld.s . Il file di output può essere comunque impostato utilizzando l'opzione -o .

gcc -S -o my_asm_output.s helloworld.c

Ovviamente funziona solo se hai la fonte originale. Un'alternativa se hai solo il file oggetto risultante è usare objdump , impostando l'opzione --disassemble (o -d per l'abbreviazione modulo).

objdump -S --disassemble helloworld > helloworld.dump

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

L'esecuzione di file helloworld ti darà alcune indicazioni sul livello di dettaglio che otterrai usando objdump.

Altri suggerimenti

Questo genererà il codice asm con il codice C + numeri di riga intrecciati per vedere più facilmente quali linee generano quale codice.

# 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

Trovato in Algoritmi per programmatori , pagina 3 (che è la 15a pagina generale di il PDF).

La seguente riga di comando proviene da di Christian Garbin blog

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 ++ è 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 <*>,-16(%ebp)

Utilizza l'opzione -S

g++ -S main.cpp

o anche con gcc

gcc -S main.c

Vedi anche questo

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 citato gcc -S. Ecco uno script molto utile di Loren Merritt che converte la sintassi predefinita di objdump 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
       

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 citato gcc -S. Ecco uno script molto utile di Loren Merritt che converte la sintassi predefinita di objdump nella sintassi nasm più leggibile:

<*>

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

=~ /\tnop |\txchg *ax,ax$/) { # drop this line } else { print $prev; $prev =

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 citato gcc -S. Ecco uno script molto utile di Loren Merritt che converte la sintassi predefinita di objdump nella sintassi nasm più leggibile:

<*>

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

; } } print $prev; close FH;

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

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

Come tutti hanno sottolineato, utilizzare l'opzione -S su GCC. Vorrei anche aggiungere che i risultati possono variare (selvaggiamente) a seconda che si aggiungano o meno le opzioni di ottimizzazione ( -O0 per nessuna, -O2 per 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!

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.

Usa l'opzione -S:

gcc -S program.c

Se stai cercando un assembly LLVM:

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

Non vedo questa possibilità tra le risposte, probabilmente perché la domanda è del 2008, ma nel 2018 è possibile utilizzare il sito Web online di Matt Goldbolt https://godbolt.org

Puoi anche localizzare clone ed eseguire localmente il suo progetto https://github.com/mattgodbolt/compiler- explorer

Da: http://www.delorie.com/djgpp/v2faq/faq8_20 .html

gcc -c -g -Wa, -a, -ad [altre opzioni GCC] foo.c > foo.lst

in alternativa alla risposta di PhirePhly O semplicemente usa -S come hanno detto tutti.

 Output 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 blocchi di codice e salvalo con estensione .c

  2. Compilalo ed eseguilo.

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

    comando seguente 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 -S D: \ Aa_C_Certified \ alternate_letters.c

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

4. Successivamente, digita il seguente comando

C; \ gcc > cpp nomefile.s INVIO

Esempio di comando (come nel mio caso)

C; \ gcc > cpp alternate_letters.s

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

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

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

-save-temps

Questo è stato menzionato in https://stackoverflow.com/a/17083009/895245 ma lasciatemi esemplificare ulteriormente . 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 , l'attuale directory di lavoro contiene anche i seguenti file:

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

    # 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'assembly 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 dell'output dell'oggetto -o anziché l'attuale directory di lavoro, evitando così potenziali conflitti di nome di base.

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

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 temporali in / tmp , quindi è facile sapere esattamente cosa sta succedendo, tra cui i passaggi di preelaborazione / compilazione / assembly:

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

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 file del Programma 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 tuo programma e output è il nome dell'eseguibile che vuoi generare.

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top