重定位项说明如何修改下图中的指令和数据字段。位数显示在框的下角。
在 SPARC 平台上,重定位项应用于字节 (byte8)、半字 (half16) 或字。
在 64 位 SPARC 和 x64 上,重定位项还会应用于扩展字 (xword64):
在 x86 上,重定位项应用于字 (word32):
word32 可指定一个占用 4 个字节的 32 位字段,此字段以任意字节对齐。这些值使用与 x86 体系结构中的其他字值相同的字节顺序:
在所有情况下,r_offset 值都会指定受影响存储单元的第一个字节的偏移或虚拟地址。重定位类型可指定要更改的位以及计算这些位的值的方法。
针对以下重定位类型进行的计算假定,操作会将可重定位文件转换为可执行文件或共享库文件。在概念上,链接编辑器会将一个或多个可重定位文件合并以形成输出。链接编辑器首先确定如何合并和定位输入文件。然后,链接编辑器会更新符号值并执行重定位。应用于可执行文件或共享库文件的重定位类似,并会取得相同的结果。本节的表中的说明使用以下表示法:
用于计算可重定位字段的值的加数。
执行过程中将共享库装入内存的基本地址。通常,生成的共享库文件的基本虚拟地址为 0。但是,共享库的执行地址不相同。 请参见程序头。
执行过程中,重定位项的符号地址所在的全局偏移表中的偏移。 请参见全局偏移表(特定于处理器)。
全局偏移表的地址。 请参见全局偏移表(特定于处理器)。
符号的过程链接表项的节偏移或地址。 请参见过程链接表(特定于处理器)。
使用 r_offset 计算出的重定位的存储单元的节偏移或地址。
索引位于重定位项中的符号的值。
下表中的字段名称可确定重定位类型是否会检查 overflow。计算出的重定位值可以大于预期的字段,并且重定位类型可以验证 (V) 值是否适合结果或将结果截断 (T)。例如,V-simm13 表示计算出的值不能包含 simm13 字段外有意义的非零位。
表 7–13 SPARC: ELF 重定位类型
名称 |
值 |
字段 |
计算 |
---|---|---|---|
R_SPARC_NONE |
0 |
无 |
无 |
R_SPARC_8 |
1 |
V-byte8 |
S + A |
R_SPARC_16 |
2 |
V-half16 |
S + A |
R_SPARC_32 |
3 |
V-word32 |
S + A |
R_SPARC_DISP8 |
4 |
V-byte8 |
S + A - P |
R_SPARC_DISP16 |
5 |
V-half16 |
S + A - P |
R_SPARC_DISP32 |
6 |
V-disp32 |
S + A - P |
R_SPARC_WDISP30 |
7 |
V-disp30 |
(S + A - P) >> 2 |
R_SPARC_WDISP22 |
8 |
V-disp22 |
(S + A - P) >> 2 |
R_SPARC_HI22 |
9 |
T-imm22 |
(S + A) >> 10 |
R_SPARC_22 |
10 |
V-imm22 |
S + A |
R_SPARC_13 |
11 |
V-simm13 |
S + A |
R_SPARC_LO10 |
12 |
T-simm13 |
(S + A) & 0x3ff |
R_SPARC_GOT10 |
13 |
T-simm13 |
G & 0x3ff |
R_SPARC_GOT13 |
14 |
V-simm13 |
G |
R_SPARC_GOT22 |
15 |
T-simm22 |
G >> 10 |
R_SPARC_PC10 |
16 |
T-simm13 |
(S + A - P) & 0x3ff |
R_SPARC_PC22 |
17 |
V-disp22 |
(S + A - P) >> 10 |
R_SPARC_WPLT30 |
18 |
V-disp30 |
(L + A - P) >> 2 |
R_SPARC_COPY |
19 |
无 |
请参阅此表后面的说明。 |
R_SPARC_GLOB_DAT |
20 |
V-word32 |
S + A |
R_SPARC_JMP_SLOT |
21 |
无 |
请参阅此表后面的说明。 |
R_SPARC_RELATIVE |
22 |
V-word32 |
B + A |
R_SPARC_UA32 |
23 |
V-word32 |
S + A |
R_SPARC_PLT32 |
24 |
V-word32 |
L + A |
R_SPARC_HIPLT22 |
25 |
T-imm22 |
(L + A) >> 10 |
R_SPARC_LOPLT10 |
26 |
T-simm13 |
(L + A) & 0x3ff |
R_SPARC_PCPLT32 |
27 |
V-word32 |
L + A - P |
R_SPARC_PCPLT22 |
28 |
V-disp22 |
(L + A - P) >> 10 |
R_SPARC_PCPLT10 |
29 |
V-simm13 |
(L + A - P) & 0x3ff |
R_SPARC_10 |
30 |
V-simm10 |
S + A |
R_SPARC_11 |
31 |
V-simm11 |
S + A |
R_SPARC_HH22 |
34 |
V-imm22 |
(S + A) >> 42 |
R_SPARC_HM10 |
35 |
T-simm13 |
((S + A) >> 32) & 0x3ff |
R_SPARC_LM22 |
36 |
T-imm22 |
(S + A) >> 10 |
R_SPARC_PC_HH22 |
37 |
V-imm22 |
(S + A - P) >> 42 |
R_SPARC_PC_HM10 |
38 |
T-simm13 |
((S + A - P) >> 32) & 0x3ff |
R_SPARC_PC_LM22 |
39 |
T-imm22 |
(S + A - P) >> 10 |
R_SPARC_WDISP16 |
40 |
V-d2/disp14 |
(S + A - P) >> 2 |
R_SPARC_WDISP19 |
41 |
V-disp19 |
(S + A - P) >> 2 |
R_SPARC_7 |
43 |
V-imm7 |
S + A |
R_SPARC_5 |
44 |
V-imm5 |
S + A |
R_SPARC_6 |
45 |
V-imm6 |
S + A |
R_SPARC_HIX22 |
48 |
V-imm22 |
((S + A) ^ 0xffffffffffffffff) >> 10 |
R_SPARC_LOX10 |
49 |
T-simm13 |
((S + A) & 0x3ff) | 0x1c00 |
R_SPARC_H44 |
50 |
V-imm22 |
(S + A) >> 22 |
R_SPARC_M44 |
51 |
T-imm10 |
((S + A) >> 12) & 0x3ff |
R_SPARC_L44 |
52 |
T-imm13 |
(S + A) & 0xfff |
R_SPARC_REGISTER |
53 |
V-word32 |
S + A |
R_SPARC_UA16 |
55 |
V-half16 |
S + A |
R_SPARC_GOTDATA_HIX22 |
80 |
T-imm22 |
((S + A - GOT) >> 10) ^ ((S + A - GOT) >> 31) |
R_SPARC_GOTDATA_LOX22 |
81 |
T-imm13 |
((S + A - GOT) & 0x3ff) | (((S + A - GOT) >> 31) & 0x1c00) |
R_SPARC_GOTDATA_OP_HIX22 |
82 |
T-imm22 |
(G >> 10) ^ (G >> 31) |
R_SPARC_GOTDATA_OP_LOX22 |
83 |
T-imm13 |
(G & 0x3ff) | ((G >> 31) & 0x1c00) |
R_SPARC_GOTDATA_OP |
84 |
Word32 |
请参阅此表后面的说明。 |
其他重定位类型可用于线程局部存储引用。这些重定位类型将在第 8 章,线程局部存储中介绍。
一些重定位类型的语义不只是简单的计算:
与 R_SPARC_LO10 类似,不同的是此重定位指向符号的 GOT 项的地址。此外,R_SPARC_GOT10 还指示链接编辑器创建全局偏移表。
与 R_SPARC_13 类似,不同的是此重定位指向符号的 GOT 项的地址。此外,R_SPARC_GOT13 还指示链接编辑器创建全局偏移表。
与 R_SPARC_22 类似,不同的是此重定位指向符号的 GOT 项的地址。此外,R_SPARC_GOT22 还指示链接编辑器创建全局偏移表。
与 R_SPARC_WDISP30 类似,不同的是此重定位指向符号的过程链接表项的地址。此外,R_SPARC_WPLT30 还指示链接编辑器创建过程链接表。
由链接编辑器为动态可执行文件创建,用于保留只读文本段。此重定位偏移成员指向可写段中的位置。符号表索引指定应在当前目标文件和共享库中同时存在的符号。执行过程中,运行时链接程序将与共享库的符号关联的数据复制到偏移所指定的位置。 请参见复制重定位。
与 R_SPARC_32 类似,不同的是此重定位会将 GOT 项设置为所指定符号的地址。使用特殊重定位类型,可以确定符号和 GOT 项之间的对应关系。
由链接编辑器为动态库创建,用于提供延迟绑定。此重定位偏移成员可指定过程链接表项的位置。运行时链接程序会修改过程链接表项,以将控制权转移到指定的符号地址。
由链接编辑器为动态库创建。此重定位偏移成员可指定共享库中包含表示相对地址的值的位置。运行时链接程序通过将装入共享库的虚拟地址与相对地址相加,计算对应的虚拟地址。此类型的重定位项必须为符号表索引指定零值。
与 R_SPARC_32 类似,不同的是此重定位指向未对齐的字。必须将要重定位的字作为任意对齐的四个独立字节进行处理,而不是作为根据体系结构要求对齐的字进行处理。
与 R_SPARC_HI22 类似,不同的是此重定位会进行截断而不是验证。
与 R_SPARC_PC22 类似,不同的是此重定位会进行截断而不是验证。
与 R_SPARC_LOX10 一起用于可执行文件,这些可执行文件在 64 位地址空间中的上限为 4 GB。与 R_SPARC_HI22 类似,但会提供链接值的补码。
与 R_SPARC_HIX22 一起使用。与 R_SPARC_LO10 类似,但始终设置链接值的位 10 到 12。
与 R_SPARC_H44 和 R_SPARC_M44 重定位类型一起使用,以生成 44 位的绝对寻址模型。
用于初始化寄存器符号。此重定位偏移成员包含要初始化的寄存器编号。对于此寄存器必须存在对应的寄存器符号。该符号必须为 SHN_ABS 类型。
这些重定位类型用于代码转换。
重定位计算中使用的以下表示法是特定于 64 位 SPARC 的。
用于计算重定位字段的值的辅助加数。此加数通过应用 ELF64_R_TYPE_DATA 宏从 r_info 字段中提取。
下表中列出的重定位类型是扩展或修改针对 32 位 SPARC 定义的重定位类型所得的。 请参见SPARC: 重定位类型。
表 7–14 64 位 SPARC: ELF 重定位类型
名称 |
值 |
字段 |
计算 |
---|---|---|---|
R_SPARC_HI22 |
9 |
V-imm22 |
(S + A) >> 10 |
R_SPARC_GLOB_DAT |
20 |
V-xword64 |
S + A |
R_SPARC_RELATIVE |
22 |
V-xword64 |
B + A |
R_SPARC_64 |
32 |
V-xword64 |
S + A |
R_SPARC_OLO10 |
33 |
V-simm13 |
((S + A) & 0x3ff) + O |
R_SPARC_DISP64 |
46 |
V-xword64 |
S + A - P |
R_SPARC_PLT64 |
47 |
V-xword64 |
L + A |
R_SPARC_REGISTER |
53 |
V-xword64 |
S + A |
R_SPARC_UA64 |
54 |
V-xword64 |
S + A |
R_SPARC_H34 |
85 |
V-imm22 |
(S + A) >> 12 |
以下重定位类型的语义不只是简单的计算:
与 R_SPARC_LO10 类似,不同的是会添加额外的偏移,以充分利用 13 位带符号的直接字段。
下表中列出的重定位类型是针对 32 位 x86 定义的。
表 7–15 32 位 x86: ELF 重定位类型
名称 |
值 |
字段 |
计算 |
---|---|---|---|
R_386_NONE |
0 |
无 |
无 |
R_386_32 |
1 |
word32 |
S + A |
R_386_PC32 |
2 |
word32 |
S + A - P |
R_386_GOT32 |
3 |
word32 |
G + A |
R_386_PLT32 |
4 |
word32 |
L + A - P |
R_386_COPY |
5 |
无 |
请参阅此表后面的说明。 |
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_32PLT |
11 |
word32 |
L + A |
R_386_16 |
20 |
word16 |
L + A |
R_386_PC16 |
21 |
word16 |
L + A - P |
R_386_8 |
22 |
word8 |
L + A |
R_386_PC8 |
23 |
word8 |
L + A - P |
其他重定位类型可用于线程局部存储引用。这些重定位类型将在第 8 章,线程局部存储中介绍。
一些重定位类型的语义不只是简单的计算:
计算 GOT 的基本地址与符号的 GOT 项之间的距离。此重定位还指示链接编辑器创建全局偏移表。
计算符号的过程链接表项的地址,并指示链接编辑器创建一个过程链接表。
由链接编辑器为动态可执行文件创建,用于保留只读文本段。此重定位偏移成员指向可写段中的位置。符号表索引指定应在当前目标文件和共享库中同时存在的符号。执行过程中,运行时链接程序将与共享库的符号关联的数据复制到偏移所指定的位置。 请参见复制重定位。
用于将 GOT 项设置为所指定符号的地址。使用特殊重定位类型,可以确定符号和 GOT 项之间的对应关系。
由链接编辑器为动态库创建,用于提供延迟绑定。此重定位偏移成员可指定过程链接表项的位置。运行时链接程序会修改过程链接表项,以将控制权转移到指定的符号地址。
由链接编辑器为动态库创建。此重定位偏移成员可指定共享库中包含表示相对地址的值的位置。运行时链接程序通过将装入共享库的虚拟地址与相对地址相加,计算对应的虚拟地址。此类型的重定位项必须为符号表索引指定值零。
计算符号的值与 GOT 的地址之间的差值。此重定位还指示链接编辑器创建全局偏移表。
与 R_386_PC32 类似,不同的是它在其计算中会使用 GOT 的地址。此重定位中引用的符号通常是 _GLOBAL_OFFSET_TABLE_,该符号还指示链接编辑器创建全局偏移表。
下表中列出的重定位是针对 x64 定义的。
表 7–16 x64: ELF 重定位类型
名称 |
值 |
字段 |
计算 |
---|---|---|---|
R_AMD64_NONE |
0 |
无 |
无 |
R_AMD64_64 |
1 |
word64 |
S + A |
R_AMD64_PC32 |
2 |
word32 |
S + A - P |
R_AMD64_GOT32 |
3 |
word32 |
G + A |
R_AMD64_PLT32 |
4 |
word32 |
L + A - P |
R_AMD64_COPY |
5 |
无 |
请参阅此表后面的说明。 |
R_AMD64_GLOB_DAT |
6 |
word64 |
S |
R_AMD64_JUMP_SLOT |
7 |
word64 |
S |
R_AMD64_RELATIVE |
8 |
word64 |
B + A |
R_AMD64_GOTPCREL |
9 |
word32 |
G + GOT + A - P |
R_AMD64_32 |
10 |
word32 |
S + A |
R_AMD64_32S |
11 |
word32 |
S + A |
R_AMD64_16 |
12 |
word16 |
S + A |
R_AMD64_PC16 |
13 |
word16 |
S + A - P |
R_AMD64_8 |
14 |
word8 |
S + A |
R_AMD64_PC8 |
15 |
word8 |
S + A - P |
R_AMD64_PC64 |
24 |
word64 |
S + A - P |
R_AMD64_GOTOFF64 |
25 |
word64 |
S + A - GOT |
R_AMD64_GOTPC32 |
26 |
work32 |
GOT + A + P |
其他重定位类型可用于线程局部存储引用。这些重定位类型将在第 8 章,线程局部存储中介绍。
大多数重定位类型的特殊语义与用于 x86 的语义相同。一些重定位类型的语义不只是简单的计算:
此重定位类型具有与 R_AMD64_GOT32 或等效 R_386_GOTPC 重定位类型不同的语义。x64 体系结构提供了相对于指令指针的寻址模式。因此,可以使用单个指令从 GOT 装入地址。
针对 R_AMD64_GOTPCREL 重定位类型进行的计算提供了 GOT 中指定了符号地址的位置与应用重定位的位置之间的差值。
计算出的值会截断为 32 位。链接编辑器可验证为重定位生成的值是否会使用零扩展为初始的 64 位值。
计算出的值会截断为 32 位。链接编辑器可验证为重定位生成的值是否会使用符号扩展为初始的 64 位值。
这些重定位类型不适用于 x64 ABI,在此列出是为了说明。R_AMD64_8 重定位类型会将计算出的值截断为 8 位。R_AMD64_16 重定位类型会将所计算的值截断为 16 位。