基于库的C链接器优化
假设我在某个C库中有一个函数foo(),并且静态地将该库链接到某个可执行文件,但是没有从库或可执行文件中的代码调用该方法。 链接器会通过删除函数定义来优化最终可执行文件,还是它仍然是代码的一部分?基于库的C链接器优化,c,C,假设我在某个C库中有一个函数foo(),并且静态地将该库链接到某个可执行文件,但是没有从库或可执行文件中的代码调用该方法。 链接器会通过删除函数定义来优化最终可执行文件,还是它仍然是代码的一部分? 是否有任何链接器优化可以打开/关闭此行为?但是,它应该取决于您的工具链 我的gcc-7不包括它 您可以使用objdump //foo.h #pragma once int foo(int x); int foo2(int x); //foo.c #include "foo.h" int foo(in
是否有任何链接器优化可以打开/关闭此行为?但是,它应该取决于您的工具链 我的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
在test.c中使用函数时,它将出现在符号表中。
但是,如果库包含多个函数,则无论其使用情况如何,都将包含所有函数
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
您可以使用编译器标志解决这个问题(在gcc上)。
(见附件)
其思想是,使用-fffunction sections-fdata sections
构建所有对象文件,从而为每个函数创建一个唯一的节。(通常它们都在同一个.text中)
将向您展示以下内容:
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
这将导致:
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
通常是的,链接器应该能够进行这种优化,因为这通常是首先进行静态链接(而不是通常更可取的动态链接)的原因。您询问的是特定的工具链还是一般的(在这种情况下,答案是:这取决于您的工具链)你必须指定操作系统的链接。对于绝大多数系统来说:不,一个不被调用的函数(或者它的地址)不会被链接。请不要在询问C时加上C++。我猜答案是:有链接器会打开/关闭这种行为。
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
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