本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一个c文件是如何运行的?它的内部经过了什么?这正是这篇文章的主题。
代码的旅程
C语言代码要想最终成为机器可执行的程序,都会经过以下处理:
- 预处理器:将 C 语言代码(da.c)转化成 da.i 文件(gcc –E)
- 编译器:C 语言代码(da.c, wang.c)经过编译器的处理(gcc -0g -S)成为汇编代码(da.s, wang.s)
- 汇编器:汇编代码(da.s, wang.s)经过汇编器的处理(gcc 或 as)成为对象程序(da.o, wang.o)
- 链接器:对象程序(da.o, wang.o)以及所需静态库(lib.a)经过链接器的处理(gcc 或 ld)最终成为计算机可执行的程序
- 加载器:将可执行程序加载到内存并进行执行,loader 和 ld-linux.so
本章的学习重点就是链接器部分:
链接基本知识
连接器主要负责做两件事情
- 符号解析 Symbol resolution
我们在代码中会声明变量及函数,之后会调用变量及函数,所有的符号声明都会被保存在符号表(symbol table)中,而符号表会保存在由汇编器生成的 object 文件中(也就是 .o 对象文件)。符号表实际上是一个结构体数组,每一个元素包含名称、大小和符号的位置。
所谓的对象文件(Object File)实际上是一个统称,具体来说有以下三种形式:
- 共享目标文件 Shared object file (.so file)
- 可重定位目标文件 Relocatable object file (.o file)
- 可执行目标文件 Executable object file (a.out file)
在 symbol resolution 阶段,链接器会给每个符号应用一个唯一的符号定义,用作寻找对应符号的标志。
- 重定位 Relocation
这一步所做的工作是把原先分开的代码和数据片段汇总成一个文件,会把原先在 .o 文件中的相对位置转换成在可执行程序的绝对位置,并且据此更新对应的引用符号(才能找到新的位置)