¿Usando GCC para producir un ensamblaje legible?

256

Me preguntaba cómo usar GCC en mi archivo fuente C para volcar una versión mnemónica del código de máquina para poder ver en qué se estaba compilando mi código. Puede hacer esto con Java, pero no he podido encontrar una manera con GCC.

Estoy tratando de reescribir un método C en ensamblador y ver cómo funciona GCC sería de gran ayuda.

James
fuente
25
tenga en cuenta que 'bytecode' generalmente significa el código consumido por una VM, como JVM o .NET's CLR. La salida de GCC se llama mejor 'código máquina', 'lenguaje máquina' o 'lenguaje ensamblador'
Javier
2
Agregué una respuesta usando godbolt, ya que es una herramienta muy poderosa para experimentar rápidamente cómo las diferentes opciones afectan su generación de código.
Shafik Yaghmour
Posible duplicado de ¿Cómo se obtiene la salida del ensamblador de la fuente C / C ++ en gcc?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Para obtener más consejos sobre cómo hacer que la salida asm sea legible para humanos, consulte también: ¿Cómo eliminar el "ruido" de la salida del ensamblaje GCC / clang?
Peter Cordes

Respuestas:

335

Si compila con símbolos de depuración, puede usar objdumppara producir un desmontaje más legible.

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

objdump -drwC -Mintel es bueno:

  • -rmuestra los nombres de los símbolos en las reubicaciones (por lo que vería putsen las callinstrucciones a continuación)
  • -R muestra reubicaciones de enlace dinámico / nombres de símbolos (útil en bibliotecas compartidas)
  • -C demanda los nombres de símbolos de C ++
  • -w es el modo "ancho": no ajusta en línea los bytes del código de máquina
  • -Mintel: use la .intel_syntax noprefixsintaxis similar a MASM de GAS / binutils en lugar de AT&T
  • -S: intercalar líneas de origen con desmontaje.

Podrías poner algo como alias disas="objdump -drwCS -Mintel"en tu~/.bashrc


Ejemplo:

> 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
fuente
3
¿Hay un interruptor para tomar solo las instrucciones de Intel?
James
3
Todas estas son instrucciones de Intel, ya que se ejecutan en procesadores Intel: D.
toto
12
@toto Creo que se refiere Intel sintaxis en lugar de la sintaxis de AT & T
Amok
77
Es posible renunciar al archivo de objeto intermedio con el mediante la secuencia de cambio -Wa,-adhln -g to gcc. Esto supone que el ensamblador es gas y este no siempre es el caso.
Marc Butler
8
@ James Sí, suministro -Mintel.
fuz
106

Si le das la bandera a GCC-fverbose-asm , será

Ponga información adicional de comentarios en el código de ensamblado generado para que sea más legible.

[...] Los comentarios agregados incluyen:

  • información sobre la versión del compilador y las opciones de línea de comandos,
  • las líneas del código fuente asociadas con las instrucciones de ensamblaje, en el formato FILENAME: LINENUMBER: CONTENT OF LINE,
  • insinúa en qué expresiones de alto nivel corresponden a los diversos operandos de instrucciones de ensamblaje.
Kasper
fuente
Pero entonces, me perdido todo el interruptor utilizado para objdump- objdump -drwCS -Mintel, ¿cómo puedo usar algo como verbosecon objdump? Para que pueda tener comentarios en el código asm, como lo hace -fverbose-asmen gcc?
Pastor
1
@Herdsman: no puedes. Las cosas -fverbose-asmadicionales que se agregan están en forma de comentarios en la sintaxis asm de la salida, no directivas que agregarán algo extra al .oarchivo. Todo se descarta en el momento del montaje. Mire la salida del compilador asm en lugar del desensamblaje, por ejemplo, en godbolt.org, donde puede emparejarla fácilmente con la línea fuente a través del mouseover y resaltar el color de las líneas fuente / asm correspondientes. ¿Cómo eliminar el "ruido" de la salida del conjunto GCC / clang?
Peter Cordes
75

