【读书笔记】《深入理解计算机操作系统》第七章

【1】预处理编译汇编过程

预处理器(预处理,生成ASCII码中间文件)——》编译器(编译,生成ASCII码汇编语言文件)——》汇编器(汇编,生成可重定位目标文件)——》链接器(链接,生成可执行目标文件)

 

【2】ELF格式的可重定位目标文件格式: 

 ——————

|   ELF头          |

  ——————

|   .text          | —— 已经编译程序的机器代码

  ——————

|   .rodata        | —— 只读数据

  ——————

|   .data          | —— 已经初始化的全局和静态C变量

  ——————

|   .bss           | —— 未初始化的全局和静态C变量

  ——————

|   .symtab        | —— 符号表,存放在程序中定义和引用的函数和全局变量信息。

  ——————

|   .rel.text      | ——

  ——————

|   .rel.data      | —— 被模块引用或重定位的所有全局变量的重定位信息

  ——————

|   .debug         | ——

  ——————

|   .line          | ——

  ——————

|   .strtab        | —— 

  ——————

 

【3】链接器如何解析多重定义的全局符号

编译时,汇编器想链接器输出每个全局符号,分强弱。函数和已经初始化的全局变量是强符号,未初始化的全局变量是若符号。

连接规则1:不允许有多个同名强符号;规则2:一个强符号,多个若符号,选择强符号;规则3:多个弱符号,任选一个(很容易引起程序运行错误)。

 

【4】静态链接库

静态链接库(.a)是一系列可重定位目标文件的集合,有一个头部用来描述每个成员目标文件的大小和位置。当链接器运行的时候,就只会复制 .a 中需要被用到的 .o 模块到可执行文件中。

如果库之间不是相互独立的,存在依赖关系,那么命令行方式中需要左边放依赖的库,右边放被依赖的库,也就是越独立的、越基本的库越在右边。

 

【5】重定位

分两步组成:

  • 重定位节和符号定义。比如,把所有来自输入模块的节全部合并成一个聚合节。这一步完成之后,程序中的每条指令和全局变量都有唯一的运行时内存地址了。

  • 重定位节中的符号引用。修改代码节和数据节中对每个符号的引用,使得它们指向正确的运行地址。

 

【6】可执行目标文件

可分为以下三段:只读内存段(代码段)、读/写内存段(数据段)、不加载到内存的符号表和调试信息。

 

【7】加载器

当在shell中输入 > ./a.out 的时候,shell会认为这是一个可执行目标文件,于是便调用一段称为“加载器(loader)”的代码来运行它。

 

【8】共享库(动态链接库)

  • 首先,在任何给定的文件系统中,所有引用该库的可执行目标文件共享这个.so,而不是像静态库那样把内容复制和嵌入到可执行文件中。其次,内存中,一个共享库的.text节的一个副本可以被不同的正在运行的继承共享。

  • 因此静态库更新之后,所有使用了该静态库的软件需要重新连接(因为是内嵌在可执行文件中的),而动态库更新了之后,允许应用程序在运行时连接新的共享库。

  • 位置无关代码

 

【9】linux链接器支持打桩机制

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章