¿Usando GCC para producir un ensamblaje legible?

10 minutos de lectura

avatar de usuario
Jaime

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

Estoy tratando de volver a escribir un método C en ensamblaje y ver cómo lo hace GCC sería de gran ayuda.

  • tenga en cuenta que ‘código de bytes’ generalmente significa el código consumido por una máquina virtual, como JVM o CLR de .NET. La salida de GCC se llama mejor ‘código de máquina’, ‘lenguaje de máquina’ o ‘lenguaje ensamblador’

    – Javier

    17 de agosto de 2009 a las 19:27

  • Agregué una respuesta usando Godbolt ya que es una herramienta muy poderosa para experimentar rápidamente cómo las diferentes opciones afectan la generación de código.

    – Shafik Yaghmour

    12 de septiembre de 2014 a las 2:35

  • stackoverflow.com/a/19083877/995714

    – phuclv

    30 de noviembre de 2014 a las 6:33

  • Para obtener más consejos sobre cómo hacer que la salida asm sea legible por humanos, consulte también: ¿Cómo eliminar el “ruido” de la salida del ensamblaje GCC/clang?

    – Peter Cordes

    5 sep 2016 a las 20:46

  • Respondido aquí: stackoverflow.com/questions/137038/… Use la opción -S para gcc (o g++).

    – el conocimiento es poder

    26 de julio de 2017 a las 19:38

avatar de usuario
Bastien leonard

Si compila con símbolos de depuración (agregue -g a su línea de comando GCC, incluso si también está usando -O31), puedes usar objdump -S para producir un desensamblado más legible intercalado con fuente C.

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

objdump -drwC -Mintel es bueno:

  • -r muestra los nombres de los símbolos en las reubicaciones (para que vea puts en el call instrucciones a continuación)
  • -R muestra reubicaciones de enlaces dinámicos/nombres de símbolos (útil en bibliotecas compartidas)
  • -C desarma los nombres de los símbolos de C++
  • -w es el modo “ancho”: no envuelve los bytes de código de máquina
  • -Mintel: use GAS/binutils similar a MASM .intel_syntax noprefix sintaxis en lugar de AT&T
  • -S: líneas fuente intercaladas con desmontaje.

Podrías poner algo como alias disas="objdump -drwCS -Mintel" en tus ~/.bashrc. Si no está en x86, o si le gusta la sintaxis de AT&T, omita -Mintel.


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

Tenga en cuenta que esto no es utilizando -r entonces el call rel32=-4 no está anotado con el puts nombre del símbolo. Y parece un roto call que salta al medio de la instrucción de llamada en main. Recuerda que el rel32 el desplazamiento en la codificación de la llamada es solo un marcador de posición hasta que el enlazador complete un desplazamiento real (a un código auxiliar PLT en este caso, a menos que vincule estáticamente libc).


Nota al pie 1: la fuente intercalada puede ser complicada y no muy útil en compilaciones optimizadas; para eso, considera https://godbolt.org/ u otras formas de visualizar qué instrucciones van con qué líneas fuente. En el código optimizado, no siempre hay una sola línea fuente que represente una instrucción, pero la información de depuración elegirá una línea fuente para cada instrucción asm.

  • ¿Hay un interruptor para obtener solo las instrucciones de Intel?

    – Jaime

    17 de agosto de 2009 a las 19:39

  • Todas estas son instrucciones de Intel, ya que se ejecutan en procesadores Intel: D.

    – totó

    18 de agosto de 2009 a las 4:01

  • @toto Creo que se refiere a la sintaxis de Intel en lugar de la sintaxis de AT&T

    – Amok

    9 oct 2009 a las 21:56

  • 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 esto puede no ser siempre el caso.

    –Marc mayordomo

    8 de septiembre de 2010 a las 16:45


  • @James Sí, suministro -Mintel.

    – fuz

    26/09/2015 a las 15:42

avatar de usuario
Casper

Si das CCG la bandera -fverbose-asmva a

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

[…] Los comentarios agregados incluyen:

  • información sobre la versión del compilador y las opciones de la línea de comandos,
  • las líneas de código fuente asociadas con las instrucciones de ensamblaje, en la forma NOMBRE DE ARCHIVO: NÚMERO DE LÍNEA: CONTENIDO DE LA LÍNEA,
  • sugerencias sobre qué expresiones de alto nivel corresponden a los diversos operandos de instrucciones de ensamblaje.

  • Pero entonces, perdería todo el interruptor usado para objdumpobjdump -drwCS -Mintelentonces, ¿cómo puedo usar algo como verbose con objdump? Para que pueda tener comentarios en el código asm, al igual que -fverbose-asm en CCG?

    – Pastor

    10 de enero de 2020 a las 17:08


  • @Pastor: no puedes. las cosas extra -fverbose-asm los agregados tienen la forma de comentarios en la sintaxis asm de la salida, no directivas que pondrán algo extra en el .o expediente. Todo se descarta en el momento del ensamblaje. Mire la salida del compilador asm en cambio de desmontaje, por ejemplo, en pernodios.org donde puede combinarlo fácilmente con la línea de origen mediante el mouseover y el resaltado en color de las líneas de origen / asm correspondientes. ¿Cómo eliminar el “ruido” de la salida del ensamblaje GCC/clang?

    – Peter Cordes

    9 de mayo de 2020 a las 19:16


