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

标签 gcc linker symbols elf

研究ELF格式的结果,可以看到目标文件中有一个符号对应每个函数,对应的符号表项的值为st_size,表示大小的功能。

问题是,即使我更改了目标文件中特定函数的 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函数是很好的。链接器如何确定每个函数的大小?

最佳答案

嗯,首先我想从一句老话开始,人类更有可能找到万物理论并将量子力学与广义相对论统一起来,而不是理解链接器的优化和决策树。

回到我们的话题,我在我的机器上玩过这个,得出的结论是,对此唯一合理的解释是,链接器并不真正需要函数的大小来统一原始机器将来自不同编译单元的指令转换为单个可执行文件,让我们讨论一下原因:

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

但是,话虽如此,某些可执行格式(例如 ELF) 不会为您提供编译单元内函数机器代码的偏移量,您必须通过使用该部分在 ELF 文件中的偏移量以及符号表指向的部分中每个符号条目的大小。这只是意味着,如果您有如我之前所说,两个编译单元,每个编译单元具有三个函数,在破坏符号表中的大小条目之后,因为链接器会尝试将编译单元解析为一个可执行文件,它只会破坏它,并且您的可执行文件会很快导致您出现段错误。我在家里尝试过,这些是我收到的结果:

当使用一个函数破坏编译单元的符号表大小条目时,没有任何反应,因为整个文本部分的大小(就此而言)与该函数的大小完全相同,因此链接器没有问题解决, 当对具有三个函数的编译单元做同样的事情时,它会破坏我的可执行文件,因为链接器开始将损坏的文本偏移量从一个编译单元复制到最终的可执行文件中。

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

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

关于gcc - gcc 链接器如何获取函数的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52157899/

相关文章:

linker - 静态链接lua的问题

c++ - nm 符号值的偏移量?

linux - 链接库的 2 个冲突版本

r - 使用R提取字符串中 "+"和 "*"符号的位置

c - 递归程序中编译器的优化

linux - GCC版本是4.8,在centos中仍然出现unrecognized command -std=c++11的错误

c++ - 如何优化默认的 if-branch

从不同的驱动器号运行时 C++ DLL 失败

c++ - 剥离符号的最佳方法

c - C 的多个条件编译宏