c - 在c中,其他文件中定义的函数如何进行实际链接

标签 c

我有两个文件

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

现在请注意,5main 中 callq 立即地址的精确偏移量(如何编码并不特别重要,它可能在不同平台甚至内部有所不同)一个平台)。

无论如何,考虑到您在 C 代码中放置的 func 的外部声明,编译器知道它可能还没有正确的地址供函数放入 callq 中。

当链接器将不同的目标文件链接在一起时,它确保所有此类悬空地址均已成功解析。

现在回答您的特定问题 - 将重定位表条目(外部声明)与实际符号(函数或变量定义)匹配的关键是它们的签名。特定的签名会产生可能匹配的重定位条目和符号。不同的签名在联动方面有本质的不同。

除此之外,您的问题实际上相当广泛。所以请询问进一步的研究方向或者说得更清楚。

编辑:另请注意,我在 x86_64 linux 下获得了这些列表,您在您的环境中可能会得到不同的结果,但想法仍然是相同的。

关于c - 在c中,其他文件中定义的函数如何进行实际链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44693207/

相关文章:

c - 使用C语言对Atmega2560微 Controller 进行编程

c++ - 从父级重定向时,到 stderr 的 DLL 输出不起作用

c - 如何在 C 中旋转一维数组的一部分?

c - 如何在执行 : #include "file" 时保留新行

c - 代码解释 - fork, wait, execv

c++ - scanf() 的宽度说明符 - 要使用的字符长度在编译时不固定,仅在运行时确定。如何使其可变?

c - 多个 GCC 版本导致多个堆,导致崩溃?

c - 如何允许 getopt 和 get_long_opt 也处理任意参数而不发出错误?

c - 当没有语法错误时,此代码中的 if 情况不起作用

c - 符号多重定义