CSAPP-链接(2)

158 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

书接上篇啊,这篇文章介绍对象文件的格式以及如何重定位。

对象文件格式

上面提到的三种对象文件有统一的格式,即 Executable and Linkable Format(ELF),因为,我们把它们统称为 ELF binaries,具体的文件格式如下

链接器实际上会处理一下不同的符号,对应于代码中不同写法的部分:

  • 强符号:有函数体的函数名、带初值的全局变量都是强符号。

  • 弱符号:无函数体的函数名、不带初值的全局变量为弱符号。

  • 全局符号 Global symbols:在当前模块中定义,且可以被其他代码引用的符号,例如非静态 C 函数和非静态全局变量

  • 外部符号 External symbols:同样是全局符号,但是是在其他模块(也就是其他的源代码)中定义的,但是可以在当前模块中引用

  • 本地符号 Local symbols:在当前模块中定义,只能被当前模块引用的符号,例如静态函数和静态全局变量



链接器只知道非静态的全局变量/函数,而对于局部变量一无所知。然后我们来看看局部非静态变量和局部静态变量的区别:

  • 局部非静态变量会保存在栈中
  • 局部静态变量会保存在 .bss 或 .data 中

那如果两个函数中定义了同名的静态变量会怎么样呢?首先,编译器会在 .data 部分为每一个静态变量进行定义,如果遇到同名,就会在本地的符号表中自动给出唯一的编号

而如果是不同文件的同名全局变量,则会按照强弱符号去判断,然后根据三个规则去处理

因此,得出结论:如果可能,尽量避免使用全局变量

如果一定要用的话,注意下面几点:

  • 使用静态变量
  • 定义全局变量的时候初始化
  • 注意使用 extern 关键字

重定位

重定位就是把不同可重定位对象文件拼成可执行对象文件: