《程序员的自我修养-链接装载与库》

不可视境界线最后变动于:2022年10月6日 下午

1-2

没啥特别的

3 ELF

COFF 是由 Unix System V Release 3 首先提出并且使用的格式规范,后来微软公司基 于 COFF 格式,制定了 PE 格式标准,并将其用于当时的 Windows NT 系统。 System V Release 4 在 COFF 的基础上引入了 ELF 格式,目前流行的 Linux 系统也以 ELF 作 为基本可执行文件格式。这也就是为什么目前 PE 和 ELF 如此相似的主要原因

段 section:

  • 另外值得一提的是,有时候编译器会把宁符串常量放到 “.data” 段,而不会单独放在”.rodata” 段。
  • ” .note.GNU-stack” 段虽然有 “ CONTENTS”, 但它的长度为 0, 这是个很古怪的段
  • 应用程序也可以使用一些非系统保留的名字作为段名 。 比如我们可以在 ELF 文件中插入一个 “music” 的 段,里面存放了一首 MP3 音乐,节 ELF 文件运行起来以后可以读取这个段播放这首 MP3. 但是应用程序自定义的段名不能使用“.”作为前缀,否则容易跟系统保留段名冲突。
  • 比如一个 ELF 文件中可能有两个或两个以上叫做 “.text” 的段
  • 自定义段
    • _attribute_( (section( "FOO"))) int global= 42;

ELF:

  • ELF 段表的这个数组的第一个元素是无效的段描述符,它的类型为 ‘,NULL”, 除此之外每个段 描述符都对应一个段
  • 主要决定段的属性的是段的类型 (sb_type) 和段的标志位 (sh_flags) P100
  • 对于变量和函数来说,符号值就是它们的地址
  • P108 符号表详细介绍
    • 链接器特殊符号! 用extern声明. 在ucore中也见过.

编译器行为:

  • 符号修饰与函数签名, 加不加下划线的区别.
    • P111 C++函数签名.
    • binutils中c++filt命令解析函数签名, 真行
    • extern “C”的作用!
    • 确实是涨知识.
  • 强弱引用:
    • 通过使用 "_attribute_((weakref))" 这个扩展关键字来声明对一 个外部函数的引用为弱引用
    • 这种弱符号和弱引用对于库来说十分有用,比如库中定义的弱符号可以被用户定义的强 符号所覆盖,从而使得程序可以使用自定义版本的库函数;或者程序可以对某些扩展功能模块的引用定义为弱引用,当我们将扩展模块与程序链接在一起时,功能模块就可以正常使用; 如果我们去掉了某些功能模块,那么程序也可以正常链接,只是缺少了相应的功能,这使得程序的功能更加容易裁剪和组合。
  • DWARF ( Debug With Arbitrary Record Format)

静态链接

对于多个输入目标文件,链接器将相似段合并

整个链接过程分两步:

  • 扫描所有的输入目标文件,并且获得它们的各个段的长度、 属性和位置,并且将输入目标文件中的符号表中所有的符号定义和符号引用收集起来,统— 放到一个全局符号表。
  • 使用上面第一步中收集到的所有信息,读取输入文件中段的数据、重定位信息,井且进行符号解析与重定位、调整代码中的地址等

也就是:

  • 链接器按照前面介绍的空间分配方法进行分配,这时候输入文 件中的各个段在链接后的虚拟地址就已经确定了
  • 当前面一步完成之后,链接器开始计算各个符号的虚拟地址

我现在的知识似乎还停留在静态链接的框架里面. 还是继续看吧, 书里也有动态链接的细节. 在CSAPP里也没提及.

4.3 COMMON 块

  • COMMON 类型的链接规则是针对符号都是弱符号的情况, 如果其中有一个符号 为强符号,那么最终输出结果中的符号所占空间与强符号相同, 如果有弱符号的大小大于强符号的大小, 那么连接器会给出警告.
  • 直接导致需要COMMON 机制的原因是编译器和链接器允许不同类型的弱符号存在,但最本质的原因还是 链接器不支持符号类型,即链接器无法判断各个符号的类型是否一致。
  • 编译器在链接前无法为弱符号在BSS 段分配空间,因为所须要空间的大小未知。如果只使用gcc -c的话会发现未初始化的全局变量没有出现在bss段. 但是链接器在链接过程中可以确定弱符号的大小.
  • -fno-common or __attribute__((nocommon)); 禁用common处理.
  • 一旦一个未初始化的全局变蜇不是以 COMMON 块的形式存在,那么它就相当于一个强符号,如果其他目标文件中还有同一个变量的强符号定义,链接时就会发生符号重复定义错误。

4.4 C++相关问题 P135

4.4.2 全局构造与析构

  • Linux 系统下一般程序的入口是 “_start”. 这个函数是 Linux 系统库 (Glibc) 的一部分
  • 利用.init和.fini段的特性, C++的全局构造和析构函数就由此实现

4.4.3 C++与 ABI

  • 其中我们把符号修饰 标准、变量内存布局、函数调用方式等这些跟可执行代码二进制兼容性相关的内容称为 ABI (Application Binary Interface).
  • 影响ABI的因素. P139

静态库链接:

  • VIsual C++也提供了与 Lmux下的ar类似的工具,叫lib.exe,这个程序可以用来创建,提取,列举lib文件中的内容。
  • P143 链接的一个示例过程

4.6.2 最“小"的程序

做着做着就做到思维导图上去了…