.o / .a / .so文件究竟是什么?

时间:2015-07-02 08:33:58

标签: c++ c compilation object-files archive-file

我想知道在编译C ++程序时,.o或.so文件中究竟存储了什么。 This post非常好地概述了编译过程和.o文件的功能,据我所知,this post,。a和.so文件只是多个.o文件合并为一个以静态(.a)或动态(.so)方式链接的文件。

但我想检查一下我是否正确理解了这样一个文件中存储的内容。编译以下代码后

void f();
void f2(int);

const int X = 25;

void g() {
  f();
  f2(X);
}

void h() {
  g();
}

我希望在.o文件中找到以下项目:

  • g()的机器代码,包含调用f()f2(int)的占位符地址。
  • h()的机器代码,没有占位符
  • X的机器代码,只是数字25
  • 某种表格,用于指定文件中的哪些地址可以找到符号g()h()X
  • 另一个表格,用于指定哪些占位符用于引用未定义的符号f()f2(int),这些符号必须在链接期间解析。

然后像nm这样的程序会列出两个表中的所有符号名称。

我认为编译器可以通过调用f2(X)来优化调用f2(25),但它仍然需要将符号X保留在.o文件中,因为无法知道它是否存在将从不同的.o文件中使用。

这会是正确的吗? .a和.so文件是否相同?

感谢您的帮助!

2 个答案:

答案 0 :(得分:5)

对于目标文件的一般想法,你是非常正确的。在“指定文件中的哪些地址的表”中,我将“地址”替换为“偏移”,但这只是措辞。

.a文件只是简单的归档(一种早于tar的旧格式,但做同样的事情)。你可以用tar文件替换.a文件,只要你教导链接器解压缩它们并且只链接它们中包含的所有.o文件(或多或少,有一些逻辑不能链接到目标文件中)存档不是必需的,但这只是一种优化。)

.so文件不同。它们比目标文件更接近最终二进制文件。解析了所有符号的.so文件至少在理论上可以作为程序运行。事实上,对于PIE(位置无关的可执行文件),共享库和程序之间的差异(至少在理论上)只是标题中的几个位。它们包含动态链接器如何加载库的指令(或多或少与正常程序相同的指令)和包含指令的重定位表,告诉动态链接器如何解析外部符号(同样,在程序中) 。动态库(和程序)中的所有未解析符号都是通过间接表访问的,这些表在动态链接时填充(程序启动或dlopen)。

如果我们对此进行了简化,那么对象和共享库之间的区别在于,共享库中已经完成了更多的工作而不进行文本重定位(这不是严格必要和强制执行的,但这是一般的想法)。这意味着在目标文件中,汇编程序只生成了链接器随后填充的地址的占位符,对于共享库,地址填充了跳转表的地址,以便不需要更改库的文本,只有有限的跳转表。

顺便说一下。我在说ELF。较旧的格式在程序和库之间存在更多差异。

答案 1 :(得分:1)

您在问题中描述的内容(函数,初始化数据和重定位表的机器代码)几乎就是.o(对象)和.so(共享对象)文件。

.a(档案)基本上是多个.o(对象)文件聚集在一起,以便在链接期间更容易参考。 (“链接库”)

.so(共享对象)文件包含一些额外的元数据,例如其他 .so需要链接到的。(xyz.so可能会引用一些驻留在abc.so中的函数,以及abc.so需要链接的信息,以及可选地找到abc.so(RPATH)的路径,需要在xyz.so中编码。)

Windows .dll(动态链接库)文件基本上是具有不同名称的共享对象(.so)。

免责声明:这显着简化了事情,但足以接近“The Truth(tm)”以满足日常开发人员的需求。