Usando GCC per produrre assemblaggi leggibili?


256

Mi chiedevo come usare GCC sul mio file sorgente C per scaricare una versione mnemonica del codice macchina in modo da poter vedere in cosa veniva compilato il mio codice. Puoi farlo con Java ma non sono stato in grado di trovare un modo con GCC.

Sto cercando di riscrivere un metodo C in assembly e vedere come fa GCC sarebbe di grande aiuto.


25
si noti che "bytecode" indica in genere il codice utilizzato da una macchina virtuale, come JVM o CLR di .NET. L'output di GCC è meglio chiamato "codice macchina", "linguaggio macchina" o "linguaggio assembly"
Javier

2
Ho aggiunto una risposta usando godbolt poiché è uno strumento molto potente per sperimentare rapidamente l'effetto di diverse opzioni sulla generazione del codice.
Shafik Yaghmour,



Per ulteriori suggerimenti su come rendere leggibile l'output dell'asm, vedere anche: Come rimuovere il "rumore" dall'output dell'assieme GCC / clang?
Peter Cordes,

Risposte:


335

Se si compila con simboli di debug, è possibile utilizzare objdumpper produrre uno smontaggio più leggibile.

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

objdump -drwC -Mintel è bella:

  • -rmostra i nomi dei simboli sui trasferimenti (quindi vedresti putsnelle callistruzioni sotto)
  • -R mostra riposizionamenti a collegamento dinamico / nomi di simboli (utile su librerie condivise)
  • -C confonde i nomi dei simboli C ++
  • -w è la modalità "wide": non esegue il wrapping di riga dei byte del codice macchina
  • -Mintel: usa la .intel_syntax noprefixsintassi simile a MASM GAS / binutils invece di AT&T
  • -S: interlacciare le linee di origine con lo smontaggio.

Potresti mettere qualcosa di simile alias disas="objdump -drwCS -Mintel"nel tuo~/.bashrc


Esempio:

> 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
C'è un interruttore per afferrare solo le istruzioni Intel?
James,

3
Tutte queste sono istruzioni Intel poiché eseguite su processori Intel: D.
toto

12
@toto Penso che significhi la sintassi Intel invece della sintassi AT&T
Amok,

7
È possibile rinunciare al file oggetto intermedio con il usando la sequenza switch -Wa,-adhln -g to gcc. Ciò presuppone che l'assemblatore sia a gas e ciò potrebbe non essere sempre il caso.
Marc Butler,

8
@James Sì, rifornimento -Mintel.
fuz,

106

Se dai la bandiera a GCC-fverbose-asm , lo farà

Inserire ulteriori informazioni di commento nel codice assembly generato per renderlo più leggibile.

[...] I commenti aggiunti includono:

  • informazioni sulla versione del compilatore e le opzioni della riga di comando,
  • le righe del codice sorgente associate alle istruzioni di assemblaggio, nel formato FILENAME: LINENUMBER: CONTENT OF LINE,
  • suggerimenti su quali espressioni di alto livello corrispondono ai vari operandi delle istruzioni di assemblaggio.

Ma poi, avrei perso tutto lo switch usato per objdump- objdump -drwCS -Mintel, quindi come posso usare qualcosa come verbosecon objdump? In modo che io possa avere commenti nel codice asm, come fa -fverbose-asmin gcc?
Pastore

1
@Herdsman: non puoi. La roba aggiuntiva -fverbose-asmaggiunge è sotto forma di commenti nella sintassi asm dell'output, non direttive che aggiungeranno qualcosa in più nel .ofile. È tutto scartato al momento del montaggio. Guarda l'output del compilatore asm invece del disassemblaggio, ad esempio su godbolt.org dove puoi facilmente abbinarlo alla linea di origine tramite il passaggio del mouse e l'evidenziazione del colore delle linee di origine / asm corrispondenti. Come rimuovere il "rumore" dall'output dell'assieme GCC / clang?
Peter Cordes

75

