gpt4 book ai didi

linker - 究竟什么是目标文件中的符号引用?

转载 作者:行者123 更新时间:2023-12-05 00:14:41 28 4
gpt4 key购买 nike

我正在从程序员的角度阅读计算机系统,关于链接的章节。它解释了如何使用程序 ld 在 linux x86-64 中进行链接。作者声称,为了从可重定位的目标文件构建可执行文件,链接器做了两件事:符号解析和重定位。这是他们对符号解析的简要概述:

Object files define and reference symbols, where each symbol corresponds to a function, a global variable, or a static variable (i.e., any C variable declared with the static attribute). The purpose of symbol resolution is to associate each symbol reference with exactly one symbol definition.



但他们没有阐明符号引用的含义,即使他们开始深入描述符号解析。那么在可重定位目标文件中究竟是如何引用符号的呢?

最佳答案

考虑以下来源:

static int foo() { return 42; }
static int bar() { return foo() + 1; }

extern int baz();

int main()
{
return foo() + bar() + baz();
}
之后 gcc -c foo.cobjdump -d foo.o 的输出在 x86_64 Linux 上是:
foo.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <foo>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 2a 00 00 00 mov $0x2a,%eax
9: 5d pop %rbp
a: c3 retq

000000000000000b <bar>:
b: 55 push %rbp
c: 48 89 e5 mov %rsp,%rbp
f: b8 00 00 00 00 mov $0x0,%eax
14: e8 e7 ff ff ff callq 0 <foo>
19: 83 c0 01 add $0x1,%eax
1c: 5d pop %rbp
1d: c3 retq

000000000000001e <main>:
1e: 55 push %rbp
1f: 48 89 e5 mov %rsp,%rbp
22: 53 push %rbx
23: 48 83 ec 08 sub $0x8,%rsp
27: b8 00 00 00 00 mov $0x0,%eax
2c: e8 cf ff ff ff callq 0 <foo>
31: 89 c3 mov %eax,%ebx
33: b8 00 00 00 00 mov $0x0,%eax
38: e8 ce ff ff ff callq b <bar>
3d: 01 c3 add %eax,%ebx
3f: b8 00 00 00 00 mov $0x0,%eax
44: e8 00 00 00 00 callq 49 <main+0x2b>
49: 01 d8 add %ebx,%eax
4b: 48 83 c4 08 add $0x8,%rsp
4f: 5b pop %rbx
50: 5d pop %rbp
51: c3 retq
这里有几点需要注意:
  • 注意 bar来电foo地址 0 ?objdump如何知道它是foo这被称为?
    它真的可以在地址0吗? (大多数现代系统使用 PROT_NONE 映射虚拟内存的零页,因此不会发生读取或写入访问。)
  • 请注意如何调用 baz来自 main不同于对 foo 的调用和 bar ?编译器知道 foo 在哪里和 bar是相对于调用指令本身的,但它不知道在哪里 baz将会。

  • 那么,鉴于上述信息,链接器如何将其变成合理的东西?它不能:这里没有足够的信息。
    为了使链接器能够链接到 baz 的引用(我们还没有看到)调用 baz ,它需要额外的信息。在 ELF 系统上,该附加信息被写入特殊部分 .rela.text这里,其中包含:
    $ readelf -Wr foo.o

    Relocation section '.rela.text' at offset 0x5d0 contains 1 entries:
    Offset Info Type Symbol's Value Symbol's Name + Addend
    0000000000000045 0000000b00000002 R_X86_64_PC32 0000000000000000 baz - 4
    那是本书谈到但没有定义的“引用”。它告诉链接器:如果你能找到 baz 的定义(在其他对象中),获取它的地址,并将其(实际上, &baz - 4 因为 CALL 指令相对于 CALL 之后的下一条指令)放入 .text 的字节 [45-48] foo.o的部分.
    如果没有这样的定义?链接器会产生错误:
    $ gcc foo.o
    foo.o: In function `main':
    foo.c:(.text+0x45): undefined reference to `baz'
    collect2: error: ld returned 1 exit status
    最后,回到上面的第 1 点: foo 可以吗?真的在地址0吗?
    不,但是 CALL地址 0x14 处的指令实际上并没有说 CALL 0 .它说“在调用后的下一条指令的地址处调用例程,减 25”。如果最终二进制文件中的调用指令结束于地址 0x400501 ,那么该调用的目标将是 0x4004ed ,这是 foo将结束(当链接器将 fooCALL 部分重新定位到不同的地址时, .textfoo.o 之间的距离不会改变(尽管链接器放宽了;但这是另一天的复杂话题)。

    关于linker - 究竟什么是目标文件中的符号引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46515755/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com