根据编译器标志和源代码,编译器可能会在编译后的模块(.o文件)中添加对齐字节。这些字节随后会在最终的二进制文件中结束,例如,请参见this SO question。
以下三个选项在理论上可以对齐.o文件中的函数:
(1)函数前的对齐字节:
NOP(s)
function_start
...
function_end
(2)函数内的对齐字节
function_start
...
NOP(s)
...
function_end
(3)函数后的对齐字节
function_start
...
function_end
NOP(s)
我看过(2)和(3)。
- 是不是可以放心地假定(1)不做呢?
- 在(1)或(3)的情况下,当链接/合并.o文件以创建最终的二进制文件时,链接器是否可能添加或删除对齐字节?链接时间优化是否是一个特殊情况?
2条答案
按热度按时间wsewodh21#
编译器执行(1)。为函数发出的汇编代码的形式为
对于每个目标文件中的第一个函数,这没有任何影响。对于后续函数,它可能会有影响。当您使用
objdump
转储代码时,您会发现该工具不知道函数何时结束。它只知道函数何时开始。但是函数在发出用于对齐的填充之后开始,因此它最终看起来像是填充“属于”前一个函数。当它真的为下面的函数发出时。当您将多个目标文件链接在一起时,链接器会添加额外的填充,以使它粘贴在一起的每个部分达到其所需的对齐。此对齐要求是其中给定的最高值
.align
指令的值(即,即使是第一个函数的初始.align
指令也很重要)。t9eec4r02#
是不是可以放心地假定(1)不做呢?
通常,目标文件包含一些信息,即段应具有一些对齐(例如,对齐到16字节)。
然后,链接器将在节之间添加字节(可能是
NOP
或0x00
),以确保节正确对齐。通过插入额外的
NOP
,您无法实现比截面对齐“更大”的对齐:如果区段对齐16个字节,您就无法借由插入NOP
s来将某些程式码对齐32个字节。因此,区段中的第一个字节将永远具有可能的“最佳”对齐,而且...
是不是可以放心地假定(1)不做呢?
...只有当您明确希望函数“未对齐”时(例如,如果函数应位于
8*N+5
形式的地址,以确保函数中间的某条指令位于8对齐的地址),才有意义在段中的第一个函数前添加NOP
s。然而,在这种情况下,将允许编译器在函数之前添加对齐字节。
(3)函数后的对齐字节
同一节中两个函数之间的对齐字节是有意义的。
仅当对节的大小有限制时(例如,节大小必须是16的倍数或类似值),节末尾的对齐字节才有意义。
链接器是否可能在链接时添加...对齐字节
通常,链接器甚至必须在节之间添加对齐字节,但不是在节内部。
链接器是否可能在链接时删除对齐字节
通常,链接器不区分对齐字节和“有用”字节。因此,它不能删除对齐字节。