2011-05-13 1 views
38

file1.c 파일에는 file2.c 파일에 구현 된 함수 호출이 있습니다. file1.ofile2.o을 실행 파일에 연결하면 file2의 함수가 매우 작 으면 링커는 함수가 작고 호출을 인라인한다고 자동으로 감지합니까?링커 인라인 기능을 사용할 수 있습니까?

+2

시도해 보셨습니까? –

+7

일부 링커는 가능합니다 (Visual C++ 링커에는 모듈 간 인라인 및 최적화를 수행하는 "링크 타임 코드 생성"이라는 기능이 있습니다). 사용하고있는 링커가 이것을 할 수 있는지 여부를 결정할 때, 사용하는 링커를 알려주지 않았기 때문에 말하기가 불가능합니다 (심지어 그렇다고하더라도 실제로 알 수있는 유일한 실제 방법은 코드를 찾는 것입니다) 링커 생성 ...). –

답변

62

Jame McNellis가 언급 한 링크 타임 코드 생성 (LTCG)에 대한 지원 외에도 GCC 툴 체인은 링크 시간 최적화를 지원합니다. GCC는 4.5 버전부터 개별 객체 파일 (컴파일러가 컴파일 할 경우 컴파일러가 할 수있는 다른 최적화 기능)에서 인라인 함수를 허용하는 전체 프로그램 최적화의 한 형태 인 LTO (Link Time Optimization)를 활성화하는 -flto 스위치를 지원합니다 마치 하나의 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을 사용하지만 간단한 테스트에서 눈에 띄는 결과를 얻으려면를 사용해야했습니다. 7,875,113,642,216,824,987,383,210 :

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 

분해.

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. 

을 그리고 여기 (첫번째 LTCG와) MSVC와 같은 실험이다 : printf()에 대한 호출이 직접 유의하십시오 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> 

합니다. MSVC에서는 링커가 LTCG를 수행하지 못하도록 /GL없이 .c 파일을 컴파일해야합니다. 그렇지 않으면 링커가 /GL이 지정되었음을 감지하고 /LTCG 옵션을 강제 실행합니다 (이봐, 네가 원하는 주위 /GL에 처음) :

마이크로 소프트의 링커는 내가 아는 한 (GCC를 지원하지 않습니다 LTCG 에서 지원하는
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> 

한 것) 는 활용 최적화 (PGO)을 프로필입니다. 이 기술을 통해 Microsoft의 링커는 이전 프로그램 실행에서 수집 한 프로파일 링 데이터를 기반으로 최적화 할 수 있습니다.이를 통해 링커는 '핫'기능을 같은 메모리 페이지에 모으거나 드물게 사용되는 코드 시퀀스를 다른 메모리 페이지에 집어 넣어 프로그램의 작업 세트를 줄일 수 있습니다.

 


편집 (2011년 8월 28일) : GCC 지원 프로파일 -fprofile-generate-fprofile-use 등의 옵션을 사용하여 활용 최적화를,하지만 난 그들에 대해 완전히받지입니다.

이 점을 지적 해 주신 Konrad Rudolph에게 감사드립니다.

+1

GCC는'-fprofile-generate'와'-fprofile-use'를 통해 PGO도 지원합니다. –

+0

@Konrad : 와우 ​​- 나는 전혀 몰랐다. 나는 그것을 조사해야 할 것이다. 감사! –

+1

하지만 LTO는 링커 (binutils/ld)에서 처리하지 않습니다. 컴파일러 (gcc/gcc)입니다. – osgx