Utilizzare l'opzione -S (nota: maiuscola S) su GCC e emetterà il codice assembly in un file con estensione .s. Ad esempio, il seguente comando:

gcc -O2 -S foo.c

lascerà il codice assembly generato sul file foo.s.

Strappato direttamente da http://www.delorie.com/djgpp/v2faq/faq8_20.html (ma rimozione errata -c)


35
Non dovresti mescolare -c e -S, usane solo uno. In questo caso, uno sta scavalcando l'altro, probabilmente a seconda dell'ordine in cui vengono utilizzati.
Adam Rosenfield,

4
@AdamRosenfield Qualche riferimento su 'shouldn't mix -c and -S'? Se è vero, dovremmo ricordare all'autore e modificarlo.
Tony

5
@Tony: gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Options "Puoi usare ... una delle opzioni -c, -S o -E per dire dove gcc deve fermarsi. "
Nate Eldredge,

1
Se si desidera tutte le uscite intermedie, utilizzare gcc -march=native -O3 -save-temps. È ancora possibile utilizzare -cper interrompere la creazione di file oggetto senza tentare di collegarsi o altro.
Peter Cordes,

2
-save-tempsè interessante in quanto scarica in una sola volta il codice generato dal codice esatto, mentre l'altra opzione di chiamare il compilatore -Ssignifica compilare due volte e possibilmente con diverse opzioni. Ma -save-temps scarica tutto nella directory corrente, che è piuttosto disordinata. Sembra che sia più inteso come un'opzione di debug per GCC piuttosto che uno strumento per ispezionare il tuo codice.
Stéphane Gourichon,

50

L'uso dello -Sswitch su GCC su sistemi x86 produce un dump della sintassi AT&T, per impostazione predefinita, che può essere specificato con lo -masm=attswitch, in questo modo:

gcc -S -masm=att code.c

Considerando che se si desidera produrre un dump nella sintassi Intel, è possibile utilizzare l' -masm=intelopzione, in questo modo:

gcc -S -masm=intel code.c

(Entrambi producono dump code.cnella loro diversa sintassi, code.srispettivamente nel file )

Per produrre effetti simili con objdump, ti consigliamo di utilizzare l'opzione --disassembler-options= intel/ att, un esempio (con i dump del codice per illustrare le differenze nella sintassi):

 $ 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

e

$ 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

Ma che ... gcc -S -masm=intel test.cnon ha fatto esattamente il lavoro per me, ho avuto qualche incrocio di Intel e AT & T sintassi simile a questo: mov %rax, QWORD PTR -24[%rbp]invece di questo: movq -24(%rbp), %rax.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ il

1
Bel consiglio. Va notato che questo funziona anche quando si eseguono output paralleli di .oe file ASM, ovvero via-Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm
underscore_d

Potrebbe usare l' -Mopzione, è la stessa --disassembler-optionsma molto più breve, ad esempioobjdump -d -M intel a.out | less -N
Eric Wang

34

godbolt è uno strumento molto utile, elencano solo compilatori C ++ ma puoi usare -x cflag per farlo trattare il codice come C.In questo modo genererà un elenco di assiemi per il tuo codice fianco a fianco e puoi usare l' Colouriseopzione per generare barre colorate per indicare visivamente quale codice sorgente viene mappato all'assembly generato. Ad esempio il seguente codice:

#include <stdio.h>

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

utilizzando la seguente riga di comando:

-x c -std=c99 -O3

e Colourisegenererebbe quanto segue:

inserisci qui la descrizione dell'immagine


Sarebbe bello sapere come funzionano i filtri godbolt: .LC0, .text, // e Intel. Intel è facile -masm=intelma per quanto riguarda il resto?
Bosone Z,

Suppongo che sia spiegato qui stackoverflow.com/a/38552509/2542702
Z boson

godbolt supporta C (insieme a un sacco di altre lingue come Rust, D, Pascal ...). È solo che ci sono molti meno compilatori C, quindi è ancora meglio usare compilatori C ++ con-x c
phuclv,

