Usando o GCC para produzir montagem legível?

256

Eu queria saber como usar o GCC no meu arquivo de origem C para despejar uma versão mnemônica do código da máquina para que eu pudesse ver em que meu código estava sendo compilado. Você pode fazer isso com Java, mas não consegui encontrar uma maneira com o GCC.

Estou tentando reescrever um método C em assembly e ver como o GCC faz isso seria uma grande ajuda.

James
fonte
25
observe que 'bytecode' normalmente significa o código consumido por uma VM, como JVM ou CLR do .NET. A saída do GCC é melhor chamado de 'código de máquina', 'linguagem de máquina' ou 'linguagem assembly'
Javier
2
Eu adicionei uma resposta usando o godbolt, pois é uma ferramenta muito poderosa para experimentar rapidamente como as opções diferentes afetam sua geração de código.
Shafik Yaghmour
Possível duplicata de Como você obtém a saída do assembler da fonte C / C ++ no gcc?
Ciro Santilli escreveu:
Para obter mais dicas sobre como tornar a saída ASM legível por humanos, consulte também: Como remover “ruído” da saída do conjunto GCC / clang?
Peter Cordes

Respostas:

335

Se você compilar com símbolos de depuração, poderá usar objdumppara produzir uma desmontagem mais legível.

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

objdump -drwC -Mintel é legal:

  • -rmostra os nomes dos símbolos nas realocações (você verá putsna callinstrução abaixo)
  • -R mostra realocações de vinculação dinâmica / nomes de símbolos (útil em bibliotecas compartilhadas)
  • -C desmarca os nomes dos símbolos C ++
  • -w é o modo "amplo": ele não quebra os bytes de código de máquina
  • -Mintel: use a .intel_syntax noprefixsintaxe semelhante a GAS / binutils MASM em vez da AT&T
  • -S: intercalar linhas de origem com desmontagem.

Você poderia colocar algo como alias disas="objdump -drwCS -Mintel"no seu~/.bashrc


Exemplo:

> 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
Bastien Léonard
fonte
3
Existe uma opção para pegar apenas as instruções da Intel?
James James
3
Todas estas são instruções da Intel, pois são executadas nos processadores Intel: D.
Toto
12
@toto Eu acho que ele significa Intel sintaxe em vez de sintaxe AT & T
Amok
7
É possível renunciar ao arquivo de objeto intermediário usando o comando switch -Wa,-adhln -g to gcc. Isso pressupõe que o montador é gás e isso nem sempre pode ser o caso.
Marc Butler
8
@ James Sim, fornecimento -Mintel.
fuz 26/09/15
106

Se você der a bandeira ao GCC-fverbose-asm , ela será

Coloque informações adicionais de comentários no código de montagem gerado para torná-lo mais legível.

[...] Os comentários adicionados incluem:

  • informações sobre a versão do compilador e as opções da linha de comando,
  • as linhas de código-fonte associadas às instruções de montagem, no formato FILENAME: LINENUMBER: CONTENT OF LINE,
  • dicas nas quais expressões de alto nível correspondem aos vários operandos de instruções de montagem.
Kasper
fonte
Mas então, eu teria perdido todo o interruptor usado para objdump- objdump -drwCS -Mintel, então como eu posso usar algo como verbosecom objdump? Para que eu possa ter comentários no código asm, assim como -fverbose-asmno gcc?
Pastor
1
@ Herdsman: você não pode. As coisas extras -fverbose-asmadicionadas estão na forma de comentários na sintaxe asm da saída, não nas diretivas que colocarão algo extra no .oarquivo. Tudo é descartado no momento da montagem. Observe a saída do compilador asm em vez da desmontagem, por exemplo, em godbolt.org, onde você pode facilmente combiná-lo com a linha de origem via mouseover e realce de cores das linhas de origem / asm correspondentes. Como remover "ruído" da saída do conjunto GCC / clang?
Peter Cordes
75

