我能找到的最佳解释来自官方文件:
-r --relocateable生成可重定位输出 - 即生成一个输出文件,该输出文件又可以作为ld的输入。这通常被称为 部分链接。作为副作用,在支持的环境中 标准的Unix幻数,此选项也设置输出文件 魔术数字给OMAGIC。如果未指定此选项,则为绝对值 文件已生成。链接C ++程序时,此选项不会 解析对构造函数的引用;要做到这一点,请使用-Ur。这个选项 做与`-i'相同的事情。
我特别想知道链接器输入中出现的符号会发生什么。当我有一个包含单个目标文件 component.o 的静态库 libstatic.a 时,请考虑具体情况。 现在,我想创建另一个静态库 libfinal.a ,它将作为 libstatic.a 的接口。我用这个命令来创建它:
ld -r -o libfinal.a wrapper.o -L. -lstatic
其中 wrapper.o 提供独占API来调用libstatic.a中定义的函数
libfinal.a 是否只是一个包含 wrapper.o 和 component.o 的组合存档,或者是所有可以引用的引用解析 wrapper.o 和 component.o 之间解决(链接)然后放入 libfinal.a ?
Edit_1:根据所取得的进展更新问题:
组件库libstatic.a
(objdump -D libstatic.a
)的 objdump 分别为每个函数显示.text
个部分(如预期的那样)。而在通过部分链接(libfinal.a
标志)创建的组合库-r
中,只有一个.text
部分。我想这意味着内部链接已经发生,而且不只是创建一个简单的存档。
答案 0 :(得分:3)
最小的可运行示例
在这里,我给出一个最小的示例,并以两种方式对其进行编译以生成功能相同的可执行文件:
f12.c
文件,没有部分链接,链接到f12.o
f1.c
和f2.c
,它们首先部分链接到f12_r.o
main.c
#include <assert.h>
#include <stdlib.h>
int f_1_2(void);
int f_2_1(void);
int main(void) {
assert(f_1_2() + f_2_1() == 5);
return EXIT_SUCCESS;
}
f1.c
#include "f1.h"
f2.c
#include "f2.h"
f12.c
#include "f1.h"
#include "f2.h"
f1.h
int f_2(void);
int f_1_2(void) {
return f_2() + 1;
}
int f_1(void) {
return 1;
}
f2.h
int f_1(void);
int f_2_1(void) {
return f_1() + 1;
}
int f_2(void) {
return 2;
}
run.sh
#!/usr/bin/env bash
set -eux
cflags='-ggdb3 -std=c99 -O0 -fPIE -pie'
gcc $cflags -c -o f1.o f1.c
gcc $cflags -c -o f2.o f2.c
gcc $cflags -c -o f12.o f12.c
ld -o f12_r.o -r f1.o f2.o
gcc $cflags -c -o main.o main.c
gcc $cflags -o main.out f12.o main.o
gcc $cflags -o main_r.out f12_r.o main.o
./main.out
./main_r.out
如果我们尝试相同的操作但没有ld -r
,则会收到最终警告:
+ ld -o f12_r.o f1.o f2.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
+ gcc -ggdb3 -std=c99 -O0 -fPIE -pie -o main_r.out f12_r.o main.o
/usr/bin/ld: error in f12_r.o(.eh_frame); no .eh_frame_hdr table will be created
没有一个使工具退出非0,并且最终的可执行文件仍在运行,因此我不确定它的严重程度。待办事项了解。
二进制分析
如果您不熟悉重定位,请先阅读以下内容:What do linkers do?
关键问题是部分链接如何加快链接速度。我唯一想到的就是通过解决预链接文件之间的引用。我现在专注于此。
但是,它没有按照Resolve relative relocations in partial link的要求进行操作,因此我希望它不会显着加快链接速度。
我已经通过以下方式确认了这一点
objdump -S f12.o
objdump -S f12_r.o
两者都产生相同的输出,其中包含:
int f_1_2(void) {
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
return f_2() + 1;
4: e8 00 00 00 00 callq 9 <f_1_2+0x9>
9: 83 c0 01 add $0x1,%eax
}
c: 5d pop %rbp
d: c3 retq
所以我们看到在两种情况下对f_1_2
的调用都尚未解决,因为相对偏移地址仍为0:e8 00 00 00 00
(e8
是操作码)。>
这还告诉我,GCC不能在TODO原理的最终链接之前解决函数调用,有可能迫使其解决吗?
基准
我在Replacing ld with gold - any experience?上对LD vs GOLD进行了基准测试,所以我决定重用它来查看部分链接是否会导致任何链接加速。
我用this script生成了测试对象:
./generate-objects 100 1000 100
然后我开始以最极端的链接案例开始:预链接除主文件之外的所有内容,然后对最终链接进行基准测试:
mv main.o ..
ld -o partial.o -r *.o
time gcc partial.o ../main.o
time gcc -fuse-ld=gold partial.o ../main.o
以秒为单位的挂钟时间结果如下:
No partial link Partial link
No Gold 6.15 5.756
Gold 4.06 4.457
因此:
因此,基于此实验,似乎部分链接可能根本不会加快链接时间,我只建议您尝试使用GOLD代替。
让我知道您是否可以提供一个具体的示例,其中增量链接可以显着提高速度。
案例研究:Linux内核
Linux内核是一个大型项目的一个示例,该项目曾经使用增量链接,因此也许我们可以从中学到一些东西。
此后,它已移至ar T
精简存档,如https://unix.stackexchange.com/questions/5518/what-is-the-difference-between-the-following-kernel-makefile-terms-vmlinux-vml/482978#482978
最初的提交和原理位于:a5967db9af51a84f5e181600954714a9e4c69f1f(包含在v4.9
中),其提交消息为:
ld -r is an incremental link used to create built-in.o files in build
subdirectories. It produces relocatable object files containing all
its input files, and these are are then pulled together and relocated
in the final link. Aside from the bloat, this constrains the final
link relocations, which has bitten large powerpc builds with
unresolvable relocations in the final link.
Documentation/process/changes.rst中也提到了这一点:
Binutils
--------
The build system has, as of 4.13, switched to using thin archives (`ar T`)
rather than incremental linking (`ld -r`) for built-in.a intermediate steps.
This requires binutils 2.20 or newer.
TODO:了解何时引入了增量链接,并查看是否有最小的测试用例,我们可以使用它来使它运行得更快。:https://unix.stackexchange.com/questions/491312/why-does-the-linux-kernel-build-system-use-incremental-linking-or-ar-t-thin-arch
已在Ubuntu 18.10,GCC 8.2.0,Lenovo ThinkPad P51笔记本电脑,Intel Core i7-7820HQ CPU(4核/ 8线程),2个Samsung M471A2K43BB1-CRC RAM(2个16GiB),Samsung MZVLB512HAJQ-000L7 SSD(3,000)上进行了测试MB / s)。
答案 1 :(得分:1)
ld
创建可执行文件和共享库,而不是目标文件存档(.a文件)。
ar
创建并修改目标文件存档。
-r, --relocateable
的某些(未解析的)符号并生成另一个.so
时, .so
选项很有用。