我有两个文件
main.c:
int main()
{
func();
return 0;
}
第二个文件
func.c:
#include <stdio.h>
void func()
{
printf("welcome");
}
我想知道链接器如何解析函数(func)的调用。我知道重定位是在重定位表的帮助下发生的,但我无法理解这是如何发生的
最佳答案
这就是声明的用途。考虑以下代码:
extern void func(void);
int main(void)
{
func(void);
return 0;
}
当使用gcc -c main.c
编译时,它将生成一个main.o
目标文件,其中main函数如下所示:
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 下获得了这些列表,您在您的环境中可能会得到不同的结果,但想法仍然是相同的。
关于c - 在c中,其他文件中定义的函数如何进行实际链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44693207/