计算机系统课程 笔记总结 CSAPP第七章 链接(7.1-7.13)

目录

7.1 编译器驱动程序

7.2 静态链接

7.3 目标文件

7.4 可重定位目标文件

7.5 符号和符号表

7.6 符号解析

7.6.1 链接器如何歇息多重定义的全局符号

7.6.2 与静态库链接

7.7 重定位

7.7.1 重定位条目

7.7.2 重定位符号引用

7.7.2.1 相对引用

7.7.2.2 绝对引用

7.8 可执行目标文件

7.9 加载可执行目标文件

7.10 动态链接共享库

7.11 从应用程序中加载和链接共享库 

7.12 位置无关代码

7.13 库打桩机制


 

7.1 编译器驱动程序

  • 使用编译器驱动程序compiler driver进行程序的翻译和链接:
    • linux> gcc -Og -o prog main.c sum.c
    • linux> ./prog
  • 加载器loader
    • 将可执行文件prog中的代码和数据复制到内存
    • 然后将控制转移到这个程序的开头

 


7.2 静态链接

为什么用链接器?

  • 模块化
    • 程序可以编写为一个较小的源文件的集合,而不是一个整体巨大的一团.
    • 可以构建公共函数库 (稍后详述)
      • 例如, 数学运算库, 标准C库
  • 效率
    • 时间: 分开编译
      • 更改一个源文件,编译,然后重新链接.
      • 不需要重新编译其他源文件.
    • 空间: 库
      • 可以将公共函数聚合为单个文件...
      • 然而,可执行文件和运行内存映像只包含它们实际使用的函数的代码.

 

  • 静态链接器 static linker
    • 输入:一组可重定位目标文件和命令行参数
      • 各种不同的代码
      • 数据节 section,连续的字节序列
    • 输出:一个完全链接的、可以加载和运行的可执行目标文件作为输出
    • 例:Linux LD
  • 任务
    • 符号解析 symbol resolution
      • 目标文件定义和引用:符号、函数、全局变量、静态变量(static)
      • 链接器将每个符号引用正好与一个符号定义关联起来
    • 重定位 relocation
      • 将多个单独的代码节和数据节合并为单个节
      • 将符号从它们的在.o文件的相对位置重新定位到可执行文件的最终绝对内存位置
      • 更新所有对这些符号的引用来反映它们的新位置

 

 


7.3 目标文件

  • 可重定位目标文件(.o 文件)
    • 包含与其他可重定位目标文件相结合的代码和数据,以形成可执行的目标文件.
    • 每一个.o文件是由一个源(.c)文件生成的
  • 可执行目标文件(a.out 文件)
    • 包含可以直接复制到内存并执行的代码和数据.
  • 共享目标文件(.so 文件)
    • 特殊类型的可重定位目标文件,在其他的加载时或运行时,它可以被动态加载到内存,并被动态链接
    • 在Windows中称为动态链接库.DLL

 

  • 目标模块就是一个字节序列
  • 目标文件就是一个以文件形式存放再磁盘中的目标模块

 

  • Linux&Unix:   Executable and Linkable Format
  • Windows:       Portable Executable
  • 目标文件的标准二进制格式:ELF二进制文件
  • 一个统一的格式:
    • 可重定位目标文件(.o),
    • 可执行目标文件(a.out)
    • 共享目标文件(.so)
  • 工具:    readelf  文件名

 


7.4 可重定位目标文件

ELF目标文件格式

  • Elf 头
    • 字大小、字节顺序、文件类型(.o,exec,.so),机器类型,等等
  • 段头表/程序头表
    • 页面大小,虚拟地址内存段(节),段大小
  • .text 节(代码)
    • 代码
  • .rodata 节(只读数据)
    • 只读数据 :  跳转表, ...
  • .data 节 (数据/可读写)
    • 已初始化全局变量
  • .bss 节 (未初始化全局变量)
    • 未初始化的全局变量
    • 符号开始的块
    • 更加节省空间
    • 有节头,但不占用空间
  • .symtab 节(符号表)
    • 符号表
    • 函数和静态变量名
    • 节名称和位置
  • .rel.text 节(可重定位代码)
    • .text 节的可重定位信息
    • 在可执行文件中需要修改的指令地址
    • 需修改的指令.
  • .rel.data 节(可重定位数据)
    • .data 节的可重定位信息
    • 在合并后的可执行文件中需要修改的指针数据的地址
  • .debug 节(调试)
    • 为符号调试的信息 (gcc -g)
  • 节头表Section header table
    • 每个节的偏移量和大小

 


