返回介绍

4. 编译链接

发布于 2024-10-12 21:58:07 字数 4549 浏览 0 评论 0 收藏 0

编译器将面向人类的高级语言翻译成面向机器的低级机器代码。

编译四个步骤:

  • 预处理(prepressing):处理源码和相关头文件。(gcc -E, .i)
  • 编译(compilation):作词法、语法、语义分析,生成汇编文件。(-S, .s)
  • 汇编(assembly):将汇编代码转换成可执行机器代码。(as, gcc -c, .o)
  • 链接(linking):组装所有目标文件,重定位地址。(ld)

词法分析是用扫描器(scanner, lex)将源码分割成一系列记号(token,关键字、标识符、字面量和操作符等),再以语法分析器(grammaer parser, yacc)分析记号生成以表达式(expression)为节点的语法树(syntax tree)。

语义包括编译期可确定的静态语义(static semantic),以及运行期的动态语义(dynamic semantic)。语义分析器(semantic analyzer)检查语句合法性,对语法树标识类型,插入隐式转换节点。接下来,编译器前端的源代码优化器(source code optimizer)会将语法树转换成中间代码(intermediate code)。

中间代码使得编译器分成前端和后端。前端负责生成机器无关的中间代码,后端将中间代码转换为机器代码。后端包括机器代码生成器(code generator)和目标代码优化器(target code optimizer)。

链接器要完成符号解析(symbol resolution)和重定位(relocation)。符号解析是将符号引用和符号定义联系起来。重定位是将符号与存储器位置联系起来,并修改所有对该符号的引用,使其指向具体地址。

目标文件类型:

  • 可重定位目标文件(.o)。
  • 可执行目标文件(exec)。
  • 共享目标文件(.so)。

目标文件格式包括早期通用格式 COFF,以及 Windows/PE、OSX/Mach-O 和 Unix-like/ELF。

符号和符号表

每个目标文件都有一个符号表,其中包括:

  • 当前模块内,可被外部引用的全局符号,比如函数和全局变量(非 static)。
  • 只被当前模块定义和引用的本地符号,比如 static 函数和变量,不能被外部引用。
  • 其他模块定义,被当前模块所引用的全局符号(external)。

在 .symtab 内存储了程序定义和引用的函数和全局变量信息,其中不包含局部变量。在 .strtab 内存储 .symtab 和 .debug 字符串信息。ABS 表示无需链接器处理。

UND 表示在本地引用的外部全局符号。COM 表示未初始化,比如分配在 .bss 的全局变量。OBJECT 变量。

$ readelf -s main.o

Symbol table '.symtab' contains 14 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS main.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    9 
     9: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
    10: 0000000000000004     4 OBJECT  GLOBAL DEFAULT  COM x
    11: 0000000000000000    38 FUNC    GLOBAL DEFAULT    1 main
    12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    13: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND puts
$ readelf -p .strtab main.o

String dump of section '.strtab':
  [     1]  main.c
  [     8]  x
  [     a]  main
  [     f]  _GLOBAL_OFFSET_TABLE_
  [    25]  puts

C 可用 static 隐藏函数和全局变量,类似其他语言的 private 声明。和全局变量类似,static 局部变量也在 .data/.bss 存储。默认是 extern,表示可被其他模块引用。

符号解析是将符号引用和它所在模块中的定义联系起来。

  • 如果是本地符号,那么直接查找本地符号表。
  • 全局符号引用,由链接器在组装时查找。

完成符号解析后,链接器将合并模块,并为每个符号分配运行时地址。

  • 合并不同模块的相同段,如 .data、.text。
  • 修改代码和数据中对符号的引用,使其指向正确的地址。

静态链接

可将多个目标模块(.o)打包成一个独立文件(.a),称做静态库(static library)。静态库可像普通模块那样作为链接器的输入。链接器只获取静态库中被引用的目标模块。

$ ar rs mylib.a lib1.o lib2.o   # 创建静态库。
$ gcc -static      # 全静态链接。

动态链接

相比静态库内嵌方式,动态链接库(shared library, .so)以独立文件的方式链接。在运行时由动态链接器(dynamic linker, ld-linux.so)执行动态链接,可被加载到任意位置。

$ ldd ./test
	linux-vdso.so.1 (0x00007ffce838d000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9ea9e07000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f9eaa000000)

编译参数 -fPIC 模式指示生成位置无关代码,以便实现动态链接。链接参数 -shared 指示创建一个动态库。

$ gcc -fPIC -shared -o mylib.so lib1.c lib2.c

位置无关代码(position-independent code, PIC)。

程序运行时,动态链接器在 全局偏移表 (global offset table, GOT)中存储共享库符号重地位地址。调用共享库函数时,编译器使用延迟绑定(lazy binding),将地址重定位推迟到目标函数第一次被调用时。延迟绑定使用 过程链接表 (procedure linkage table, PLT),每个被调用共享库函数都有自己的记录,内容是一段从 GOT 查找地址的可执行代码。

GOT 是 .data 的一部分,PLT 是 .text 的一部分。

第一次调用时,GOT 内没有目标地址,重定位并用真实地址修改 GOT 记录。

第二次调用是,PLT 直接从 GOT 返回地址并跳转。

                      +-----+             +-----+         +------+
  call puts@plt ----> | PLT | ----------> | GOT | ------> | puts |
                      +-----+             +-----+         +------+
                       .text               .data            libc
                       

PIE(position-independent executable)是一种防护技术。每次程序加载时,随机分配 .text、.data、.bss 等地址。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文