本文已参与「新人创作礼」活动,一起开启掘金创作之路。
书接上篇啊,这篇文章介绍对象文件的格式以及如何重定位。
对象文件格式
上面提到的三种对象文件有统一的格式,即 Executable and Linkable Format(ELF),因为,我们把它们统称为 ELF binaries,具体的文件格式如下
链接器实际上会处理一下不同的符号,对应于代码中不同写法的部分:
-
强符号:有函数体的函数名、带初值的全局变量都是强符号。
-
弱符号:无函数体的函数名、不带初值的全局变量为弱符号。
-
全局符号 Global symbols:在当前模块中定义,且可以被其他代码引用的符号,例如非静态 C 函数和非静态全局变量
-
外部符号 External symbols:同样是全局符号,但是是在其他模块(也就是其他的源代码)中定义的,但是可以在当前模块中引用
-
本地符号 Local symbols:在当前模块中定义,只能被当前模块引用的符号,例如静态函数和静态全局变量
链接器只知道非静态的全局变量/函数,而对于局部变量一无所知。然后我们来看看局部非静态变量和局部静态变量的区别:
- 局部非静态变量会保存在栈中
- 局部静态变量会保存在 .bss 或 .data 中
那如果两个函数中定义了同名的静态变量会怎么样呢?首先,编译器会在 .data 部分为每一个静态变量进行定义,如果遇到同名,就会在本地的符号表中自动给出唯一的编号
而如果是不同文件的同名全局变量,则会按照强弱符号去判断,然后根据三个规则去处理
因此,得出结论:如果可能,尽量避免使用全局变量
如果一定要用的话,注意下面几点:
- 使用静态变量
- 定义全局变量的时候初始化
- 注意使用 extern 关键字
重定位
重定位就是把不同可重定位对象文件拼成可执行对象文件: