编译过程中的链接实际上做了什么?

时间:2016-06-13 11:00:43

标签: c gcc compilation linker

据我所知,GCC编译器在编译C程序时执行了四个步骤。

  1. 预处理 - 带有宏的C代码(* .c)到没有宏的C代码(* .c)
  2. 编译 - C代码(* .c)到汇编语言(* .s)
  3. 汇编 - 汇编语言(* .s)到目标代码(* .o)
  4. 链接 - 目标代码(* .o)到可执行文件(*)
  5. 前三个步骤对我来说非常有意义,但我仍然对链接实际上做了什么感到困惑。

    在第三步之后,为什么我不能运行* .o文件?此时,我的C代码现在是对象/机器/字节代码,可以由CPU直接解释。然而,当我将* .o文件设置为可执行文件并尝试运行它时,我收到此错误:

    bash: ./helloworld.o: cannot execute binary file: Exec format error

    为什么会出现此错误?如果我有一个只有一个C文件的小C程序(例如一个hello world程序),那么在我看来,链接没有任何意义,因为没有任何东西可以链接。那么编译过程中的链接实际上是做什么的呢?

    提前感谢您的回复。

3 个答案:

答案 0 :(得分:2)

  

如果我有一个小C程序(例如一个hello world程序)

即使你的helloworld程序也使用#inlude<stdio.h>,不是吗?这意味着你正在使用一个库,并且链接步骤是为了组合必要的目标代码(这里是库代码)来为你创建二进制文件。

有关链接步骤的详细说明(并与编译比较) - 请参阅此question

答案 1 :(得分:2)

粗略解释的链接是:

  • 从每个目标文件中查找所有匹配的段,并将它们连接在一起。这样我们最终得到一个大的.code,一个.data,一个.bss等。
  • 解析所有使用的符号。许多符号是本地的,因此可以立即解决。将在请求链接的库中搜索未解析的符号。完成后,结果将是符号表/链接映射。
  • 制作一个实际可执行的文件。在Linux上,通常只会发生可执行文件,库和目标文件都是ELF格式。并非所有平台都适用。

答案 2 :(得分:1)

简单的答案是.o可执行文件用于不同的目的并具有不同的格式。

如果您需要完整的答案,则需要阅读平台二进制格式的必要文档。

在Linux上,这将是here。本文档将描述中间格式与最终可执行格式之间的区别。

另外,Linux内核模块加载器直接使用.o(或更确切地说是.ko)文件。