Use a opção -S (observação: maiúscula S) para GCC e ela emitirá o código do assembly para um arquivo com extensão .s. Por exemplo, o seguinte comando:

gcc -O2 -S foo.c

deixará o código de montagem gerado no arquivo foo.s.

Extraído diretamente de http://www.delorie.com/djgpp/v2faq/faq8_20.html (mas removendo erros -c)

Andrew Keeton
fonte
35
Você não deve misturar -c e -S, use apenas um deles. Nesse caso, um está substituindo o outro, provavelmente dependendo da ordem em que são usados.
23909 Adam Rosenfield
4
@AdamRosenfield Alguma referência sobre 'não deve misturar -c e -S'? Se for verdade, devemos lembrar o autor e editá-lo.
Tony
5
@Tony : gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Options "Você pode usar ... uma das opções -c, -S ou -E para dizer onde o gcc deve parar. "
Node Eldredge
1
Se você deseja todas as saídas intermediárias, use gcc -march=native -O3 -save-temps. Você ainda pode usar -cpara parar na criação do arquivo de objeto sem tentar vincular, ou o que seja.
Peter Cordes
2
-save-tempsé interessante, pois despeja de uma só vez o código exato gerado pelo código, enquanto a outra opção de chamar o compilador com -Smeios de compilar duas vezes e, possivelmente, com opções diferentes. Mas -save-temps despeja tudo no diretório atual, o que é meio confuso. Parece que é mais uma opção de depuração para o GCC do que uma ferramenta para inspecionar seu código.
Stéphane Gourichon 22/01
50

Usar o -Sswitch para o GCC em sistemas baseados em x86 produz um dump da sintaxe da AT&T, por padrão, que pode ser especificada com o -masm=attswitch, da seguinte maneira:

gcc -S -masm=att code.c

Considerando que, se você quiser produzir um dump na sintaxe da Intel, poderá usar o -masm=intelswitch da seguinte maneira:

gcc -S -masm=intel code.c

(Ambos produzem despejos code.cem suas várias sintaxes, no arquivo, code.srespectivamente)

Para produzir efeitos semelhantes com o objdump, você deseja usar a opção --disassembler-options= intel/ att, um exemplo (com despejos de código para ilustrar as diferenças na sintaxe):

 $ 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
amaterasu
fonte
O que ... gcc -S -masm=intel test.cfez não exatamente trabalho para mim, eu tenho algum cruzamento de Intel e AT & T sintaxe como esta: mov %rax, QWORD PTR -24[%rbp]em vez disso: movq -24(%rbp), %rax.
22410
1
Boa dica. Deve-se notar que isso também funciona ao executar saída paralela de .oarquivos e ASM, ou seja, via-Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm
underscore_d
Poderia usar -Mopção, é o mesmo que --disassembler-options, mas muito mais curto, por exemploobjdump -d -M intel a.out | less -N
Eric Wang
34

godbolt é uma ferramenta muito útil, eles listam apenas compiladores C ++, mas você pode usar -x cflag para fazer com que ele trate o código como C. Ele gerará uma lista de montagem para o seu código lado a lado e você pode usar a Colouriseopção para gerar barras coloridas para indicar visualmente qual código-fonte é mapeado para o assembly gerado. Por exemplo, o seguinte código:

#include <stdio.h>

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

usando a seguinte linha de comando:

-x c -std=c99 -O3

e Colourisegeraria o seguinte:

insira a descrição da imagem aqui

Shafik Yaghmour
fonte
Seria bom saber como os filtros godbolt funcionam: .LC0, .text, // e Intel. Intel é fácil, -masm=intelmas e o resto?
Z boson
Eu acho que é explicado aqui stackoverflow.com/a/38552509/2542702
Z boson
O godbolt suporta C (junto com várias outras línguas como Rust, D, Pascal ...). É apenas que há muito menos compiladores C, por isso ainda é melhor usar compiladores C ++ com-x c
phuclv
23

