¿Cómo se obtiene la salida del ensamblador desde la fuente C/C++ en GCC?

Resuelto Doug T. asked hace 16 años • 17 respuestas

¿Cómo se hace esto?

Si quiero analizar cómo se compila algo, ¿cómo obtendría el código ensamblador emitido?

Doug T. avatar Sep 26 '08 07:09 Doug T.
Aceptado

Utilice la opción -Sgcc para (o g++), opcionalmente con -fverbose-asm , que funciona bien con el valor predeterminado -O0 para adjuntar nombres C a operandos asm como comentarios. Funciona menos bien en cualquier nivel de optimización, que normalmente desea utilizar para que valga la pena mirarlo.

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. Para conocer opciones útiles del compilador para usar en ese caso, consulte ¿Cómo eliminar el "ruido" de la salida del ensamblado GCC/clang? (o simplemente mire su código en el Compiler Explorer en línea de Matt Godbolt , que filtra directivas y demás, y tiene resaltado para hacer coincidir las líneas fuente con asm usando información de depuración).

De forma predeterminada, esto generará el archivo helloworld.s. El archivo de salida aún se puede configurar usando la opción -o , incluso -o -para escribir en la salida estándar para canalizar a less .

gcc -S -o my_asm_output.s helloworld.c

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

objdump -S --disassemble helloworld > helloworld.dump

-Sentrelaza líneas fuente con la salida normal del desensamblado, por lo que esta opción funciona mejor si la opción de depuración está habilitada para el archivo objeto ( -g en el momento de la compilación) y el archivo no ha sido eliminado.

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

Otras objdumpopciones útiles incluyen -rwC(para mostrar reubicaciones de símbolos, deshabilitar el ajuste de líneas de código de máquina largo y exigir nombres de C++). Y si no le gusta la sintaxis de AT&T para x86, -Mintel. Consulte la página de manual .

Así por ejemplo, objdump -drwC -Mintel -S foo.o | less. -res muy importante con un .oque solo tiene 00 00 00 00marcadores de posición para referencias de símbolos, a diferencia de un ejecutable vinculado.

Andrew Edgecombe avatar Sep 26 '2008 00:09 Andrew Edgecombe

Esto generará código ensamblador con el código C + números de línea entrelazados, para ver más fácilmente qué líneas generan qué código ( -S -fverbose-asm -g -O2 ):

# 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 encontró en Algoritmos para programadores , página 3 (que es la página 15 del PDF).

PhirePhly avatar Sep 26 '2008 02:09 PhirePhly

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 Windows XP, contra una rutina que contiene una conversión implícita

cd C:\gpp_code
g++ -g -O -Wa,-aslh horton_ex2_05.cpp > list.txt

Producción:

horton_ex2_05.cpp: In function `int main()':
horton_ex2_05.cpp:92: warning: assignment to `int' from `double'

La salida es código generado ensamblado, intercalado con el código C++ original (el código C++ se muestra como comentarios en el flujo de lenguaje ensamblador 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)
Cr McDonough avatar Sep 29 '2013 22:09 Cr McDonough

Utilice el modificador -S :

g++ -S main.cpp

O también con gcc:

gcc -S main.c

Vea también esto .

Doug T. avatar Sep 26 '2008 00:09 Doug T.

-save-temps

Esto se mencionó en la respuesta de METADATA , pero permítanme ejemplificarlo con más detalle.

La gran ventaja de esta opción sobre -S es que es muy fácil agregarla a cualquier script de compilación, sin interferir mucho en la compilación misma:

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.ies una ventaja 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.scontiene 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
    

Documentos: https://gcc.gnu.org/onlinedocs/gcc/Developer-Options.html#index-save-temps

-save-temps=obj

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 base.

Por ejemplo:

gcc -save-temps -c -o out/subdir/main.o subdir/main.c

conduce a la creación de archivos:

out/subdir/main.i
out/subdir/main.o
out/subdir/main.s

Claramente un complot de Apple para apoderarse del mundo.

-save-temps -v

Otra cosa interesante de 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 utilizan en lugar de los feos archivos temporales debajo /tmp, por lo que es fácil saber exactamente qué 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

Fue probado en Ubuntu 19.04 (Disco Dingo) amd64, GCC 8.3.0.

CMake objetivos predefinidos

CMake proporciona automáticamente objetivos para el archivo preprocesado:

make help

nos muestra que podemos hacer:

make main.s

y ese objetivo se ejecuta:

Compiling C source to assembly CMakeFiles/main.dir/main.c.s
/usr/bin/cc    -S /home/ciro/hello/main.c -o CMakeFiles/main.dir/main.c.s

para que el archivo se pueda ver en CMakeFiles/main.dir/main.c.s.

Fue probado en CMake 3.16.1.