为什么有些重定位是 .text + 加数而不是符号的名称 + 加数?

Why are some relocations .text + addend instead of symbol's name + addend?

为什么 ELF 文件中的某些重定位条目 symbol name + addend 而其他的 section + addend?我希望消除一些困惑并加深对 ELF 的理解。下面是我的调查。

我有一个非常简单的 C 文件,test.c:

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

static void func1(void)
{
    fprintf(stdout, "Inside func1\n");
}

// ... a couple other simple *static* functions

int main (void)
{
    func1();

    // ... call some other functions

    exit(EXIT_SUCCESS);
}

然后我将其编译成目标文件:

clang -O0 -Wall -g -c test.c -o test.o

如果使用 readelf -r test.o 查看重定位,我会看到引用我的静态函数的条目如下(该条目选自 .rela.debug_info 部分):

Offset            Info              Type         Symbol's Value    Symbol's Name + Addend
...
000000000000006f  0000000400000001  R_X86_64_64  0000000000000000 .text + b0
...

为什么这些函数被称为 section + addend 而不是 symbol name + addend?我使用 readelf -s test.o:

.symtab 中看到函数条目
Num: Value            Size Type Bind  Vis     Ndx Name
  ...
  2: 00000000000000b0 31   FUNC LOCAL DEFAULT 2   func1
  ...

此外,当我反汇编目标文件时(通过 objdump -d),我看到函数在那里并且没有优化成 main 或任何东西。

如果我 不使函数静态化 然后查看重定位,当类型为 R_X86_64_64 时,我看到的结果与以前相同,但我也查看使用符号名称加上类型为 R_X86_64_PC32 的加数的条目。例如 .rela.text:

Offset            Info              Type           Symbol's Value    Symbol's Name + Addend
...
00000000000000fe  0000001200000002  R_X86_64_PC32  0000000000000000  func1 + 1c
...

如果更多 examples/readelf 输出有帮助,请告诉我。感谢您花时间阅读本文。

Why are these functions referred to as section + addend rather than symbol name + addend?

不保证静态函数的函数名称在 link 时出现。您可以使用例如删除它们objcopy --strip-unneededobjcopy --strip-symbol,结果仍然是 link。

I see entries for the functions in the .symtab using readelf -s test.o

我相信保留它们的唯一原因是为了帮助调试,linker 根本不使用它们。但是我没有通过查看 linker 来源来验证这一点,所以没有回答这个 .

Eli Bendersky 的博客在 his blog post 中也提到了这一点。来自标题为“额外功劳:为什么需要调用重定位?”的部分:

In short, however, when ml_util_func is global, it may be overridden in the executable or another shared library, so when linking our shared library, the linker can't just assume the offset is known and hard-code it [12]. It makes all references to global symbols relocatable in order to allow the dynamic loader to decide how to resolve them. This is why declaring the function static makes a difference - since it's no longer global or exported, the linker can hard-code its offset in the code.

应该阅读完整的 post 以获得完整的上下文,但我想我会在这里分享它,因为它提供了比我的问题更好的例子,并强化了 Employed Russian 给出的解决方案。