【问题标题】:Why is a defined function put in the relocation table为什么定义的函数放在重定位表中
【发布时间】:2020-02-21 08:37:48
【问题描述】:

我正在学习链接器在 Linux 中的工作原理。以我的代码为例:

// main.c
int printf(const char *format, ...);

void func1(int i)
{
    printf("%d\n", i);
}

int main(void)
{
    func1(1);
    return 0;
}

我执行命令gcc -c main.c,得到一个名为main.o的obj文件。

然后我执行命令objdump -r main.o,输出如下:

main.o:     file format elf64-x86-64

RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE
0000000000000011 R_X86_64_32       .rodata
000000000000001b R_X86_64_PC32     printf-0x0000000000000004
000000000000002c R_X86_64_PC32     func1-0x0000000000000004


RELOCATION RECORDS FOR [.eh_frame]:
OFFSET           TYPE              VALUE
0000000000000020 R_X86_64_PC32     .text
0000000000000040 R_X86_64_PC32     .text+0x0000000000000022

如果我是对的,objdump -r 将向我们展示 obj 文件中的所有重定位表。在这种情况下,printffunc1 都被放入重定位表中。

printf在这个C文件中没有定义,所以需要重定位,但是为什么func1也可以在重定位表中找到呢?按照我的理解,func1 应该很好定义,可以在.text 部分找到,不需要重新定位,对吧?

【问题讨论】:

  • 函数也是全局的,所以每个函数都会在 C 中获得一个重定位条目,除了你创建的那些 static,但遗憾的是我还不知道更深层次的细节。
  • @Eraklon 全局变量和函数main 不在重定位表中。
  • main 是一个入口点,它不是一个普通函数
  • @Eraklon 好的,所以我想我有点误解什么是“重定位表”。可能所有全局函数都必须在链接时重新定位。

标签: c linux compilation linker objdump


【解决方案1】:

重定位记录是确定段地址时需要调整的位置。在包括 x86 在内的许多体系结构中,可以编写与位置无关的代码,这些代码通过从一个部分中的一个位置到另一个位置的偏移量来引用对象或函数(因此当整个部分移动时偏移量不会改变),并且可以引用对象或函数通过跨节的偏移量以及一些额外的链接器帮助(因此在链接后偏移量不会改变,并且整个组合图像可能会在内存中移动)。

但是,有可能这一事实并不意味着您的构建工具正在使用与位置无关的代码。无论出于何种原因,您使用的工具和您使用的开关似乎都没有生成与位置无关的代码。因此,当有对printffunc1 的引用时,会生成对其的可重定位引用,从而产生必须由链接器或加载器调整的重定位记录。

【讨论】:

  • "在 macOS 上,默认情况下,允许链接器从代码中删除“死子部分”" 这可能是错误的。看来您必须通过明确指定“-dead_strip”来启用它。见stackoverflow.com/questions/17710024/…
  • @yuansizhu:我想我所说的“允许”可能是macOS上默认的目标文件格式是为此设置的,所以你可以启用-dead_strip开关在链接器,而无需更改有关编译或有关链接和构建的任何其他内容。但我会删除那段。
猜你喜欢
  • 1970-01-01
  • 2013-07-04
  • 1970-01-01
  • 2017-06-06
  • 2022-11-30
  • 1970-01-01
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多