Respostas:
Use a -S
opção para gcc (ou g ++).
gcc -S helloworld.c
Isso executará o pré-processador (cpp) no helloworld.c, executará a compilação inicial e parará antes que o assembler seja executado.
Por padrão, isso produzirá um arquivo helloworld.s
. O arquivo de saída ainda pode ser definido usando a -o
opção
gcc -S -o my_asm_output.s helloworld.c
Claro que isso só funciona se você tiver a fonte original. Uma alternativa se você tiver apenas o arquivo de objeto resultante é usar objdump
, definindo a --disassemble
opção (ou -d
para o formulário abreviado).
objdump -S --disassemble helloworld > helloworld.dump
Essa opção funciona melhor se a opção de depuração estiver ativada para o arquivo de objeto ( -g
no momento da compilação) e o arquivo não tiver sido removido.
A execução file helloworld
fornecerá algumas indicações sobre o nível de detalhes que você obterá usando o objdump.
.intel_syntax
é compatível com o NASM . É mais parecido com o MASM (por exemplo, mov eax, symbol
é uma carga, diferente do NASM, onde é um mov r32, imm32
endereço), mas também não é totalmente compatível com o MASM. Eu o recomendo como um bom formato para ler, especialmente se você gosta de escrever na sintaxe do NASM. objdump -drwC -Mintel | less
ou gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | less
são úteis. (Veja também Como remover “ruído” da saída do conjunto GCC / clang? ). -masm=intel
trabalha com clang também.
gcc -O -fverbose-asm -S
Isso gerará código de montagem com o código C + números de linha entrelaçados, para ver mais facilmente quais linhas geram qual código:
# 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
Encontrado em Algoritmos para programadores , página 3 (que é a 15ª página geral do PDF).
as
no OS X não conhece essas bandeiras. Se isso acontecesse, você provavelmente poderia usar uma linha -Wa
para passar as opções para as
.
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lst
seria a versão abreviada disso.
gcc -c -g -Wa,-ahl=test.s test.c
orgcc -c -g -Wa,-a,-ad test.c > test.txt
-O0
? Está cheio de cargas / lojas que dificultam o rastreamento de um valor e não informa nada sobre a eficiência do código otimizado.
A seguinte linha de comando é do blog de Christian Garbin
g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
Executei o G ++ a partir de uma janela do DOS no Win-XP, em uma rotina que contém uma conversão implícita
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'
A saída é um código gerado montado, intercalado com o código C ++ original (o código C ++ é mostrado como comentários no fluxo asm gerado)
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)
-O2
as opções de otimização que você realmente usa ao criar seu projeto, se quiser ver como o gcc otimiza seu código. (Ou se você usar LTO, como você deve, então você tem que desmontar a saída vinculador para ver o que realmente se.)
Se o que você deseja ver depende da vinculação da saída, então o objdump no arquivo / executável do objeto de saída também pode ser útil além do gcc -S acima mencionado. Aqui está um script muito útil de Loren Merritt que converte a sintaxe objdump padrão na sintaxe nasm mais legível:
#!/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;
Eu suspeito que isso também pode ser usado na saída do gcc -S.
mov eax,ds:0x804b794
não é muito NASMish. Além disso, às vezes, apenas retira informações úteis: movzx eax,[edx+0x1]
deixa o leitor adivinhar se o operando da memória era byte
ou word
.
objconv
. Você pode desmontá-lo no stdout com o arquivo de saída = /dev/stdout
, para que possa ser less
visualizado. Também existe ndisasm
, mas desmonta apenas binários planos e não sabe sobre arquivos de objetos (ELF / PE).
Como todos apontaram, use a -S
opção para o GCC. Gostaria também de acrescentar que os resultados podem variar (muito!), Dependendo de você adicionar ou não opções de otimização ( -O0
por nenhuma, -O2
para otimização agressiva).
Em arquiteturas RISC, em particular, o compilador geralmente transformará o código quase além do reconhecimento na otimização. É impressionante e fascinante ver os resultados!
Como mencionado anteriormente, observe o sinalizador -S.
Também vale a pena examinar a família de sinalizadores '-fdump-tree', em particular '-fdump-tree-all', que permite ver algumas das formas intermediárias do gcc. Isso geralmente pode ser mais legível que o assembler (pelo menos para mim) e permite que você veja o desempenho das passagens de otimização.
Não vejo essa possibilidade entre as respostas, provavelmente porque a pergunta é de 2008, mas em 2018 você pode usar o site online de Matt Goldbolt https://godbolt.org
Você também pode clonar git localmente e executar o projeto https://github.com/mattgodbolt/compiler-explorer
-save-temps
Isso foi mencionado em https://stackoverflow.com/a/17083009/895245, mas deixe-me exemplificar ainda mais.
A grande vantagem dessa opção -S
é que é muito fácil adicioná-la a qualquer script de construção, sem interferir muito na própria construção.
Quando você faz:
gcc -save-temps -c -o main.o main.c
main.c
#define INC 1
int myfunc(int i) {
return i + INC;
}
e agora, além da saída normal main.o
, o diretório de trabalho atual também contém os seguintes arquivos:
main.i
é um bônus e contém o arquivo pré-processado:
# 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
contém a montagem gerada desejada:
.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 você deseja fazer isso para um grande número de arquivos, considere usar:
-save-temps=obj
que salva os arquivos intermediários no mesmo diretório que a -o
saída do objeto em vez do diretório de trabalho atual, evitando possíveis conflitos de nome de base.
Outra coisa interessante sobre essa opção é se você adicionar -v
:
gcc -save-temps -c -o main.o -v main.c
na verdade, mostra os arquivos explícitos sendo usados em vez de temporários feios /tmp
, por isso é fácil saber exatamente o que está acontecendo, o que inclui as etapas de pré-processamento / compilação / montagem:
/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
Testado no Ubuntu 19.04 amd64, GCC 8.3.0.
Use a opção -S:
gcc -S program.c
De: http://www.delorie.com/djgpp/v2faq/faq8_20.html
gcc -c -g -Wa, -a, -ad [outras opções do GCC] foo.c> foo.lst
em alternativa à resposta de PhirePhly Ou apenas use -S como todos disseram.
Aqui estão as etapas para ver / imprimir o código de montagem de qualquer programa C no Windows
console / terminal / prompt de comando:
Escreva um programa C em um editor de código C, como codeblocks, e salve-o com uma extensão .c
Compile e execute-o.
Depois de executar com êxito, vá para a pasta em que você instalou seu compilador gcc e dê o
seguinte comando para obter um arquivo '.s' do arquivo '.c'
C: \ gcc> gcc -S caminho completo do arquivo C ENTER
Um comando de exemplo (como no meu caso)
C: \ gcc> gcc -SD: \ Aa_C_Certified \ alternate_letters.c
Isso gera um arquivo '.s' do arquivo '.c' original
4) Depois disso, digite o seguinte comando
C; \ gcc> cpp filename.s ENTER
Comando de exemplo (como no meu caso)
C; \ gcc> cpp alternate_letters.s
Isso imprimirá / produzirá todo o código da linguagem Assembly do seu programa C.
Use "-S" como uma opção. Ele exibe a saída da montagem no terminal.
gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less
. -S
por conta própria cria foo.s
.
Recentemente, eu queria conhecer a montagem de cada função em um programa,
foi assim que eu fiz.
$ 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
Aqui está uma solução para C usando o gcc:
gcc -S program.c && gcc program.c -o output
Aqui, a primeira parte armazena a saída de montagem do programa no mesmo nome de arquivo que o Programa, mas com uma extensão .s alterada , você pode abri-lo como qualquer arquivo de texto normal.
A segunda parte aqui compila seu programa para uso real e gera um executável para o seu programa com um nome de arquivo especificado.
O program.c usado acima é o nome do seu programa e a saída é o nome do executável que você deseja gerar.
BTW É o meu primeiro post no StackOverFlow: -}