链接器内联函数可以吗?

在文件file1.c ,有一个对文件file2.c实现的函数的调用。 当我将file1.ofile2.o链接到一个可执行文件中时,如果file2的函数非常小,链接程序是否会自动检测到该函数很小并且内联它的调用?

除了支持Jame McNellis提到的链接时间代码生成(LTCG)外,GCC工具链还支持链接时间优化。 从版本4.5开始,GCC支持启用链接时间优化(LTO)的-flto开关,LTO是一种整体程序优化的forms,它允许从单独的目标文件内联函数(以及编译器可能能够做出的任何其他优化编译所有的目标文件就好像它们来自单个C源文件)。

这是一个简单的例子:

test.c

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

print_int.c

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

首先使用GCC4.5.x编译它们 – GCC文档中的示例使用了-O2 ,但为了在我的简单testing中获得可见的结果,我必须使用-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 

为了得到LTO的效果,即使在链接阶段,也应该使用优化选项 – 链接器实际上会调用编译器来编译上面第一步中编译器放入对象文件的中间代码段。 如果您在这个阶段没有通过优化选项,编译器将不会执行您要查找的内联。

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

反汇编版本没有链接时间优化。 请注意,调用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 <print_int> 0x0040138a <+26>: movl $0x2a,(%esp) 0x00401391 <+33>: call 0x401350 <print_int> 0x00401396 <+38>: movl $0xffffffff,(%esp) 0x0040139d <+45>: call 0x401350 <print_int> 0x004013a2 <+50>: xor %eax,%eax 0x004013a4 <+52>: leave 0x004013a5 <+53>: ret 

通过链接时间优化对版本进行反汇编。 请注意,对printf()的调用是直接进行的:

 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 <printf> 0x00401392 <+34>: movl $0x2a,0x4(%esp) 0x0040139a <+42>: movl $0x403064,(%esp) 0x004013a1 <+49>: call 0x401acc <printf> 0x004013a6 <+54>: movl $0xffffffff,0x4(%esp) 0x004013ae <+62>: movl $0x403064,(%esp) 0x004013b5 <+69>: call 0x401acc <printf> 0x004013ba <+74>: xor %eax,%eax 0x004013bc <+76>: leave 0x004013bd <+77>: ret End of assembler dump. 

这里是与MSVC(首先与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> 

现在没有LTCG。 请注意,使用MSVC,您必须编译没有/GL的.c文件,以阻止链接器执行LTCG,否则链接器会检测到/GL已被指定,并强制执行/LTCG选项(嘿,这就是您所说的你想第一次与/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> 

微软的链接器在LTCG 支持的一个不被GCC支持的事情(就我所知)就是简档引导优化(PGO)。 该技术允许微软的链接器根据从以前的程序运行中收集的分析数据进行优化。 这允许链接器执行诸如将“热”function聚集到相同的内存页面上以及很less使用在其他内存页面上的代码序列来减less程序的工作集。


编辑(2011年8月28日):GCC支持configuration文件指导优化使用-fprofile-generate-fprofile-use这样的选项,但我完全不了解它们。

感谢Konrad Rudolph向我指出这一点。