====================== Relocation (重定位)==========================
重定位是连接符号引用和符号定义的过程。比如,当一个程序调用一个函数的时候,
相关的调用必须在执行时把控制传送到正确的目标地址。换句话说,重定位文件应当
包含有如何修改他们的 section 内容的信息,从而允许可执行文件或共享目标文件
为一个进程的程序映像保存正确的信息。重定位入口就是这样的数据。
+ Figure 1-20: Relocation Entries
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
} Elf32_Rela;
* r_offset
该成员给出了应用重定位行为的地址。对于一个重定位文件而言,该值是从该
section 开始处到受到重定位影响的存储单位的字节偏移量。对一个可执行文件
或一个共享目标而言,该值是受到重定位影响的存储单位的虚拟地址。
* r_info
该成员给出了具有受重定位影响因素的符号表索引和重定位应用的类型。比如,
一个调用指令的重定位入口应当包含被调用函数的符号索引。如果该索引是
STN_UNDEF (未定义的符号索引),重定位将使用 0 作为该符号的值。重定位
类型是和处理器相关的。当正文(text)引用到一个重定位入口的重定位类型或符
号表索引,它表明相应的应用 ELF32_R_TYPE或 ELF32_R_SYM 于入口的 r_info
成员。
#define ELF32_R_SYM(i) ((i)>>8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s, t) ((s)<<8+(unsigned char)(t))
* r_addend
该成员指定一个常量加数(用于计算将要存储于重定位域中的值)。
如上所述,只有 Elf32_Rela 入口包含一个明确的加数。Elf32_Rel 类型
的入口在可以修改的地址中存储一个隐含的加数。依赖于处理器结构,一种形式
或其他形式也许是必须的或更为方便的。因此,特定机器的应用应当使用一种排他
性的形式或依赖于上下文的另一种形式。
一个重定位 section 关联了两个其他的 section :一个符号表和一个可修改
的 section 。该 section 头的成员 sh_info 和 sh_link (在上文中的
“ section ”部分中有描述)指示了这种关系。重定位入口中的成员 r_offset
对于不同的目标文件有少许差异。
* 在可重定位文件中,r_offset 表示了一个 section 偏移。也就是说,重定位
section自己描述了如何修改其他在文件中的其他section; 重定位偏移量指
明了一个在第二个section中的存储器单元。
* 在可执行和共享的目标文件中,r_offset 表示一个虚拟地址。为了使得这些
文件的重定位入口更为有用(对于动态链接器而言),该 section 偏移(文件
中)应当让位于一个虚拟地址(内存中的)。
尽管为了允许相关的程序更为有效的访问而让 r_offset 的解释对于不同的目标
文件有所不同,重定位类型的含义是相同的。
Relocation Types(重定位类型)
重定位入口描述了怎样变更下面的指令和数据域(位数在表的两边角下)。
+ Figure 1-21: Relocatable Fields
+---------------------------+
| word32 |
31---------------------------0
* word32
指定一个以任意字节对齐方式占用 4 字节的 32 位域。这些值使用与 32 位 Intel
体系相同的字节顺序。
3------2------1------0------+
0x01020304 | 01 | 02 | 03 | 04 |
31------+------+------+------0
下面的计算假设正在将一个可重定位文件转换为一个可执行或共享的目标文件。
从概念上来说,链接器合并一个或多个可重定位文件来组成输出。它首先决定
怎样合并、定位输入文件,然后更新符号值,最后进行重定位。对于可执行文件
和共享的目标文件而言,重定位过程是相似的并有相同的结果。下面的描述使用
如下的约定符号。
* A
表示用于计算可重定位的域值的加数。
* B
表示了在执行过程中一个共享目标被加载到内存时的基地址。一般情况下,一个
共享object文件使用的基虚地址为0,但是一个可执行地址就跟共享object文件
不同了。
* G
表示了在执行过程中重定位入口符号驻留在全局偏移表中的偏移。请参阅
第二部分中的“ Global Offset Table (全局偏移表)”获得更多
的信息。
* GOT
表示了全局偏移表的地址。请参阅第二部分中的“ Global Offset Table
(全局偏移表)”获得更多的信息。
* L
表示一个符号的过程链接表入口的位置( section 偏移或地址)。一个过程
链接表入口重定位一个函数调用到正确的目的单元。链接器创建初始的链接表,
而动态链接器在执行中修改入口。
请参阅第二部分中的“ Procedure Linkage Table (过程链接表)”获得更多
的信息
* P
表示(section 偏移或地址)被重定位的存储单元位置(使用 r_offset 计算的)。
* S
表示索引驻留在重定位入口处的符号值。
一个重定位入口的 r_offset 值指定了受影响的存储单元的首字节的偏移
或虚拟地址。重定位类型指定了哪一位(bit)将要改变,以及怎样计算它们的值。
在 SYSTEM V 体系中仅仅使用 Elf32_Rel 重定位入口,将要被重定位的域中
保留了加数。在所有的情况下,加数和计算结果使用相同字节顺序。
+ Figure 1-22(表 1-22): Relocation Types(重定位类型)
Name Value Field Calculation
==== ===== ===== ===========
R_386_NONE 0 none none
R_386_32 1 word32 S + A
R_386_PC32 2 word32 S + A - P
R_386_GOT32 3 word32 G + A - P
R_386_PLT32 4 word32 L + A - P
R_386_COPY 5 none none
R_386_GLOB_DAT 6 word32 S
R_386_JMP_SLOT 7 word32 S
R_386_RELATIVE 8 word32 B + A
R_386_GOTOFF 9 word32 S + A - GOT
R_386_GOTPC 10 word32 GOT + A - P
有的重定位类型有不同于简单计算的语义。
* R_386_GOT32
这种重定位类型计算全局偏移表基地址到符号的全局偏移表
入口之间的间隔。这样另外通知了 link editor 建立一个全局偏移表 。
* R_386_PLT32
这种重定位类型计算符号的过程链接表入口地址,并另外通知链接器建立一个
过程链接表。
* R_386_COPY
链接器创建该重定位类型用于动态链接。它的偏移成员涉及一个可写段中的一个
位置。符号表索引指定一个可能存在于当前 object file 或在一个shared object
中的符号。在执行过程中,动态链接器把和 shared object 符号相关的数据
拷贝到该偏移所指定的位置。
* R_386_GLOB_DAT
这种重定位类型用于设置一个全局偏移表入口为指定符号的地址。该特定的重定位
类型允许你决定符号和全局偏移表入口之间的一致性。
* R_386_JMP_SLOT {*}
链接器创建该重定位类型用于动态链接。其偏移成员给出了一个过程链接表入口的
位置。动态链接器修改该过程链接表入口以便向特定的符号地址传递控制。
[参阅第二部分中的 "Procedure Linkage Table(过程链接表)"]
* R_386_RELATIVE
链接器创建该重定位类型用于动态链接。其偏移成员给出了包含表达相关地址值
的一个 shared object 中的位置。动态链接器计算相应的虚拟地址(把该
shared object 装载地址和相对地址相加)。该类型的重定位入口必须为
符号表索引指定为 0 。
* R_386_GOTOFF
这种重定位类型计算符号值和全局偏移表地址之间的不同。另外还通知链接器
建立全局偏移表(GOT)。
* R_386_GOTPC
这种重定位类型类似于 R_386_PC32 ,不同的是它在计算中使用全局偏移表。
这种重定位中引用的符号通常是 _GLOBAL_OFFSET_TABLE_ ,该符号通知了
链接器建立全局偏移表(GOT)。
阅读(3500) | 评论(0) | 转发(0) |