c语言so文件是什么文件,关于c ++:.o / .a / .so文件中到底是什么?

我想知道究竟是什么存储在编译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文件是否相同?

谢谢你的帮助!

这些文件中有位(0,1)...;)[我无法抗拒,我100%肯定某个地方有"好"答案,有人会将此标记为重复)

与C相对,在C ++中,除非用extern明确发布,否则所有用const注释的名称空间级别的对象都具有内部链接。因此,根据您的情况,C ++编译器有权优化X。关于您的问题,我建议尝试使用objdump和readelf实用程序,这些实用程序可以浏览.o,.a和.so文件的内容。

@Mats:告诉我一个没有位的文件:-) [我知道,一个空文件...]

@Andrey:谢谢!我不知道。这是否也适用于内联函数?

内联函数的工作方式有所不同。 C ++标准规定,使用内联函数的每个编译单元(CU)都必须定义它。因此,如果在CU中未使用内联函数,则编译器有权(但没有义务)将其丢弃。但是,GCC具有某些实用程序来减轻代码膨胀。

静态类变量呢?我想默认情况下不能将它们丢弃?

他们当然不能。无法声明无法从另一个编译单元访问类的静态数据成员。

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

.a文件只是归档文件(一种旧格式,早于tar,但功能相同)。您可以将tar文件替换为.a文件,只要您告诉链接程序解压缩它们,然后直接链接其中包含的所有.o文件即可(或多或少,有一些逻辑可以不与目标文件中的目标文件链接存档,但这不是一个最佳选择)。

.so文件是不同的。它们比目标文件更接近最终二进制文件。解析了所有符号的.so文件至少可以在理论上作为程序运行。实际上,使用PIE(与位置无关的可执行文件),共享库和程序之间的区别(至少在理论上)仅是头文件中的几位。它们包含有关动态链接程序如何加载库的指令(与普通程序大致相同的指令)和重定位表,其中包含了指示动态链接程序如何解析外部符号的指令(同样,程序中的相同) 。动态库(和程序)中所有未解析的符号都通过在动态链接时(程序启动或dlopen)填充的间接表进行访问。

如果我们将其简化很多,则对象和共享库之间的区别在于,在共享库中已经进行了更多工作以不进行文本重定位(这不是严格必要的,也不是强制执行的,但这是总的思路)。这意味着,在目标文件中,汇编器仅生成了链接器随后要填充的地址的占位符,对于共享库,地址中填充了用于跳转表的地址,因此不需要更改库的文本,只有有限的跳转表。

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

.so不能包含main()函数,可以吗?鉴于main()是可执行文件的入口点,也许这也值得一提,还是我误会了?

因此,如果.so文件包含未解析的符号,则可能出现问题了吗?

@MxMller您弄错了。我已经看到很多使用main的共享库。 main不是可执行文件的入口点。入口点只是标题中的地址(或偏移量)。在正常程序中,要执行main,设置stdio,设置环境变量,解析共享库等之前,有很多代码正在运行。即使最简单的程序也应具有至少执行以下操作的入口点:exit(main(argc, argv));从main返回退出。

@PieterNuyts共享库包含许多未解析的符号,通常需要从其他共享库(通常为libc)解析。同样,您也无法创建共享库来解析主程序中的符号。

有趣。这就是为什么我喜欢这个网站,需要学习很多东西,很多伟大的人回答您的问题。感谢您的见解!

@MxMller我做了一件事情来验证我是否记错了(也就是说谎):github.com/art4711/shared_main

谢谢。同时,我弄清楚了我的错误是什么。我以为我的源代码必须包含一个main,但事实是,只有生成的可执行文件必须包含一个main(无论它来自何处)。

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

.a(档案)基本上是多个.o(目标)文件,这些文件捆在一起,以便在链接期间进行参考。 ("链接库")

.so(共享库)文件包含一些其他元数据,例如需要链接其他.so的元数据。(xyz.so可能引用驻留在abc.so中的某些函数,而abc.so的信息则需要链接,以及可选的查找abc.so的路径(RPATH),需要在xyz.so中进行编码。)

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

免责声明:这大大简化了事情,但与"真相(tm)"足够接近,可以满足日常开发人员的需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值