微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么使用共享库时对象和库的顺序不影响链接?

如何解决为什么使用共享库时对象和库的顺序不影响链接?

我有以下源代码

  • foo.h

    void foo();
    
  • foo.cpp

    #include "foo.h"
    #include <iostream>
    
    void foo(){
        std::cout << "This is foo" << std::endl;
    }
    
  • main.cpp

    #include "foo.h"
    
    int main(){
        foo();
    
        return 0;
    }
    

然后我运行以下命令来生成 foo.cpp 的静态和共享版本:

g++ -c -fPIC foo.cpp
ar rvs libfoo.a foo.o
g++ -shared -o libfoo.so foo.o
g++ -c main.cpp

如果我尝试使用静态 libfoo.amain.o 生成可执行文件,则目标文件和库文件的顺序很重要:

g++ main.o libfoo.a -o main  # works
g++ libfoo.a main.o -o main  # fails with undefined references to `foo()`

this post中所述,顺序很重要。

但是,如果我尝试使用共享的 libfoo.somain.o 构建可执行文件,则目标文件和库文件的顺序不再重要:

g++ main.o libfoo.so -o main   # works
g++ libfoo.so main.o -o main   # also works without errors

这是否意味着当我们链接目标文件和共享库时顺序并不重要?或者这只是一个特例或一些我不知道的巧合?

以上代码和命令在以下平台上测试:

  • Linux:CentOS 7.4
  • gcc:7.3.1 或 4.8.5(均已测试)

解决方法

如本文所述,顺序很重要。

更详细的解释是here

顺序对于传统 UNIX 链接器很重要,但最近 LLD 决定打破传统,记录归档库中符号的可用性,即使它们没有立即被引用。

目前在 Linux 上可以使用三种不同的链接器:原始 BFD 链接器、Gold 链接器(大约 2008 年)和 LLD(大约 2019 年)。

使用“正确”的顺序可以成功(自然地)所有三个。

使用“错误”的顺序:g++ libfoo.a main.o 使用 BFD 和 Gold 失败,但使用 LLD 成功:

g++ libfoo.a main.o -fuse-ld=lld && echo $?
0

但是,如果我尝试使用共享的 libfoo.so 和 main.o 构建可执行文件,则目标文件和库文件的顺序不再重要

无关紧要的原因是链接器对待 .so 的方式与对待 .o 的方式类似。特别是,没有必要“拉出部分”.so——你会得到整个.so(就像你使用{{1}时会1 })

因此,当您链接 foo.o 时,此链接几乎等同于使用 g++ libfoo.so main.o,并且前一个命令中的顺序无关紧要,原因与它无关在后一个命令中无关紧要。


1使用 g++ foo.o main.o 构建并使用 -ffunction-sections

,

因为在第二种情况下不需要强符号名称解析。在 ELF 解释期间(即在您运行程序时)查找和解析共享对象中的符号。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。