#CSAPP#7.7 重定位

  • 重定位由 重定位节和符号定义 & 重定位节中的符号引用  两步组成
  • 重定位节和符号定义 链接器将所有相同类型的节合并为同一类型的新的聚合节
  • 重定位节中的符号引用:链接器修改代码节和数据节中对每个符号的引用
7.7.1   重定位条目
ELF重定位条目的形式(每个条目表示一个必须被重定位的引用,并指明如何计算被修改的引用)
typedef struct{
    long offset;
    long type:32, 
         symbol:32; 
    long addend;
}Elf64_Rela
  • offset 需要被修改的引用的节偏移
  • symbol 标识被修改引用应该指向的符号
  • type 告知链接器如何修改新的引用
  • addend 一个有符号常数,一些类型的重定位要使用它对被修改引用的值做偏移调整
两种最基本的重定位类型(type)
  • R_X86_64_PC32:重定位一个使用32位PC相对地址的引用[注1 一个PC相对地址就是距PC(程序计数器)的当前运行时值的偏移量][注2 当CPU执行到一条使用PC相对寻址的指令时,它就将在指令中编码的32位值加上PC的当前运行时值,得到有效地址(如call指令的目标),PC值通常是下一条指令在内存中地址]
  • R_X86_64_32:重定位一个使用32位PC绝对地址的引用[通过绝对寻址,CPU直接使用在指令中编码的32位值作为有效地址,不需要进一步修改]
7.7.2   重定位符号引用
记每个节s为一个字节数组,每个节相关联的重定位条目r是一个类型为Elf64_Rela的结构。并假设当算法运行时,链接器已经为每个节和每个符号选择了运行时地址(分别表示为ADDR(s)和ADDR(r.symbol))

重定位算法

foreach section s {
    foreach relocation entry r {
        refptr = s + r.offset;//计算需要被重定位的4字节引用的数组s中的地址
//若这个引用使用的是PC相对寻址
        if(r.type == R_X86_64_PC32){
            refaddr = ADDR(s) + r.offset;
            *refptr = (unsigned)(ADDR(r.symbol) + r.addend - resaddr);
        }
//若这个引用使用的是绝对寻址
        if(r.type == R_X86_64_32){
            *refptr = (unsigned)(ADDR(r.symbol) + r.addend);
        }
    }
}
为每个引用,汇编器产生一个重定位条目,显示在引用的下一行(引用如何实现???)
注意反汇编列表给出的引用值是用小端法字节顺序表示,如原来1个操作符加4个占位符为:
bf 00 00 00 00    mov    $0x0,%edi
而计算出*refptr = (unsigned)(0x601018),则该引用有重定位格式:
bf 18 10 60 00    mov    $0x601018,%edi

猜你喜欢

转载自blog.csdn.net/mayday__ashin/article/details/80722722