Return-to-dl-resolve

前置知识:

ELF可执行文件由ELF头部,程序头部和其对应的段,节头部表和其对应的节组成。

ELF文件结构如果想深入了解的话可以看下《程序员的自我修养》的第三章 P70

如果一个可执行文件要进行动态链接,它的程序头部表将包含类型为PT_DYNAMIC的段,它包含.dynamic节结构如下

typedef struct {
    Elf32_Sword d_tag;
    union {
        Elf32_Word d_val;
        Elf32_Addr d_ptr;
    } d_un;
} Elf32_Dyn;

其中tag对应着每个节 


JMPREL对应 .rel.plt 用来保存运行时重定位表

SYMTAB对应着符号表.dymsym  它是一个Elf32_Sym结构的数组 

STRTAB对应着字符串表.dymstr 用来存放动态链接时需要用到的字符串


ELF中节中包涵目标文件的所有信息,节的结构如下

typedef struct {
    Elf32_Word sh_name;      // 节头部字符串表节区的索引
    Elf32_Word sh_type;      // 节类型
    Elf32_Word sh_flags;     // 节标志,用于描述属性
    Elf32_Addr sh_addr;      // 节的内存映像
    Elf32_Off  sh_offset;    // 节的文件偏移
    Elf32_Word sh_size;      // 节的长度
    Elf32_Word sh_link;      // 节头部表索引链接
    Elf32_Word sh_info;      // 附加信息
    Elf32_Word sh_addralign; // 节对齐约束
    Elf32_Word sh_entsize;   // 固定大小的节表项的长度
} Elf32_Shdr;


.rel.plt节是用于函数重定位 ,.rel.dyn节是用于变量重定位

typedef struct {
    Elf32_Addr r_offset;    // 对于可执行文件,此值为虚拟地址
    Elf32_Word r_info;      // 符号表索引
} Elf32_Rel;

#define ELF32_R_SYM(info) ((info)>>8) #符号在符号表中的索引,占r_offset的高24位
#define ELF32_R_TYPE(info) ((unsigned char)(info))重定位类型 占r_offset的低8位
#define ELF32_R_INFO(sym, type) (((sym)<<8)+(unsigned char)(type))

.rel.plt 中的offset 对应着r_offset 是函数在.got.plt表中的位置, Info对应着r_info的高24位,Type对应着r_info的低8位 



GOT表是一个简单数组,存放各种绝对地址。

GOT[0] 存放的是动态链接数组_dynamic[]的地址,GOT[1]存放的是一个link_map类型的指针

GOT[2]存放的是动态链接器的解析函数<dl_runtime_resolve>的入口地址


PLT表是由一小段一小段代码组成的(几条控制跳转的汇编语句)

PLT0:

push GOT[1];

jmp GOT[2];

.......

PLTn:

jmp GOT[x+n];

push n; #relocation offset of symbol ,the second argument of _dl_runtime_resolve

jmp PLT0; call the rtld


程序第一次调用位于.got.plt表中的函数时 ,会跳转回plt表中

然后将参数压入栈中 ,这个参数是reloc_offset 是函数在got表中的偏移

接着会跳转到PLT0,将link_map压入栈中,在调用_dl_runtime_resolve函数来对函数进行重定位

这个函数原型是_dl_runtime_resolve(link_map,reloc_offset)

调用_dl_runtime_resolve函数后

先根据reloc_offest 找到要解析符号的重定位项结构信息reloc

ELF32_Rel *rel_entry = JMPREL + reloc_offset

然后在根据reloc->r-info 找到符号在符号表中的索引

ELF32_Sym *sym_entry = SYMTAB[ELF32_R_SYM(rel_entry->r_info)]

其中还会对重定向符号的类型进行检测

 assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);

接着在通过.dymsym项中的st_name找到符号在字符串表.dymstr中的偏移

char *sym_name = STRTAB + sym_entry->st_name

最后通过fixup()函数遍历各个库的符号表 找到函数地址再将地址写入GOT表对应的位置中

当程序第二次调用这个函数时,就会直接调用这个函数


如果想对动态链接更进一步了解的话

可以看《Linux动态链接机制研究及应用》、《程序员的自我修养》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值