¿Cómo se obtiene la salida del ensamblador de la fuente C / C ++ en gcc?


Respuestas:


422

Use la -Sopción para gcc (o g ++).

gcc -S helloworld.c

Esto ejecutará el preprocesador (cpp) sobre helloworld.c, realizará la compilación inicial y luego se detendrá antes de ejecutar el ensamblador.

Por defecto, esto generará un archivo helloworld.s. El archivo de salida todavía se puede configurar mediante la -oopción.

gcc -S -o my_asm_output.s helloworld.c

Por supuesto, esto solo funciona si tiene la fuente original. Una alternativa si solo tiene el archivo de objeto resultante es usar objdump, configurando la --disassembleopción (o -dpara la forma abreviada).

objdump -S --disassemble helloworld > helloworld.dump

Esta opción funciona mejor si la opción de depuración está habilitada para el archivo objeto ( -gen el momento de la compilación) y el archivo no se ha eliminado.

La ejecución file helloworldle dará alguna indicación sobre el nivel de detalle que obtendrá al usar objdump.


3
Si bien esto es correcto, los resultados de la respuesta de Cr McDonough me parecieron más útiles.
Rhys Ulerich el

3
un uso adicional: objdump -M intel -S --desmontar helloworld> helloworld.dump para obtener el volcado del objeto en la sintaxis de Intel compatible con nasm en linux.
touchStone

2
Si tiene una única función para optimizar / verificar, entonces puede probar los compiladores interactivos de C ++ en línea, es decir, Godbolt
fiorentinoing

1
@touchStone: GAS no.intel_syntax es compatible con NASM . Es más como MASM (por ejemplo, mov eax, symboles una carga, a diferencia de NASM donde es una mov r32, imm32de las direcciones), pero tampoco es totalmente compatible con MASM. Lo recomiendo encarecidamente como un buen formato para leer, especialmente si te gusta escribir en sintaxis NASM. objdump -drwC -Mintel | lesso gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | lessson útiles (Consulte también ¿Cómo eliminar el "ruido" de la salida del conjunto GCC / clang? ). -masm=inteltambién funciona con clang.
Peter Cordes

3
Mejor usogcc -O -fverbose-asm -S
Basile Starynkevitch

173

Esto generará código de ensamblaje con los números de línea del código C + entrelazados, para ver más fácilmente qué líneas generan qué 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

Se encuentra en Algoritmos para programadores , página 3 (que es la 15ª página general del PDF).


3
(Eso está realmente en la página (numerada) 3 (que es la 15ª página del PDF))
Grumdrig

1
Lamentablemente, asen OS X no conoce estas banderas. Sin embargo, si lo hiciera, probablemente podría usar esto en una línea -Wapara pasar opciones as.
Grumdrig el

23
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lstsería la versión abreviada de esto.
legends2k

44
También puede usar gcc -c -g -Wa,-ahl=test.s test.cogcc -c -g -Wa,-a,-ad test.c > test.txt
phuclv

1
Una publicación de blog que explica esto con más detalle, incluida la versión de un comando como leyendas y Lu'u publicado. Pero por que -O0? Está lleno de cargas / tiendas que dificultan el seguimiento de un valor, y no le dice nada acerca de cuán eficiente será el código optimizado.
Peter Cordes

51

La siguiente línea de comando es del blog de Christian Garbin.

g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt

Ejecuté G ++ desde una ventana de DOS en Win-XP, contra una rutina que contiene un reparto implícito

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'

La salida se ensambla con el código generado que se mezcla con el código original de C ++ (el código de C ++ se muestra como comentarios en el flujo de asm generado)

  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)

@Paladin: no necesariamente. El OP se trataba de obtener el equivalente de salida del ensamblador del código fuente C / C ++, esto obtiene el Listado, que estoy de acuerdo es más útil para comprender lo que está haciendo el compilador y el optimizador. Pero causaría que el ensamblador mismo vomitara, ya que no espera los números de línea, y compilará los bytes a la izquierda de las instrucciones de ensamblaje.
Jesse Chisholm

Use al menos -O2, o cualquier opción de optimización que realmente use al construir su proyecto, si desea ver cómo gcc optimiza su código. (O si usa LTO, como debería, entonces debe desarmar la salida del enlazador para ver lo que realmente obtiene.)
Peter Cordes

27

Use el interruptor -S

g++ -S main.cpp

o también con gcc

gcc -S main.c

También vea esto


77
Consulte las preguntas frecuentes: "También está perfectamente bien hacer y responder su propia pregunta de programación". El punto es que ahora StackOverflow contiene las preguntas y respuestas como un recurso para otros.
Steve Jessop

Y tal vez alguien más vendrá y te sorprenderá con una mejor respuesta, aunque la mía podría ser un poco detallada a veces ...
PhirePhly

Incluso hay un botón para responder a su propia pregunta.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

13

Si lo que quiere ver depende de la vinculación de la salida, entonces objdump en el archivo / ejecutable del objeto de salida también puede ser útil además del gcc -S mencionado anteriormente. Aquí hay un script muy útil de Loren Merritt que convierte la sintaxis objdump predeterminada en la sintaxis nasm más legible:

#!/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;