avatar de usuario
andres keton

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

gcc -O2 -S foo.c

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

Arrancado directamente de http://www.delorie.com/djgpp/v2faq/faq8_20.html (pero eliminando errores -c)

  • No debe mezclar -c y -S, solo use uno de ellos. En este caso, uno anula al otro, probablemente dependiendo del orden en que se usen.

    – Adam Rosenfield

    17 de agosto de 2009 a las 19:28

  • @AdamRosenfield ¿Alguna referencia sobre ‘no debería mezclar -c y -S’? Si es cierto, deberíamos recordárselo al autor y editarlo.

    – Tony

    5 de agosto de 2014 a las 11:55

  • @Tony: gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Options “Puedes usar … uno de las opciones -c, -S o -E para decir dónde debe detenerse gcc”.

    – Nate Eldredge

    10 de abril de 2016 a las 0:32

  • Si desea todas las salidas intermedias, utilice gcc -march=native -O3 -save-temps. Todavía puedes usar -c para detenerse en la creación de archivos de objetos sin intentar vincular, o lo que sea.

    – Peter Cordes

    2 de junio de 2018 a las 1:21


  • -save-temps es interesante ya que vuelca de una sola vez el código generado por el código exacto, mientras que la otra opción de llamar al compilador con -S significa 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

    22 de enero de 2020 a las 18:16

avatar de usuario
Basile Starynkevitch

Has probado gcc -S -fverbose-asm -O source.c luego mira en el generado source.s archivo ensamblador?

El código ensamblador generado entra en source.s (usted podría anular eso con -o ensamblador-nombre de archivo ); la -fverbose-asm La opción le pide al compilador que emita algunos comentarios del ensamblador que “explican” el código del ensamblador generado. Él -O opción le pide al compilador que optimice un poco (podría optimizar más con -O2 o -O3).

Si quieres entender lo que gcc está haciendo intentar pasar -fdump-tree-all pero tenga cuidado: obtendrá cientos de archivos de volcado.

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

avatar de usuario
amaterasu

Utilizando el -S cambiar a GCC en sistemas basados ​​en x86 produce un volcado de sintaxis de AT&T, de forma predeterminada, que se puede especificar con el -masm=att cambiar, así:

gcc -S -masm=att code.c

Mientras que si desea producir un volcado en la sintaxis de Intel, puede utilizar el -masm=intel cambiar, así:

gcc -S -masm=intel code.c

(Ambos producen vertederos de code.c en sus diversas sintaxis, en el archivo code.s respectivamente)

Para producir efectos similares con objdump, querrá usar el --disassembler-options= intel/att switch, 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

  • Que… gcc -S -masm=intel test.c no funcionó exactamente para mí, obtuve un cruce de sintaxis de Intel y AT&T como esta: mov %rax, QWORD PTR -24[%rbp]en lugar de esto: movq -24(%rbp), %rax.

    – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

    22 de noviembre de 2009 a las 4:03

  • buen consejo Cabe señalar que esto también funciona cuando se realiza una salida paralela de .o y archivos ASM, es decir, a través de -Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm

    – subrayado_d

    20 de diciembre de 2015 a las 21:49

  • Podría utilizar -M opción, es lo mismo que --disassembler-options pero mucho más corto, por ejemplo objdump -d -M intel a.out | less -N

    –Eric

    5 de julio de 2016 a las 4:57

avatar de usuario
Arnie97

perno de dios es una herramienta muy útil, la lista solo tiene compiladores de C ++, pero puede usar -x c marca para que trate el código como C. Luego generará una lista de ensamblaje para su código en paralelo y puede usar el Colourise Opció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í

  • Que… gcc -S -masm=intel test.c no funcionó exactamente para mí, obtuve un cruce de sintaxis de Intel y AT&T como esta: mov %rax, QWORD PTR -24[%rbp]en lugar de esto: movq -24(%rbp), %rax.

    – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

    22 de noviembre de 2009 a las 4:03

  • buen consejo Cabe señalar que esto también funciona cuando se realiza una salida paralela de .o y archivos ASM, es decir, a través de -Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm

    – subrayado_d

    20 de diciembre de 2015 a las 21:49

  • Podría utilizar -M opción, es lo mismo que --disassembler-options pero mucho más corto, por ejemplo objdump -d -M intel a.out | less -N

    –Eric

    5 de julio de 2016 a las 4:57

avatar de usuario
codimanix

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

gcc -O2 -S -c foo.c

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad