¿Puede el enlazador funciones en línea?

En el archivo file1.c , hay una llamada a una función que se implementa en el archivo file2.c . Cuando enlace file1.o y file2.o en un ejecutable, si la función en el file2 es muy pequeña, ¿detectará el enlazador automáticamente que la función es pequeña e inline its call?

Además del soporte para Link Time Code Generation (LTCG) que Jame McNellis mencionó, el toolchain de GCC también es compatible con la optimización del tiempo de enlace. Comenzando con la versión 4.5, GCC admite el conmutador -flto que habilita la Optimización de tiempo de enlace (LTO), una forma de optimización de todo el progtwig que le permite alinear funciones desde archivos de objeto separados (y cualquier otra optimización que un comstackdor pueda hacer si fuera comstackndo todos los archivos de objeto como si fueran de un solo archivo fuente C).

Aquí hay un ejemplo simple:

test.c :

 void print_int(int x); int main(){ print_int(1); print_int(42); print_int(-1); return 0; } 

print_int.c :

 #include  void print_int( int x) { printf( "the int is %d\n", x); } 

Primero comstackrlos usando GCC4.5.x – los ejemplos de los documentos de GCC usan -O2 , pero para obtener resultados visibles en mi prueba simple, tuve que usar -O3 :

 C:\temp>gcc --version gcc (GCC) 4.5.2 # compile with preparation for LTO C:\temp>gcc -c -O3 -flto test.c C:\temp>gcc -c -O3 -flto print_int.c # link without LTO C:\temp>gcc -o test-nolto.exe print_int.o test.o 

Para obtener el efecto de LTO se supone que debes usar las opciones de optimización incluso en la etapa de enlace: el enlazador en realidad invoca el comstackdor para comstackr partes de código intermedio que el comstackdor puso en el archivo objeto en los primeros pasos anteriores. Si no pasa la opción de optimización en esta etapa, el comstackdor no realizará la alineación que estaría buscando.

 # link using LTO C:\temp>gcc -o test-lto.exe -flto -O3 print_int.o test.o 

Desassembly de la versión sin optimización del tiempo de enlace. Tenga en cuenta que las llamadas se realizan a la función print_int() :

 C:\temp>gdb test-nolto.exe GNU gdb (GDB) 7.2 (gdb) start Temporary breakpoint 1 at 0x401373 Starting program: C:\temp/test-nolto.exe [New Thread 3324.0xdc0] Temporary breakpoint 1, 0x00401373 in main () (gdb) disassem Dump of assembler code for function main: 0x00401370 <+0>: push %ebp 0x00401371 <+1>: mov %esp,%ebp => 0x00401373 <+3>: and $0xfffffff0,%esp 0x00401376 <+6>: sub $0x10,%esp 0x00401379 <+9>: call 0x4018ca <__main> 0x0040137e <+14>: movl $0x1,(%esp) 0x00401385 <+21>: call 0x401350  0x0040138a <+26>: movl $0x2a,(%esp) 0x00401391 <+33>: call 0x401350  0x00401396 <+38>: movl $0xffffffff,(%esp) 0x0040139d <+45>: call 0x401350  0x004013a2 <+50>: xor %eax,%eax 0x004013a4 <+52>: leave 0x004013a5 <+53>: ret 

Desassembly de la versión con optimización del tiempo de enlace. Tenga en cuenta que las llamadas a printf() se realizan directamente:

 C:\temp>gdb test-lto.exe GNU gdb (GDB) 7.2 (gdb) start Temporary breakpoint 1 at 0x401373 Starting program: C:\temp/test-lto.exe [New Thread 1768.0x126c] Temporary breakpoint 1, 0x00401373 in main () (gdb) disassem Dump of assembler code for function main: 0x00401370 <+0>: push %ebp 0x00401371 <+1>: mov %esp,%ebp => 0x00401373 <+3>: and $0xfffffff0,%esp 0x00401376 <+6>: sub $0x10,%esp 0x00401379 <+9>: call 0x4018da <__main> 0x0040137e <+14>: movl $0x1,0x4(%esp) 0x00401386 <+22>: movl $0x403064,(%esp) 0x0040138d <+29>: call 0x401acc  0x00401392 <+34>: movl $0x2a,0x4(%esp) 0x0040139a <+42>: movl $0x403064,(%esp) 0x004013a1 <+49>: call 0x401acc  0x004013a6 <+54>: movl $0xffffffff,0x4(%esp) 0x004013ae <+62>: movl $0x403064,(%esp) 0x004013b5 <+69>: call 0x401acc  0x004013ba <+74>: xor %eax,%eax 0x004013bc <+76>: leave 0x004013bd <+77>: ret End of assembler dump. 

Y aquí está el mismo experimento con MSVC (primero con LTCG):

 C:\temp>cl -c /GL /Zi /Ox test.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. test.c C:\temp>cl -c /GL /Zi /Ox print_int.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. print_int.c C:\temp>link /LTCG test.obj print_int.obj /out:test-ltcg.exe /debug Microsoft (R) Incremental Linker Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. Generating code Finished generating code C:\temp>"\Program Files (x86)\Debugging Tools for Windows (x86)"\cdb test-ltcg.exe Microsoft (R) Windows Debugger Version 6.12.0002.633 X86 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: test-ltcg.exe // ... 0:000> u main *** WARNING: Unable to verify checksum for test-ltcg.exe test_ltcg!main: 00cd1c20 6a01 push 1 00cd1c22 68d05dcd00 push offset test_ltcg!__decimal_point_length+0x10 (00cd5dd0) 00cd1c27 e8e3f3feff call test_ltcg!printf (00cc100f) 00cd1c2c 6a2a push 2Ah 00cd1c2e 68d05dcd00 push offset test_ltcg!__decimal_point_length+0x10 (00cd5dd0) 00cd1c33 e8d7f3feff call test_ltcg!printf (00cc100f) 00cd1c38 6aff push 0FFFFFFFFh 00cd1c3a 68d05dcd00 push offset test_ltcg!__decimal_point_length+0x10 (00cd5dd0) 00cd1c3f e8cbf3feff call test_ltcg!printf (00cc100f) 00cd1c44 83c418 add esp,18h 00cd1c47 33c0 xor eax,eax 00cd1c49 c3 ret 0:000> 

Ahora sin LTCG. Tenga en cuenta que con MSVC tiene que comstackr el archivo .c sin /GL para evitar que el enlazador realice LTCG; de lo contrario, el enlazador detecta que /GL se especificó y forzará la opción /LTCG (hey, eso es lo que dijo querías la primera vez con /GL ):

 C:\temp>cl -c /Zi /Ox test.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. test.c C:\temp>cl -c /Zi /Ox print_int.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. print_int.c C:\temp>link test.obj print_int.obj /out:test-noltcg.exe /debug Microsoft (R) Incremental Linker Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. C:\temp>"\Program Files (x86)\Debugging Tools for Windows (x86)"\cdb test-noltcg.exe Microsoft (R) Windows Debugger Version 6.12.0002.633 X86 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: test-noltcg.exe // ... 0:000> u main test_noltcg!main: 00c41020 6a01 push 1 00c41022 e8e3ffffff call test_noltcg!ILT+5(_print_int) (00c4100a) 00c41027 6a2a push 2Ah 00c41029 e8dcffffff call test_noltcg!ILT+5(_print_int) (00c4100a) 00c4102e 6aff push 0FFFFFFFFh 00c41030 e8d5ffffff call test_noltcg!ILT+5(_print_int) (00c4100a) 00c41035 83c40c add esp,0Ch 00c41038 33c0 xor eax,eax 00c4103a c3 ret 0:000> 

Una cosa que el enlazador de Microsoft admite en LTCG que no es compatible con GCC (hasta donde yo sé) es la optimización guiada de perfil (PGO). Esa tecnología permite que el enlazador de Microsoft optimice en base a una información de perfiles recostackda de ejecuciones previas del progtwig. Esto le permite al enlazador hacer cosas tales como juntar funciones ‘calientes’ en las mismas páginas de memoria y secuencias de código rara vez usadas en otras páginas de memoria para reducir el conjunto de trabajo de un progtwig.


Editar (28 de agosto de 2011): Optimización guiada del perfil de soporte de GCC usando opciones como -fprofile-generate y -fprofile-use , pero no estoy completamente informado sobre ellas.

Gracias a Konrad Rudolph por señalarme esto.