专栏中心

EEPW首页 > 专栏 > 静态链接全过程

静态链接全过程

发布人:电子禅石 时间:2021-04-13 来源:工程师 发布文章
写在前面

本文大部分内容翻译自Library order in static linking

静态链接顺序很重要

在gcc编译时,静态链接库链接顺序会影响链接结果和行为。
举例如下:

$ cat simplefunc.c
int func(int i) {
    return i + 21;
}

$ cat simplemain.c
int func(int);

int main(int argc, const char* argv[]) {
    return func(argc);
}

$ gcc -c simplefunc.c
$ gcc -c simplemain.c
$ gcc simplefunc.o simplemain.o
$ ./a.out ; echo $?
22

$ gcc simplemain.o simplefunc.o
$ ./a.out ; echo $?
22123456789101112131415161718192021

对于object文件,链接顺序是没有影响的,gcc会将所有的目标文件加入到链接过程中。

$ ar r libsimplefunc.a simplefunc.o
$ ranlib libsimplefunc.a
$ gcc  simplemain.o -L. -lsimplefunc
$ ./a.out ; echo $?
22

$ gcc  -L. -lsimplefunc  simplemain.o
simplemain.o: In function 'main':
simplemain.c:(.text+0x15): undefined reference to 'func'
collect2: ld returned 1 exit status12345678910

当链接器遇到libsimplefunc.a时,它仍然没有看到simplemain.o,这意味着func尚未出现在未定义的列表中。当链接器查看库时,它会看到导出func的simplefunc.o。但由于它不需要func,因此该目标文件不包含在链接中。当链接器确实到达simplemain.o并且看到func确实是必需的时,它被添加到未定义的列表中(因为它不在导出的列表中)。链接器然后到达链接的末尾并且func仍未定义。

请注意在先前的链接顺序中不会发生这种情况 - 因为simplemain.o首先出现,func在链接器看到库之前位于未定义的列表中,因此导出它的目标文件确实包含在内。

从上面的例子中可以得出:静态链接时,链接库顺序会影响链接结果。如果对象或库AA需要来自库BB的符号,则AA应该在链接器的命令行调用中位于库BB 之前。
下面一节,我们将从原理上来了解链接库的顺序是如何影响链接结果的!

静态链接过程

程序静态链接的过程如下,举例说明(翻译Library order in static linking的The linking process一节)

$ gcc main.o -L/some/lib/dir -lfoo -lbar -lbaz1

注:库指library,对象指object,此处要注意区分。
1 当链接时,链接器维护两个列表:
1.1 到目前为止遇到的所有目标文件(object)和库(library)导出的符号列表,记做exports(导出的符号)
1.2 遇到的目标文件(object)和库(library)请求导入但尚未找到的未定义符号列表,即undefined reference,记做imports(待导入的符号)

2 当链接器遇到新的目标文件(object)时,
2.1 它导出的符号会被添加到上面提到的导出符号列表中。 如果任何符号位于未定义列表中,则会从那里删除它,因为现在已找到它。 如果导出列表中已有任何符号,则会出现“多重定义”错误:两个不同的对象导出相同的符号,链接器会报错
2.2 它导入的符号被添加到未定义符号列表中,除非它们可以在导出符号列表exports中找到。

3 当链接器遇到新时,事情会更有趣。 链接器遍历库中的所有目标文件(object),库是object打包成的一个整体。 对于每一个,它首先查看它导出的符号
3.1 如果它导出的任何符号位于未定义列表中,则该对象将添加到链接中,并执行下一步。 否则,将跳过下一步。
3.2 如果目标文件(object)已添加到链接中,则按上述方式对其进行处理 - 未定义和导出的符号将添加到符号表中。
3.3 如果库中的任何目标文件(object)已包含在链接中,则会再次重新扫描整个库,因为这个目标文件可能依赖库中的其他目标文件。

链接器完成后,它会查看符号表。 如果任何符号保留在未定义的列表中,链接器将抛出“未定义的引用”错误。
在链接器查看库之后,它将不会再次查看它,即链接器只查看库一次。 即使它导出一些后来的库可能需要的符号。 链接器返回重新扫描对象的唯一时间它已经在单个库中发生 - 如上所述,一旦某个库中的对象被带入链接,同一库中的所有其他对象将被重新扫描。 传递给链接器的标志可以调整这个过程 - 再次,我们稍后会看到一些例子。
另外,检查库时,如果不提供符号表所需的符号,则可以将其中的目标文件排除在链接之外。 这是静态链接的一个非常重要的特性。 我之前提到过的C库大量使用了这个功能,主要是将自身分解为每个函数的一个对象。 因此,例如,如果您的代码使用的唯一C标准库函数是strlen,则只有strlen.o将从libc.a进入链接 - 并且您的可执行文件将非常小。

建议
  1. 在项目开发过层中尽量让lib是垂直关系,避免循环依赖,越是底层的库,越是往后面写

  2. 若存在循环依赖的情况,可用以下方法解决

    Xlinker "-("-la -lb  -lc"-)" OR--start-group -la -lb lc -Wl,--end-group
    • 1

    • 2

    • 3

参考文档

https://blog.csdn.net/caikunbob/article/details/85550000

专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们

关键词:

相关推荐

KDN-K3系列PLC用户手册

荣耀Magic 8系列搭载艾迈斯欧司朗新一代HDR闪烁检测传感器,打造专业级环境光检测新体验

三星 LPDDR6 内存规格揭晓:10.7nm 速度为 12Gbps;据报道,着眼于 14 Gbps

网络与存储 2025-11-13

知识产权合作升级:艾迈斯欧司朗与日亚签署广泛专利交叉许可协议

艾迈斯欧司朗获东软医疗“最佳成本控制奖”,助力精准医疗可持续发展

MSP430 介绍 (二)

视频 2010-03-15

MSP430 单片机外围模块 - LCD [利尔达]

视频 2010-03-15

中国 A 股芯片公司在 2025 年第一季度至第三季度向研发投入增加

嵌入式系统 2025-11-13

AMD 的 AI 芯片为数据中心收入提供动力:预计 100 年复合年增长率为 60%

IsaGraf快速入门(OPEN_PLC&泓格专用)

资源下载 2007-02-09

利用低ESR晶体实现物联网超低功耗时序

据报道,中芯国际在中国面临不断扩大的人工智能芯片需求之际增加产量

智能计算 2025-11-13

LG

资源下载 2007-02-09

MSP430 介绍 (一)

视频 2010-03-15

HOLLiAS_LEC G3 PLC培训手册

中芯国际在中国面临不断扩大的人工智能芯片紧缩之际增加产量

OLED 屏下光谱颜色传感技术,实现逼真色彩显示

村田顽童——一年级学生篇

视频 2010-03-15

MSP430 介绍 (三)

视频 2010-03-15

GPPW8

更多 培训课堂
更多 焦点
更多 视频

技术专区