23

Hai provato a gcc -S -fverbose-asm -O source.ccercare il source.sfile assemblatore generato ?

Il codice assembler generato viene inserito source.s(è possibile sovrascriverlo con -o assembller-nomefile ); l' -fverbose-asmopzione chiede al compilatore di emettere alcuni commenti dell'assemblatore "spiegando" il codice dell'assembler generato. L' -Oopzione chiede al compilatore di ottimizzare un po '(potrebbe ottimizzare di più con -O2o -O3).

Se vuoi capire cosa gccsta facendo, prova a passare-fdump-tree-all ma attenzione: otterrai centinaia di file di dump.

A proposito, GCC è estendibile tramite plugin o con MELT (un linguaggio specifico di dominio di alto livello per estendere GCC; che ho abbandonato nel 2017)


forse menzioneremo che l'output sarà presente source.s, dal momento che molte persone si aspetterebbero una stampa sulla console.
RubenLaguna,

1
@ecerulm: -S -o-dump a stdout. -masm=intelè utile se si desidera utilizzare la sintassi NASM / YASM. (ma utilizza qword ptr [mem], piuttosto che solo qword, quindi è più simile a Intel / MASM che a NASM / YASM). gcc.godbolt.org fa un buon lavoro nel riordinare il dump: rimuovendo opzionalmente righe di solo commento, etichette non utilizzate e direttive assembler.
Peter Cordes,

2
Hai dimenticato di menzionare: se stai cercando "simile alla fonte ma senza il rumore del negozio / ricarica dopo ogni linea di fonte", allora -Ogè ancora meglio di -O1. Significa "ottimizzare per il debug" e fa asm senza troppe ottimizzazioni complicate / difficili da seguire che fanno tutto ciò che dice la fonte. È disponibile da gcc4.8, ma il clang 3.7 non lo possiede ancora. IDK se hanno deciso di non farlo o cosa.
Peter Cordes,

19

Puoi usare gdb per questo come objdump.

Questo estratto è tratto da http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64


Ecco un esempio che mostra sorgente mista + assembly per Intel x86:

  (gdb) disas / m main
Dump del codice assembler per la funzione principale:
5 {
0x08048330: push% ebp
0x08048331: mov% esp,% ebp
0x08048333: sub $ 0x8,% esp
0x08048336: e $ 0xfffffff0,% esp
0x08048339: sub $ 0x10,% esp

6 printf ("Ciao. \ N");
0x0804833c: movl $ 0x8048440, (% esp)
0x08048343: chiama 0x8048284 

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

Fine della discarica dell'assemblatore.


E per cambiare il disassemblatore di GDB nella sintassi Intel, usa il set disassembly-flavor intelcomando.
Ruslan,

13

Utilizzare l'opzione -S (nota: maiuscola S) su GCC e emetterà il codice assembly in un file con estensione .s. Ad esempio, il seguente comando:

gcc -O2 -S -c foo.c


4

Non ho dato un colpo a gcc, ma in caso di g ++. Il comando seguente funziona per me. -g per la compilazione del debug e -Wa, -adhln viene passato all'assemblatore per l'elenco con il codice sorgente

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


Funziona anche con gcc! -Wa, ... è per le opzioni della riga di comando per la parte assembler (eseguire in gcc / g ++ dopo la compilazione C / ++). Invoca internamente (as.exe in Windows). Vedi> as - help come riga di comando per vedere altro aiuto
Hartmut Schorrig,

0

usa -Wa, -adhln come opzione su gcc o g ++ per produrre un output dell'elenco su stdout.

-Wa, ... è per le opzioni della riga di comando per la parte assembler (eseguire in gcc / g ++ dopo la compilazione C / ++). Si invoca come internamente (as.exe in Windows). Vedere

> come --help

come riga di comando per vedere più aiuto per lo strumento assemblatore all'interno di gcc

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.