Você tentou gcc -S -fverbose-asm -O source.cexaminar o source.sarquivo assembler gerado ?

O código do assembler gerado entra source.s(você pode substituí-lo pelo -o assembler-filename ); a -fverbose-asmopção solicita que o compilador emita alguns comentários do assembler "explicando" o código do assembler gerado. A -Oopção solicita que o compilador otimize um pouco (ele pode otimizar mais com -O2ou -O3).

Se você quiser entender o que gccestá fazendo, tente passar, -fdump-tree-allmas tenha cuidado: você receberá centenas de arquivos de despejo.

BTW, o GCC é extensível através de plugins ou com MELT (uma linguagem específica de domínio de alto nível para estender o GCC; que eu abandonei em 2017)

Basile Starynkevitch
fonte
talvez mencione que a saída será exibida source.s, pois muitas pessoas esperariam uma impressão no console.
precisa saber é o seguinte
1
@ecerulm: -S -o-despeja para stdout. -masm=intelé útil se você deseja usar a sintaxe NASM / YASM. (mas usa qword ptr [mem], e não apenas qword, é mais como Intel / MASM do que NASM / YASM). O gcc.godbolt.org faz um bom trabalho de organização do despejo: opcionalmente, excluindo linhas somente para comentários, rótulos não utilizados e diretivas de montagem.
Peter Cordes
2
Esqueci de mencionar: Se você está procurando "semelhante à fonte, mas sem o barulho de armazenar / recarregar após cada linha de fonte", -Ogé ainda melhor que -O1. Significa "otimizar para depuração" e faz o asm sem muitas otimizações difíceis / difíceis de seguir que fazem tudo o que a fonte diz. Está disponível desde o gcc4.8, mas o clang 3.7 ainda não o possui. IDK se eles decidiram contra ou o quê.
Peter Cordes
19

Você pode usar o gdb para isso, como o objdump.

Este trecho foi retirado de http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64


Aqui está um exemplo mostrando fonte mista + assembly para Intel x86:

  (gdb) disas / m principal
Despejo do código do assembler para a função main:
5 {
0x08048330: push% ebp
0x08048331: mov% esp,% ebp
0x08048333: sub $ 0x8,% esp
0x08048336: e $ 0xfffffff0,% esp
0x08048339: sub $ 0x10,% esp

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

7 retorna 0;
8}
0x08048348: mov $ 0x0,% eax
0x0804834d: licença
0x0804834e: ret

Fim do despejo do montador.
Vishal Sagar
fonte
1
link arquivado
vlad4378
E para alternar o desmontador do GDB para a sintaxe Intel, use o set disassembly-flavor intelcomando
Ruslan
13

Use a opção -S (observação: maiúscula S) para GCC e ela emitirá o código do assembly para um arquivo com extensão .s. Por exemplo, o seguinte comando:

gcc -O2 -S -c foo.c

codymanix
fonte
4

Eu não dei uma chance ao gcc, mas no caso do g ++. O comando abaixo funciona para mim. -g para depuração e -Wa, -adhln é passado para o assembler para listar com o código fonte

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

DAG
fonte
Também funciona para o gcc! -Wa, ... é para opções de linha de comando para a parte do montador (execute no gcc / g ++ após a compilação do C / ++). Invoca como internamente (as.exe no Windows). Veja> as --help como linha de comando para obter mais ajuda
Hartmut Schorrig 17/04
0

use -Wa, -adhln como opção no gcc ou g ++ para produzir uma saída de listagem para o stdout.

-Wa, ... é para opções de linha de comando para a parte do montador (execute no gcc / g ++ após a compilação do C / ++). Invoca como internamente (as.exe no Windows). Vejo

> como --help

como linha de comando para ver mais ajuda para a ferramenta assembler dentro do gcc

Hartmut Schorrig
fonte