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

问题描述 投票:2回答:1

作为研究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文件中st_size函数的myprintf值,并链接了log.o和main.o文件。在默认情况下,st_size值为0x13。我通过将其更改为0x00来测试它。我通过将其更改为0x40来测试它。但是a.out结果文件的myprintf函数很好。链接器如何确定每个函数的大小?

gcc linker symbols elf
1个回答
1
投票

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

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

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

但是,有了这样的说法,一些可执行的格式(例如ELF)不会为编译单元中的函数机器代码提供偏移量,并且您必须通过确实使用ELF文件中该部分的偏移量来自己计算它。符号表指向的部分中每个符号条目的大小。这简单的意思是,如果你像我之前所说的那样,两个编译单元在破坏符号表中的大小条目之后各有三个函数,因为链接器会尝试将编译单元解析为单个可执行文件,它只会破坏它,你的可执行文件会迅速导致你的段错误。我在家里试过这个,这些是我收到的结果:

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

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

希望以某种方式回答你的问题,如果你想更深入地证明这一点,我会非常乐意提供帮助

© www.soinside.com 2019 - 2024. All rights reserved.