Pregunta

¿Cómo se hace esto?

Si quiero analizar cómo se compila algo, ¿cómo puedo obtener el código de ensamblaje emitido?

¿Fue útil?

Solución

Use la opción -S 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 que se ejecute el ensamblador.

Por defecto, esto generará un archivo helloworld.s . El archivo de salida aún se puede configurar mediante la opción -o .

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 utilizar objdump , configurando la opción --disassemble (o -d para el abreviado forma).

objdump -S --disassemble helloworld > helloworld.dump

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

Ejecutar file helloworld le dará alguna indicación sobre el nivel de detalle que obtendrá al usar objdump.

Otros consejos

Esto generará el código ASM con el código C + los números de línea entrelazados para ver más fácilmente qué líneas generan qué código.

# create assembler code:
c++ -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 de el PDF).

La siguiente línea de comando es de Christian Garbin's blog

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 una conversión 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'

La salida es un código generado ensamblado, mezclado 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 <*>,-16(%ebp)

Usa el interruptor -S

g++ -S main.cpp

o también con gcc

gcc -S main.c

También vea esto

Si lo que desea ver depende de la vinculación de la salida, entonces objdump en el archivo de objeto de salida / ejecutable también puede ser útil, además de la mencionada gcc -S. Aquí hay un guión muy útil de Loren Merritt que convierte la sintaxis de 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
       

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

<*>

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

=~ /\tnop |\txchg *ax,ax$/) { # drop this line } else { print $prev; $prev =

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

<*>

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

; } } print $prev; close FH;

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

Bueno, como todos dijeron, use 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). (Obtenga cada uno de ellos usando -E, -S y -c.)

Como todos lo han señalado, use la opción -S para GCC. También me gustaría agregar que los resultados pueden variar (¡enormemente!) Dependiendo de si agrega o no las opciones de optimización ( -O0 para ninguna, -O2 para una optimización agresiva) .

En las 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!

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. A menudo, estos pueden ser más legibles que el ensamblador (al menos para mí), y le permiten ver cómo se realizan los pases de optimización.

Utilice la opción -S:

gcc -S program.c

Si está buscando un ensamblaje LLVM:

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

No veo esta posibilidad entre las respuestas, probablemente porque la pregunta es de 2008, pero en 2018 puede usar el sitio web en línea de Matt Goldbolt https://godbolt.org

También puede clonar localmente y ejecutar su proyecto https://github.com/mattgodbolt/compiler- explorador

De: http://www.delorie.com/djgpp/v2faq/faq8_20 .html

gcc -c -g -Wa, -a, -ad [otras opciones de GCC] foo.c > foo.lst

en alternativa a la respuesta de PhirePhly O simplemente use -S como todos dijeron.

 Salida de estas comunicaciones

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

consola / terminal / indicador de comando:

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

  2. Compila y ejecuta.

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

    siguiendo el 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 -S D: \ 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

Ejemplo de comando (como en mi caso)

C; \ gcc > cpp alternate_letters.s

Esto imprimirá / generará el código completo de lenguaje ensamblador de su programa en C

Utilice " -S " como una opción. Muestra la salida del conjunto en el terminal.

recientemente quise 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

-save-temps

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

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

main.c

#define INC 1

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

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

  • main.i es un bono y contiene el archivo preposeso deseado:

    # 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 salida del objeto -o en lugar del directorio de trabajo actual, evitando así posibles conflictos de nombre base.

La ventaja de esta opción sobre -S es que es fácil agregarla a cualquier script de compilación, sin interferir mucho en la compilación en sí.

Otra cosa interesante sobre esta opción es si agregas -v :

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

en realidad muestra los archivos explícitos que se están utilizando en lugar de los temporales feos en / tmp , por lo que es fácil saber exactamente qué está sucediendo, lo que incluye los pasos de preproceso / 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.

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 tu programa para uso real y genera un ejecutable para tu Programa con un nombre de archivo específico.

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

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top