Use el interruptor -S (nota: S mayúscula) a GCC, y emitirá el código de ensamblaje a un archivo con una extensión .s. Por ejemplo, el siguiente comando:

gcc -O2 -S foo.c

dejará el código de ensamblaje generado en el archivo foo.s.

Extraído directamente de http://www.delorie.com/djgpp/v2faq/faq8_20.html (pero eliminando erróneamente -c)

Andrew Keeton
fuente
35
No debe mezclar -c y -S, solo use uno de ellos. En este caso, uno está anulando al otro, probablemente dependiendo del orden en que se usen.
Adam Rosenfield
44
@AdamRosenfield ¿Alguna referencia sobre 'no debería mezclar -c y -S'? Si es cierto, debemos recordarle al autor y editarlo.
Tony
55
@Tony: gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Options "Puede usar ... una de las opciones -c, -S o -E para indicar dónde debe detenerse gcc. "
Nate Eldredge
1
Si desea todas las salidas intermedias, use gcc -march=native -O3 -save-temps. Todavía puede usar -cpara detenerse en la creación de archivos de objetos sin intentar vincular, o lo que sea.
Peter Cordes
2
-save-tempses interesante ya que voltea de una vez el código exacto generado, mientras que la otra opción de llamar al compilador -Ssignifica compilar dos veces, y posiblemente con diferentes opciones. Pero -save-temps vuelca todo en el directorio actual, que es un poco desordenado. Parece que está más pensado como una opción de depuración para GCC que como una herramienta para inspeccionar su código.
Stéphane Gourichon
50

El uso del -Scambio a GCC en sistemas basados ​​en x86 produce un volcado de sintaxis de AT&T, por defecto, que se puede especificar con el -masm=attcambio, de la siguiente manera:

gcc -S -masm=att code.c

Mientras que si desea generar un volcado en la sintaxis de Intel, puede usar el -masm=intelconmutador de esta manera:

gcc -S -masm=intel code.c

(Ambos producen volcados de code.csus diversas sintaxis, en el archivo code.srespectivamente)

Para producir efectos similares con objdump, querrás usar el modificador --disassembler-options= intel/ att, un ejemplo (con volcados de código para ilustrar las diferencias en la sintaxis):

 $ 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

y

$ 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
fuente
¿Qué ... gcc -S -masm=intel test.c¿no es exactamente el trabajo para mí, tengo algunos cruce de Intel y AT & T sintaxis de la siguiente manera: mov %rax, QWORD PTR -24[%rbp]en lugar de esto: movq -24(%rbp), %rax.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
1
Buen consejo. Cabe señalar que esto también funciona cuando se realizan salidas paralelas .oy archivos ASM, es decir, a través de-Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm
underscore_d
Podría usar la -Mopción, es lo mismo --disassembler-optionspero mucho más corto, por ejemploobjdump -d -M intel a.out | less -N
Eric Wang
34

godbolt es una herramienta muy útil, la lista solo tiene compiladores de C ++, pero puede usar -x cflag para que trate el código como C. Luego generará una lista de ensamblaje para su código de lado a lado y puede usar la Colouriseopción para generar barras de colores para indicar visualmente qué código fuente se asigna al ensamblaje generado. Por ejemplo el siguiente código:

#include <stdio.h>

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

usando la siguiente línea de comando:

-x c -std=c99 -O3

y Colourise generaría lo siguiente:

ingrese la descripción de la imagen aquí

Shafik Yaghmour
fuente
Sería bueno saber cómo funcionan los filtros godbolt: .LC0, .text, // e Intel. Intel es fácil, -masm=intelpero ¿qué pasa con el resto?
Z boson
Supongo que se explica aquí stackoverflow.com/a/38552509/2542702
Z boson
Godbolt admite C (junto con una tonelada de otros lenguajes como Rust, D, Pascal ...). Es solo que hay muchos menos compiladores de C, por lo que aún es mejor usar compiladores de C ++ con-x c
phuclv
23

