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

Pie*_*yts 3 c c++ compilation object-files archive-file

我想知道在编译C++程序时,.o或.so文件中存储的确切内容. 这篇文章给出了编译过程的一个相当不错的概述,并在其.o文件的功能,而据我了解,从这个帖子,u和.so文件只是多个.o文件合并成一个单一的文件,以静态(.a)或动态(.so)方式链接.

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

void f();
void f2(int);

const int X = 25;

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

void h() {
  g();
}
Run Code Online (Sandbox Code Playgroud)

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

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

然后一个程序nm会列出两个表中的所有符号名称.

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

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

谢谢你的帮助!

Art*_*Art 5

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

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

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

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

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

  • @PieterNuyts共享库包含大量未解析的符号,通常要从其他共享库(通常是libc)解析.没有什么能阻止您创建用于解析主程序中的符号的共享库. (2认同)