假设我有一个名为foo()的函数在某个C库中,并且我正在静态链接这个库到某个可执行文件中,但是库或可执行文件中没有调用该方法。
链接器是否通过删除函数定义来优化最终的可执行文件,还是它仍然是代码的一部分?
是否有任何链接器优化可以打开/关闭此行为?
这取决于你的工具链,然而我的gcc-7版本没有包含它。
你可以使用objdump
轻松测试它。
//foo.h
#pragma once
int foo(int x);
int foo2(int x);
//foo.c
#include "foo.h"
int foo(int x) {
return x * 2; //whatever
}
int foo2(int x) {
return x * 2; //whatever
}
//test.c
#include "foo.h"
int main() {
//foo(2);
return 0;
}
使用以下命令构建静态库:
gcc -c foo.c
ar rcs libfoo.a foo.o
objdump -j .text -S libfoo.a
Disassembly of section .text:
0000000000000000 <foo>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d fc mov %edi,-0x4(%rbp)
7: 8b 45 fc mov -0x4(%rbp),%eax
a: 01 c0 add %eax,%eax
c: 5d pop %rbp
d: c3 retq
000000000000000e <foo2>:
e: 55 push %rbp
f: 48 89 e5 mov %rsp,%rbp
12: 89 7d fc mov %edi,-0x4(%rbp)
15: 8b 45 fc mov -0x4(%rbp),%eax
18: c1 e0 02 shl $0x2,%eax
1b: 5d pop %rbp
1c: c3 retq
gcc test.c libfoo.a
之后,它并未出现在可执行文件中。objdump -j .text -x a.out
SYMBOL TABLE:
00000000000004f0 l d .text 0000000000000000 .text
0000000000000520 l F .text 0000000000000000 deregister_tm_clones
0000000000000560 l F .text 0000000000000000 register_tm_clones
00000000000005b0 l F .text 0000000000000000 __do_global_dtors_aux
00000000000005f0 l F .text 0000000000000000 frame_dummy
0000000000000680 g F .text 0000000000000002 __libc_csu_fini
0000000000000610 g F .text 0000000000000065 __libc_csu_init
00000000000004f0 g F .text 000000000000002b _start
00000000000005fa g F .text 000000000000000b main
SYMBOL TABLE:
00000000000004f0 l d .text 0000000000000000 .text
0000000000000520 l F .text 0000000000000000 deregister_tm_clones
0000000000000560 l F .text 0000000000000000 register_tm_clones
00000000000005b0 l F .text 0000000000000000 __do_global_dtors_aux
00000000000005f0 l F .text 0000000000000000 frame_dummy
00000000000006a0 g F .text 0000000000000002 __libc_csu_fini
000000000000061d g F .text 000000000000000f foo2
0000000000000630 g F .text 0000000000000065 __libc_csu_init
000000000000060f g F .text 000000000000000e foo
00000000000004f0 g F .text 000000000000002b _start
00000000000005fa g F .text 0000000000000015 main
-ffunction-sections -fdata-sections
构建所有对象文件,这将为每个函数创建一个唯一的部分。(通常它们都在同一个.text文件中)gcc -c foo.c -ffunction-sections -fdata-sections
ar rcs libfoo.a foo.o
objdump -S libfoo.a
将显示这个:
Disassembly of section .text.foo:
0000000000000000 <foo>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d fc mov %edi,-0x4(%rbp)
7: 8b 45 fc mov -0x4(%rbp),%eax
a: 01 c0 add %eax,%eax
c: 5d pop %rbp
d: c3 retq
Disassembly of section .text.foo2:
0000000000000000 <foo2>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d fc mov %edi,-0x4(%rbp)
7: 8b 45 fc mov -0x4(%rbp),%eax
a: c1 e0 02 shl $0x2,%eax
d: 5d pop %rbp
e: c3 retq
使用-Wl,--gc-sections
将启用链接过程中的垃圾收集,未使用的部分将被忽略/删除。
gcc test.c libfoo.a -Wl,--gc-sections
objdump -j .text -x a.out
SYMBOL TABLE:
00000000000004f0 l d .text 0000000000000000 .text
0000000000000520 l F .text 0000000000000000 deregister_tm_clones
0000000000000560 l F .text 0000000000000000 register_tm_clones
00000000000005b0 l F .text 0000000000000000 __do_global_dtors_aux
00000000000005f0 l F .text 0000000000000000 frame_dummy
0000000000000690 g F .text 0000000000000002 __libc_csu_fini
0000000000000620 g F .text 0000000000000065 __libc_csu_init
000000000000060f g F .text 000000000000000e foo
00000000000004f0 g F .text 000000000000002b _start
00000000000005fa g F .text 0000000000000015 main