gcc 链接器如何获取函数的大小?

How does gcc linker get the size of a function?

研究ELF格式的结果,发现目标文件中每个函数都有对应的符号,对应的符号table条目的值为st_size,即表示函数的大小。

问题是executable文件创建成功,即使我在目标文件中更改了特定函数的st_size并链接了它。下面的代码是我用的测试代码

// In main.c,

int main(void)
{
    myprintf("TEST");
}

// In log.c

#include <stdio.h>
void myprintf(const char *str)
{
    printf(str);
}

在上面的代码中,我更改了 log.o 文件中 myprintf 函数的 st_size 值,并链接了 log.o 和 main.o文件。默认情况下,st_size 值为 0x13。我通过将其更改为 0x00 对其进行了测试。我通过将它更改为 0x40 来测试它。但是 a.out 结果文件的 myprintf 功能很好。链接器如何确定每个函数的大小?

嗯,首先我想从一句老话开始,人类更有可能找到万物理论并将量子力学与广义相对论统一起来,而不是理解 link呃.

回到我们的话题,我在我的机器上玩过这个,得出的结论是,对此唯一合理的解释是,linker 并不真正需要 a 的大小函数,以便将来自不同编译单元的原始机器指令统一到单个 executable,让我们讨论原因:

假设您有两个编译单元,每个包含三个连续的函数, 为什么需要知道每个函数的大小?由特定 linker 授予该功能的固定解析虚拟地址是否足以进行重定位?真正的答案是——只需要目标文件中的一个函数到link不同编译单元的偏移就足够了,进入一个executables。

然而,话虽如此,某些 executable 格式(例如 ELF)不会为编译单元中的函数机器码提供偏移量,您必须自己计算它,方法是使用 ELF 文件中该部分的偏移量以及符号 table 指向的部分中每个符号条目的大小。这只是意味着,如果你有 正如我之前所说,两个编译单元每个具有三个函数 在破坏符号 table 中的大小条目之后,作为 linker 会尝试将编译单元解析为单个 executable,它只会破坏它,而你的 executable 会很快导致你出现段错误。我在家里尝试过,这些是我收到的结果:

当使用 一个函数 破坏符号 table 的编译单元的大小条目时,没有任何反应,因为整个文本部分的大小(就此而言)是与该函数的大小完全相同,因此 linker 可以毫无问题地解决它, 当对具有三个函数的编译单元做同样的事情时,它破坏了我的executable,因为linker开始从一个编译单元复制损坏的文本偏移量进入最终执行table.

一般来说,如果您要使用 executable 格式,它会为 linker 提供目标文件中该函数的直接偏移量,而无需按大小和部分进行计算文件中的偏移量,即使您在单个编译单元中有多个函数,您也可能最终得到相同的结果,除非 link 完成了一些合理性测试er. 在我看来 linker 需要使用大小而不是我刚才提到的大小的唯一原因可能是需要从冗余函数或变量中清除某些部分没有被其他任何人引用(link 时间优化),因此需要重新计算该编译单元内其他引用函数的重定位偏移量, 以某种方式从内部重新计算相对跳转同一个编译单元。

希望这能以某种方式回答您的问题,如果您想要对此进行更深入的演示,我将非常乐意提供帮助