Sospecho que esto también se puede usar en la salida de gcc -S.


2
Aún así, este script es un truco sucio que no convierte completamente la sintaxis. Por ejemplo, mov eax,ds:0x804b794no es muy NASMish. Además, a veces simplemente elimina información útil: movzx eax,[edx+0x1]deja al lector adivinar si el operando de la memoria fue byteo no word.
Ruslan

Para desmontar la sintaxis NASM en primer lugar, use Agner Fog'sobjconv . Puede hacer que se desmonte en stdout con el archivo de salida = /dev/stdout, para que pueda canalizarlo lesspara verlo. También hay ndisasm, pero solo desmonta los binarios planos, y no conoce los archivos de objetos (ELF / PE).
Peter Cordes

9

Como todos han señalado, use la -Sopción para GCC. También me gustaría agregar que los resultados pueden variar (¡salvajemente!) Dependiendo de si agrega o no opciones de optimización ( -O0para ninguno, -O2para una optimización agresiva).

En arquitecturas RISC en particular, el compilador a menudo transformará el código casi más allá del reconocimiento al hacer la optimización. ¡Es impresionante y fascinante ver los resultados!


9

Bueno, como todos decían, usa la opción -S. Si usa la opción -save-temps, también puede obtener el archivo preprocesado ( .i), el archivo de ensamblaje ( .s) y el archivo de objeto (*. O). (obtén cada uno de ellos usando -E, -S y -c.)


8

Como se mencionó anteriormente, mira la bandera -S.

También vale la pena mirar la familia de banderas '-fdump-tree', en particular '-fdump-tree-all', que le permite ver algunas de las formas intermedias de gcc. Estos a menudo pueden ser más legibles que el ensamblador (al menos para mí) y le permiten ver cómo funcionan los pases de optimización.


8

Si está buscando el ensamblaje LLVM:

llvm-gcc -emit-llvm -S hello.c


8

-save-temps

Esto se mencionó en https://stackoverflow.com/a/17083009/895245 pero permítanme ejemplificarlo más.

La gran ventaja de esta opción -Ses que es muy fácil agregarlo a cualquier script de compilación, sin interferir mucho en la compilación misma.

Cuando tu lo hagas:

gcc -save-temps -c -o main.o main.c

C Principal

#define INC 1

int myfunc(int i) {
    return i + INC;
}

y ahora, además de la salida normal main.o, el directorio de trabajo actual también contiene los siguientes archivos:

  • main.i es una bonificación y contiene el archivo preprocesado:

    # 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 contiene el ensamblaje generado deseado:

        .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

Si desea hacerlo para una gran cantidad de archivos, considere usar en su lugar:

 -save-temps=obj

que guarda los archivos intermedios en el mismo directorio que la -osalida del objeto en lugar del directorio de trabajo actual, evitando así posibles conflictos de nombres básicos.

Otra cosa interesante de esta opción es si agrega -v:

gcc -save-temps -c -o main.o -v main.c

En realidad, muestra los archivos explícitos que se utilizan en lugar de los temporales feos debajo /tmp, por lo que es fácil saber exactamente lo que está sucediendo, lo que incluye los pasos de preprocesamiento / compilación / ensamblaje:

/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

Probado en Ubuntu 19.04 amd64, GCC 8.3.0.




3

Salida de estos comnads

Estos son los pasos para ver / imprimir el código de ensamblaje de cualquier programa C en su Windows

consola / terminal / símbolo del sistema:

  1. Escriba un programa C en un editor de código C como bloques de código y guárdelo con una extensión .c

  2. Compilar y ejecutarlo.

  3. Una vez ejecutado con éxito, vaya a la carpeta donde ha instalado su compilador gcc y proporcione el

    siguiente comando para obtener un archivo '.s' del archivo '.c'

    C: \ gcc> gcc -S ruta completa del archivo C ENTER

    Un comando de ejemplo (como en mi caso)

    C: \ gcc> gcc -SD: \ Aa_C_Certified \ alternate_letters.c

    Esto genera un archivo '.s' del archivo '.c' original

4) Después de esto, escriba el siguiente comando

C; \ gcc> cpp filename.s ENTER

Comando de ejemplo (como en mi caso)

C; \ gcc> cpp alternate_letters.s

Esto imprimirá / imprimirá todo el código del lenguaje ensamblador de su programa en C.


2

Use "-S" como una opción. Muestra la salida del ensamblaje en la terminal.


Para mostrar en el terminal, use gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less. -Spor sí mismo crea foo.s.
Peter Cordes

2

Recientemente quería saber el ensamblaje de cada función en un programa,
así es como lo hice.

$ 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

2

Aquí hay una solución para C usando gcc:

gcc -S program.c && gcc program.c -o output
  1. Aquí la primera parte almacena la salida del ensamblaje del programa en el mismo nombre de archivo que el Programa pero con una extensión .s modificada , puede abrirlo como cualquier archivo de texto normal.

  2. La segunda parte aquí compila su programa para el uso real y genera un ejecutable para su programa con un nombre de archivo especificado.

El program.c utilizado anteriormente es el nombre de su programa y la salida es el nombre del ejecutable que desea generar.

Por cierto, es mi primera publicación en StackOverFlow: -}

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.