总结(三)

静态链接

链接过程主要包括地址和空间的分配、符号决议、重定位


空间和地址分配

分配的空间是指虚拟地址空间的分配。

  • 将这连个文件编译之后链接在一块儿成为ab的过程中,a.o和b.o的内容如何合并,换句话说如何在ab中储存两个.o文件的内容?
    相似段合并: 将所有文件中的代码段.text合并在一块儿,.data合并到一块儿等等。
  • 将文件合并之后之前文件的相对偏移地址发生变化,如何在新的文件中对其内容进行定位?
    在链接的过程中,合并多个文件会根据所的信息对其内容碱性符号解析和重定位。

综上所述,链接器分配空间的策略是采用相似段合并,并采用两步链接的方法。

  1. 空间地址分配 扫描输入文件,获得段长度属性位置,将输入文件中的符号定义和引用都收集起来放到全局符号表中。 链接器获得输入文件的段长度,并将它们合并起来,计算输出文件的各个段长度和位置,建立映射关系。
  2. 符号解析和重定位 使用第一步的信息,对合成的输出文件的符号信息进行解析调节,调整代码中的地址等。

查看各个文件的属性,可以看到ab的.text的大小正好是两个文件的.text大小和
符号地址的确定
因为各个符号在段内的相对位置是固定的,所以其实在合并之后的各个符号的地址就一定确定了,在段基址加上一个偏移值,或者原本的偏移值加上一个偏移值。

符号解析和重定位

重定位 起始对于符号地址以及各个代码段的地址在上面部份已经解决,但是在代码段中的引用的外部符号的地址会在新的输出文件中发生改变,所以代码段中的引用外部符号的地址也需要进行改变,这个也就是重定位的过程。

0x14 向esi传入0x00 和 0x21 的main的地址也是0x00, 这些在a.o中作为符号保留位置,在链接成为ab之后,他们的地址被改写

可以看到shared的地址是0x00601000所以填入00 10 60 00
call指令是下一个指令的地址加上调用的偏移值所以 swap地址等于 0040010d + 00000002 = 40010f

问题: 如何确定在重定位的时候的每个符号的地址信息,就是如何找到代码段中哪些地方需要修改?

使用重定位表
对于可重定位的ELF文件来说,他必须包含重定位表,用来专门保存重定位信息(重定位包含但不局限于代码段)。
可以使用objdump的-r选项查看重定位表信息,重定位的数据结构:

r_offset 重定位入口地址
r_info 重定位符号类型

符号解析
使用objdump -s 查看符号信息符号表 .symtab

指令修正方式

  • 绝对寻址修正 S+A
    S是符号的实际地址, A 是修正位置的值,比如shared的修正
  • 相对寻址修正 S + A - P

S是符号的实际地址, P是被修正的位置地址, A是修正位置的值
A是目的地址相对于下一条指令的偏移量
我的理解是 如果D是要填的值的话, 那么有使用call调用函数的地址是D+(-P+A) = S
所以有D = S + A -P

COMMON块

用于解决符号冲突问题,是对弱符号机制问题解决得办法
对于多个符号定义类型不一致情况:

  • 两个或者两个以上得强符号类型不一致
  • 一个强符号,其他的弱符号,类型不一致
  • 两个或者两个以上弱符号类型不一致
    解决办法:
    第一种情况连接器报错, 后面两种情况,参照强符号弱符号得处理方式来进行处理。

API 和 ABI


可以使用ar命令查看lib.a这样得文件内部所存在得.o文件得种类
每个.o文件中只包含一个函数,这样来避免浪费,因为链接器链接静态库的单位是目标文件

链接控制脚本

使用链接器得方法:

  1. 使用命令行 ld collect2之类
  2. 将连接指令存放在目标文件里面
  3. 使用连接控制脚本
    ENTRY(函数名) 入口函数
    STARTUP(filename) 第一个输入文件
    SEARCH_DIR(path) 将路径加入ld链接器得库查找目录
    INPUT(file,file,...) 将指定文件作为链接输入文件
    INCLUDE filename 指定文件包含进本链接脚本
    PROVIDE(symbol) 在链接脚本中定义某个符号

Windows上得可执行文件PE类型,大体和Linux得Elf一样

原文地址:https://www.cnblogs.com/Alruddy/p/9153049.html