7.5 符号和符号表

  • 全局符号
    • 由模块m定义的,可以被其他模块引用的符号
    • 例如: 非静态non-static C 函数与非静态全局变量.
  • 外部符号
    • 由模块m引用的全局符号,但由其他模块定义
  • 本地/局部符号
    • 模块m定义和仅由m唯一引用的符号
    • 如:使用静态属性定义的C函数和全局变量
    • 本地链接符号不是本地程序变量-局部变量

 


7.6 符号解析

7.6.1 链接器如何歇息多重定义的全局符号

 

  • 程序符号要么是强符号,要么是弱符号
    • 函数初始化全局变量
    • : 未初始化的全局变量

 

 

链接器的符号处理规则

  • 规则 1:不允许多个同名的强符号
    • 每个强符号只能定义一次
    • 否则: 链接器错误
  • 规则 2:若有一个强符号和多个弱符号同名,则选择强符号
    • 对弱符号的引用解析为强符号
  • 规则 3:如果有多个弱符号,选择任意一个
    • 可以用 gcc –fno-common 来覆盖这个规则

 

全局变量

  • 避免:如果你能---尽量---这样程序的模块化好
  • 否则
    • 使用 static :如果你能
    • 定义了一个全局变量,就初始化它
    • 使用 extern :如果你引用了一个外部全局符号

 

7.6.2 与静态库链接

 

  • 静态库 (.a 存档文件)
    • 将相关的可重定位目标文件连接到一个带有索引的单个文件中(叫做存档文件).
    • 增强链接器,使它尝试通过查找一个或多个存档文件中的符号来解决未解析的外部引用.
    • 如果一个存档成员文件.o解析了符号引用,就把它链接入可执行文件

 

 


7.7 重定位

  • 重定位节和符号定义
    • 链接器将所有相同类型的节合并为同一类型的新聚合节
    • 链接器将运行时内存地址赋给新的聚合节,赋给输入模块定义的每个节以及每个符号
    • 程序中的每条指令和全局变量将有唯一的运行时的内存地址
  • 重定位节中的符号引用
    • 链接器修改代码节和数据节中对每个符号的引用,使它们指向正确的运行时的地址
    • 要执行这一步,链接器依赖于可重定位目标模块中称为 重定位条目 relocation entry 的数据结构

7.7.1 重定位条目

  • offset
    • 需要被修改的引用的节偏移
  • symbol
    • 标识被修改引用应该指向的符号
  • type
    • 如何修改新的引用
    • R_X86_64_32 array
      • 绝对地址引用
    • R_X86_64_PC32 sum-0x4
      • 相对地址引用
  • attend
    • 有符号常数
    • 偏移调整

7.7.2 重定位符号引用

7.7.2.1 相对引用

7.7.2.2 绝对引用

 


7.8 可执行目标文件

 


7.9 加载可执行目标文件

 


7.10 动态链接共享库

  • 当执行文件第一次加载和运行时(加载时链接),动态链接就会出现.
    • Linux的常见情况是,由动态链接器(ld-linux.so)自动处理.
    • 标准C (libc.so)通常是动态链接的.
  • 动态链接也可以在程序启动后进行(运行时链接).
    • Linux中,这是通过调用dlopen()接口完成的.
      • 分布式软件.
      • 高性能web服务器.
      • 运行时库打桩.
  • 共享库的例程可以由多个进程共享.
    • 当我们学习虚拟内存时有更多关于这个的内容

 


7.11 从应用程序中加载和链接共享库 


7.12 位置无关代码


7.13 库打桩机制

  • 安全
  • 调试
  • 库打桩机制:   强大的链接技术--- 允许程序员拦截对任意函数的调用
  • 打桩可出现在:
    • 编译时:源代码被编译时   
    • 链接时:当可重定位目标文件被静态链接来形成一个可执行目标文件时
    • 加载/运行时:当一个可执行目标文件被加载到内存中,动态链接,然后执行时
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值