2011-05-13 83 views
38

在文件file1.c中,有一個調用函數,該函數在文件file2.c中實現。 當我將file1.ofile2.o鏈接到一個可執行文件中時,如果file2中的函數非常小,鏈接器是否會自動檢測到該函數很小並且內聯其調用?鏈接器內聯函數可以嗎?

+2

你試過了嗎? – 2011-05-13 03:40:45

+7

有些鏈接器可以,(Visual C++鏈接器有一個稱爲「鏈接時間代碼生成」的功能,可執行跨模塊內聯和優化)。無論您使用的鏈接程序是否可以執行此操作,都不可能說,因爲您沒有告訴我們您使用的是哪種鏈接程序(即便如此,唯一真正瞭解的方法是找出代碼你的鏈接器生成...)。 – 2011-05-13 03:44:11

回答

62

除了支持Jame McNellis提到的鏈接時間碼生成(LTCG)外,GCC工具鏈還支持鏈接時間優化。從版本4.5開始,GCC支持-flto交換機,該交換機支持鏈路時間優化(LTO),這是一種整體程序優化的形式,它允許從單獨的目標文件內聯函數(以及編譯器在編譯時可能做出的任何其他優化所有的對象文件就好像它們來自單個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,但爲了在我的簡單測試中獲得可見的結果,我必須使用-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,您必須編譯.c文件而不使用/GL以防止鏈接器執行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)。該技術允許微軟的鏈接器根據從以前的程序運行中收集的分析數據進行優化。這允許鏈接器執行諸如將「熱」功能聚集到相同的內存頁面上以及很少將代碼序列使用到其他內存頁面上以減少程序的工作集合的事情。

 


編輯(2011年8月28日):GCC支持輪廓使用選項,如-fprofile-generate-fprofile-use嚮導式優化,但我完全不瞭解他們。

感謝Konrad Rudolph爲我指出這一點。

+1

GCC還通過'-fprofile-generate'和'-fprofile-use'支持PGO。 – 2011-08-28 21:26:57

+0

@Konrad:哇 - 我完全沒有意識到。我得看看它。謝謝! – 2011-08-28 22:50:53

+1

但LTO不是由鏈接器(binutils/ld)處理;它是一個編譯器(gcc/gcc)。 – osgx 2011-08-28 23:41:10

相關問題