¿Intentó gcc -S -fverbose-asm -O source.cluego buscar en el source.sarchivo ensamblador generado ?

El código de ensamblador generado entra source.s(puede anularlo con -o assembler-filename ); la -fverbose-asmopción le pide al compilador que emita algunos comentarios del ensamblador "explicando" el código del ensamblador generado. La -Oopción le pide al compilador que optimice un poco (podría optimizar más con -O2o -O3).

Si desea comprender lo que gccestá haciendo, intente pasar, -fdump-tree-allpero tenga cuidado: obtendrá cientos de archivos de volcado.

Por cierto, GCC es extensible a través de complementos o con MELT (un lenguaje específico de dominio de alto nivel para extender GCC; que abandoné en 2017)

Basile Starynkevitch
fuente
quizás mencione que la salida estará en source.s, ya que mucha gente esperaría una impresión en la consola.
RubenLaguna
1
@ecerulm: -S -o-volcados a stdout. -masm=inteles útil si desea utilizar la sintaxis NASM / YASM. (pero usa qword ptr [mem], en lugar de solo qword, por lo que es más como Intel / MASM que NASM / YASM). gcc.godbolt.org hace un buen trabajo al ordenar el volcado: opcionalmente, elimina las líneas de solo comentario, las etiquetas no utilizadas y las directivas de ensamblador.
Peter Cordes
2
Olvidé mencionar: si está buscando "similar a la fuente pero sin el ruido de almacenar / recargar después de cada línea de fuente", entonces -Oges incluso mejor que -O1. Significa "optimizar para la depuración" y crea asm sin demasiadas optimizaciones difíciles / difíciles de seguir que hacen todo lo que dice la fuente. Ha estado disponible desde gcc4.8, pero clang 3.7 todavía no lo tiene. IDK si decidieron en contra o qué.
Peter Cordes
19

Puede usar gdb para esto como objdump.

Este extracto está tomado de http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64


Aquí hay un ejemplo que muestra fuente mixta + ensamblaje para Intel x86:

  (gdb) disas / m principal
Volcado del código del ensamblador para la función main:
5 {
0x08048330: push% ebp
0x08048331: mov% esp,% ebp
0x08048333: sub $ 0x8,% esp
0x08048336: y $ 0xfffffff0,% esp
0x08048339: sub $ 0x10,% esp

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

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

Fin del volcado del ensamblador.
Vishal Sagar
fuente
Y para cambiar el desensamblador de GDB a la sintaxis de Intel, use el set disassembly-flavor intelcomando.
Ruslan
13

Use el interruptor -S (nota: S mayúscula) a GCC, y emitirá el código de ensamblaje a un archivo con una extensión .s. Por ejemplo, el siguiente comando:

gcc -O2 -S -c foo.c

codymanix
fuente
4

No le he dado una inyección a gcc, pero en el caso de g ++. El siguiente comando funciona para mí. -g para la compilación de depuración y -Wa, -adhln se pasa al ensamblador para que aparezca con el código fuente

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

TROZO DE CUERO
fuente
¡Funciona también para gcc! -Wa, ... es para las opciones de línea de comandos para la parte del ensamblador (ejecutar en gcc / g ++ después de la compilación C / ++). Se invoca como internamente (as.exe en Windows). Ver> as --help as command line para ver más ayuda
Hartmut Schorrig
0

use -Wa, -adhln como opción en gcc o g ++ para producir una salida de listado a stdout.

-Wa, ... es para las opciones de línea de comandos para la parte del ensamblador (ejecutar en gcc / g ++ después de la compilación C / ++). Se invoca como internamente (as.exe en Windows). Ver

> como --ayuda

como línea de comando para ver más ayuda sobre la herramienta ensambladora dentro de gcc

Hartmut Schorrig
fuente