.o/.a/.so文件中的具体内容
What exactly is in a .o / .a / .so file?
我想知道编译C++程序产生的.o或.so文件中到底存储了什么。这篇文章很好地概述了编译过程和.o文件的功能,据我从这篇文章中了解,.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(25)
来优化调用f2(X)
,但它仍然需要将符号X保留在.o文件中,因为无法知道它是否会从其他.o文件使用。
这大致正确吗?.a和.so文件是一样的吗?
谢谢你的帮助!
您对对象文件的总体想法非常正确。在"指定文件中地址的表"中,我会用"偏移量"替换"地址",但这只是措辞。
.a文件只是归档文件(一种早于tar的旧格式,但作用相同)。你可以用tar文件替换.a文件,只要你教链接器解压缩它们,并只链接其中包含的所有.o文件(或多或少,有更多的逻辑可以不链接存档中不需要的对象文件,但这只是一种优化)。
.所以文件不同。与对象文件相比,它们更接近于最终的二进制文件。解析了所有符号的.so文件至少在理论上可以作为程序运行。事实上,对于PIE(独立于位置的可执行文件),共享库和程序之间的区别(至少在理论上)只是头中的几位。它们包含动态链接器如何加载库的指令(与正常程序大致相同的指令)和重新定位表,其中包含告诉动态链接器怎样解析外部符号的指令(同样,程序中也是如此)。动态库(和程序)中所有未解析的符号都是通过间接表访问的,间接表在动态链接时(程序启动或dlopen
)填充。
如果我们对此进行了大量简化,那么对象和共享库之间的区别在于,在共享库中已经做了更多的工作来不进行文本重定位(这不是严格必要和强制的,但这是一般的想法)。这意味着,在对象文件中,汇编程序只为链接器随后填充的地址生成占位符,对于共享库,地址中填充了跳转表的地址,这样库的文本就不需要更改,只需要有限的跳转表。
Btw。我说的是ELF。较旧的格式在程序和库之间有更多的差异。
您在问题中描述的内容(函数的机器代码、初始化数据和重新定位表)几乎完全是.o(对象)和.so(共享对象)文件中的内容。
.a(档案)基本上是多个.o(对象)文件聚在一起,以便在链接过程中更容易引用。("链接库")
.so(共享对象)文件包括一些额外的元数据,类似于其他.so需要链接的元数据
Windows.dll(动态链接库)文件基本上是具有不同名称的共享对象(.so)。
免责声明:这大大简化了事情,但足以满足开发人员的日常需求。
- 如何使用ndk-build.cmd构建Android.so文件
- 在C++代码中包含opencv时,使用ctypes创建.so文件
- 用于构建 cuda .so 文件(共享库)的生成文件
- 无法从 SO 文件调用 SO 文件的函数 - C++生成文件
- 如何在 C++ 的 .so 文件中包含库
- JNI,使用两个 .so 文件时出错,其中一个文件需要另一个文件
- Google Colab 看不到 .so 文件
- 如何在 Linux 中从 .so 文件打开可执行文件?
- 如何在makefile中包含tensorflow c ++".so"文件?
- 缺少 .h 文件,尽管从库文件夹链接了 .so 文件
- 如何在 CMake 超级生成中查找 dll/so 文件
- 如何用.so文件linux打包所有需要的库
- 如何调试visual studio 2017生成的C++代码.android中的SO文件和其他第三方库
- 从多个C++文件生成 .so 文件并使用它
- .so 文件无法"see"编译时使用的库
- 从 .so/.o 文件中获取 C/cpp 中的静态库列表
- 在Windows上运行Linux Makefile(.so文件)
- 如何静态链接到 POCO C++ so 文件
- C++ .so 文件中的模板化函数
- 卸载共享对象(.so 文件)在 C++ 中用 dlopen() 打开