2011年(15)
分类: 嵌入式
2011-12-23 17:12:42
Linux中的重定位处理都是通过bfd库完成的。本文描述的是在编译链接时bfd的重定位处理,不涉及运行时加载器的重定位。重定位信息保存在.rel.text节中,用“objdump -r ”可以查看。
1、重定位的流程:重定位的过程是基于bfd_perform_relocation,各后端有不同的实现。这里以elf_backend_relocate_section分析:
2、://重定位处理开始
//符号重定位计算
if(common_section)relocation=0
else relocation=symbol->value
relocation+= symbol->section->output_offset
if(!(output_bfd&&!partial_inplace) ) relocation+=symbol->section->output_section->vma;//最终连接重定位
relocation+=reloc_entry->addend
if(pc_relative)
//relocation是要跳转到的新地址。
//现在,relocation是绝对地址。
relocation-=input_section->output_section->vma + input_section->output_offset
//现在,relocation是相对于节开头的偏移。
if(pcrel_offset) relocation-=reloc_entry->address
//现在,relocation是相对于PC的偏移。
endif//perform_relocation特有的部分
if(!output_bfd)
reloc_entry->addend=relocation
reloc_entry->address+=input_section->output_offset
if(!partial_inplace)return
else
reloc_entry->addend=0
endif//重定位目标内容
x=read_content //从被定位的目标地址读取数据
x=(x&~dsk_mask)|( (x&src_mask+relocation>>rightshift<write_content(x)
//重定位处理结束
本地符号辨别规则:[ (rela).r_info>>8 ] < (section header).sh_info
否则为全局符号。
处理方法的区别:
全局符号结构复杂(通过链表寻找);
全局符号只对defined和defweak进行处理,作出unresolved的标记,或与本地符号做完全相同的计算。
本地符号和全局符号的重定位计算方式是一模一样的。本地符号在链接时最终重定位后会被解析,但全局符号有可能被解析,有可能继续保留,特别是与动态连接相关的符号。
结构的作用
Howto结构保存重定位参数信息,供多个函数使用。
以RELA重定位为例,在重定位流程中,重定位内容是这样计算的:
x=(x&~dsk_mask)|( (x&src_mask+relocation>>rightshift< 下面的表格展示了该表达式的意义。 注:粗体字是howto结构的成员。 relocation RRRRRRR new_relocation= relocation >>rightshift<<bitpos 000RRR0 x IIINNNN 重定位前的指令 src_mask 0001110 指出操作数中参与累加的部分 dst_mask 0001111 指出指令中会受重定位影响的部分 p0=x&~dst_mask III0000 操作码 p1= x&src_mask 000NNN0 操作数中参与累加的部分 p1 + new_relocation = p2 000NNN0 + 000RRR0 = 00xxxx0 重定位的计算 p3=p2&dst_mask 000xxx0 x=p0|p3 IIIxxx0 重定位后的指令