Elimination of unused functions
As you know, Link-time optimization can make decisions based on knowledge of all translation units. Let's assume the following example taken from Ruby configuration script:
#include <setjmp.h> jmp_buf jb; void foo(v) int v; { __builtin_longjmp(jb, v); } int main ( { builtin_setjmp(jb); return 0; }
The program tests if one can call __builtin_longjmp with a variable given as argument. With non-LTO mode a compilation error occurs:
gcc -O2 /tmp/test2.c /tmp/test2.c: In function ‘t’: /tmp/test2.c:5:19: error: ‘__builtin_longjmp’ second argument must be 1 void t(v) int v; {__builtin_longjmp(jb, v);}
If you build the same source file with -flto, there are no errors:
gcc -O2 -flto /tmp/test2.c echo $? 0
In LTO mode, the compiler proves that there is no usage of the symbol and the function is removed. Behavior is similar to keyword static that allows a compiler to do the same job even in non-LTO mode. To be sure a function symbol is not optimized out, add __attribute__((used)):
#include <setjmp.h> jmp_buf jb; __attribute__ ((used)) void foo(v) int v; {__builtin_longjmp(jb, v);} int main () { __builtin_setjmp(jb); return 0; }
Symbol usage from assembly language
Even though usage of assembly language is quite rare, there are still many libraries/programs that contain asm statements. Performance critical parts written in assembler can be widely seen in audio/video codecs. Let's take following http://gcc.gnu.org/PR60690 (ffmpeg bug) as our example:
static int __attribute__ ((used)) wm1010 = 12345; void fn1 () { __asm__(" \nmovq 0, %%mm3 \nmovq wm1010(%%rip), %%mm4 " "\nmovq %%mm0, 0 \nmovq %%mm0,0 \nmovq %%mm0,0 " " \nmovq %%mm0,0 \n2: " "\nmovq 0, %%mm0 \nmovq 0, %%mm1 \nmovq 0, " "%%mm2 \nmovq 0, %%mm3 \nmovq %%mm0, %%mm4 " "\npsrad $20, %%mm2 \npsrad $20, %%mm5 \nmovq %%mm6, " "%%mm2 \npsrad $20, %%mm5 \nmovq %%mm6, %%mm4 " "\npsrad $20, %%mm0 \npsrad $20, %%mm2 \npackssdw " "%%mm7, %%mm7 \nmovd %%mm7,0 \npackssdw %%mm0, " "%%mm2 \npsrad $20, %%mm5 \nmovq %%mm6, %%mm4 " "\nmovd %%mm6,0 \nmovd %%mm4,0 \nmovd %%mm4, %%eax " "\norl %%eax, %%eax \njz 0 " "\nmovq 0, %%mm4 \npmaddwd %%mm0, %%mm5 " "\npsrad $11, %%mm7 \npsrad $11, %%mm4 " "\n# .p2align \n6: movq 0, %%mm1 " " \npsrad $20, %%mm6 \npsrad $20, %%mm2 \n9: \n" :); }
If we compile and link the translation unit with following options:
gcc -O2 -fPIC -shared dsputil_init.i simple_idct.i -g
objdump presents:
0000000000004880 <fn1>: static int __attribute__ ((used)) wm1010 = 123456; void fn1 () { __asm__(" \nmovq 0, %%mm3 \nmovq wm1010(%%rip), %%mm4 " 4880: 0f 6f 1c 25 00 00 00 movq 0x0,%mm3 4887: 00 4888: 0f 6f 25 d1 2d 00 00 movq 0x2dd1(%rip),%mm4 # 7660 <wm1010>
On the other hand, if you add -flto option, a linker cannot perform position independent code:
gcc -O2 -fPIC -shared dsputil_init.i simple_idct.i -g -flto ld: error: /tmp/ccmWN08q.ltrans1.ltrans.o: requires dynamic R_X86_64_PC32 reloc against 'wm1010' which may overflow at runtime; recompile with -fPIC collect2: error: ld returned 1 exit status
Explanation is quite simple: even though the used attribute is added to the static variable, the compiler does not parse asm statements for a translation unit. As a result, LTO partitioning does not tie wm1010 and fn1 and the symbols go to different partitions.
Objdump of partitions follows:
ltrans0.s:
.LHOTE73: .data .align 4 .type wm1010, @object .size wm1010, 4 wm1010: .long 123456 .text
ltrans1.s:
fn1: .LFB25: .loc 2 4 0 .cfi_startproc .loc 2 5 0 #APP # 5 "simple_idct.i" 1 movq 0, %mm3 movq wm1010(%rip), %mm4
As you can see, the generated objects cannot really be linked to fulfill -fPIC flag.
As a workaround you may use -fno-lto when compiling the files that contain the asm statements.
ar, nm and ranlib
If you try to build bigger projects with -flto you have to make sure that you use a version of binutils that supports gcc's liblto_plugin. Since version 4.9 gcc produces slim object files that only contain the intermediate representation. In order to handle archives of these objects you have to use the gcc wrappers: gcc-ar, gcc-nm and gcc-ranlib. (The next version of binutils will support automatic loading of the liblto_plugin.)
Let's take a simple example:
% cat a.c extern void foo1 (void); void foo2 (void) { foo1 (); } void foo3 (void) {} % cat b.c extern void foo2 (void); extern void foo3 (void); void foo1 (void) { foo3 (); } int main (void) { foo2 (); }
Creating an archive with gcc-ar works as expected:
% gcc -c -flto a.c % gcc-ar cr a.a a.o % gcc -flto b.c a.a %
If you use a version of ar that doesn't load the liblto_plugin, you'll get linker errors:
% gcc -c -flto a.c % ar cr a.a a.o % gcc -flto b.c a.a /tmp/ccncHnsT.ltrans0.ltrans.o:ccncHnsT.ltrans0.o:function foo1: error: undefined reference to 'foo3' /tmp/ccncHnsT.ltrans0.ltrans.o:ccncHnsT.ltrans0.o:function main: error: undefined reference to 'foo2' collect2: error: ld returned 1 exit status %
gcc uses standard ELF files with special LTO sections for storing its IR.
For example:
% readelf -SW a.o There are 17 section headers, starting at offset 0x518: Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 0000000000000000 000040 000000 00 AX 0 0 1 [ 2] .data PROGBITS 0000000000000000 000040 000000 00 WA 0 0 1 [ 3] .bss NOBITS 0000000000000000 000040 000000 00 WA 0 0 1 [ 4] .gnu.lto_.inline.4419b0beb59170a7 PROGBITS 0000000000000000 000040 000027 00 E 0 0 1 [ 5] .gnu.lto_foo2.4419b0beb59170a7 PROGBITS 0000000000000000 000067 0000a6 00 E 0 0 1 [ 6] .gnu.lto_foo3.4419b0beb59170a7 PROGBITS 0000000000000000 00010d 000081 00 E 0 0 1 [ 7] .gnu.lto_.symbol_nodes.4419b0beb59170a7 PROGBITS 0000000000000000 00018e 000039 00 E 0 0 1 [ 8] .gnu.lto_.refs.4419b0beb59170a7 PROGBITS 0000000000000000 0001c7 00000f 00 E 0 0 1 [ 9] .gnu.lto_.decls.4419b0beb59170a7 PROGBITS 0000000000000000 0001d6 00014e 00 E 0 0 1 [10] .gnu.lto_.symtab.4419b0beb59170a7 PROGBITS 0000000000000000 000324 00003c 00 E 0 0 1 [11] .gnu.lto_.opts PROGBITS 0000000000000000 000360 00004d 00 E 0 0 1 [12] .comment PROGBITS 0000000000000000 0003ad 00002a 01 MS 0 0 1 [13] .note.GNU-stack PROGBITS 0000000000000000 0003d7 000000 00 0 0 1 [14] .shstrtab STRTAB 0000000000000000 0003d7 00013f 00 0 0 1 [15] .symtab SYMTAB 0000000000000000 000958 000198 18 16 15 8 [16] .strtab STRTAB 0000000000000000 000af0 000021 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)