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

Posted

技术标签:

【中文标题】gcc 链接器如何获取函数的大小?【英文标题】:How does gcc linker get the size of a function? 【发布时间】:2019-02-08 23:48:13 【问题描述】:

通过研究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 功能很好。链接器如何确定每个函数的大小?

【问题讨论】:

【参考方案1】:

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

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

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

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

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

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

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

【讨论】:

以上是关于gcc 链接器如何获取函数的大小?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 GCC 链接器命令?

GCC - 在没有链接描述文件的情况下获取自定义部分的大小

如何从 C 程序内部或使用内联汇编获取 C 函数的大小?

gcc 链接器 - 将存档中的所有目标文件映射到某个部分

如何在qt中获取视口大小

使用函数指针消除 gcc 死代码