我有两个文件
main.c:
int main()
{
func();
return 0;
}
和第二个文件
func.c:
#include <stdio.h>
void func()
{
printf("welcome");
}
我想知道链接器是如何解析函数调用(func)的。我知道重定位是在重定位表的帮助下发生的,但我不能理解这究竟是如何发生的
发布于 2017-06-22 15:59:11
这就是声明的作用。考虑以下代码:
extern void func(void);
int main(void)
{
func(void);
return 0;
}
当使用gcc -c main.c
进行编译时,它将生成一个main.o
对象文件,其中的主函数将如下所示:
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: e8 00 00 00 00 callq 9 <main+0x9>
9: b8 00 00 00 00 mov $0x0,%eax
e: 5d pop %rbp
f: c3 retq
并且重定位表将包含一个条目:
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000005 R_X86_64_PC32 func-0x0000000000000004
现在请注意,5
是main
中的callq立即地址的精确偏移量(这并不是特别重要的编码方式,它可能会在不同的平台上甚至在一个平台内有所不同)。
无论如何,考虑到您在C代码中放置的func
的外部声明,编译器知道它可能还没有合适的地址将函数放入callq中。
当链接器将不同的目标文件链接在一起时,它会确保所有这样的悬空地址都被成功解析。
现在回答您的特定问题-将重定位表项(外部声明)与实际符号(函数或变量定义)匹配的关键是它们的签名。特定签名产生可能匹配的这样的重定位条目和符号。不同的签名在链接方面本质上是不同的。
除了这一点,你的问题实际上是相当宽泛的。因此,请询问进一步的研究方向或使其更清楚。
编辑:还请注意,我是在x86_64 linux下获得这些清单的,您可能会在您的环境中得到不同的结果,但想法仍然是相同的。
https://stackoverflow.com/questions/44693207
复制相似问题