总结
R_386_NONE 0 none none
1.ld时重定位
1.1位置相关
1.1.1 R_386_32
R_386_32 1 word32 S + A //数据,绝对地址
符号的值即变量的地址,因此变量都需要重定位
如果变量的值是普通值,则不需对值重定位
如果变量的值是地址,则需对值重定位,例如char *="abc";
Offset Info Type Symbol's Value Symbol's Name
0000000b 00301 R_386_32 00000000 .data
00000010 00e02 R_386_PC32 00000000 printf
9: ff 35 00 00 00 00 pushl 0x0 //ff 35 将立即数压栈
f: e8 fc ff ff ff call 10 //e8 相对寻址
14: 83 c4 10 add $0x10,%esp
所以R_386_32都是对Offset处的地址值重定位
S即调整后的符号值(新的变量地址),A即原值(Offset处的地址值,需要重定位的地址)
1.1.2 R_386_PC32
R_386_PC32 2 word32 S + A - P//代码,相对地址
P即Offset
连接时,ld会合并相同的节,假设printf被安排的地址是x,1.o中.text节安排的地址是y
则x+(-4)-(y+10)=x-y-14,所以重定位的结果是x-y-14,
当cpu执行y+f:处的call指令时,ip指向y+14,则call的目标地址是ip+(x-y-14)=x
1.2 位置无关(PIC)
1.2.1 R_386_GOTPC
R_386_GOTPC 10 word32 GOT + A - P
GOT即GOT地址(符号_GLOBAL_OFFSET_TABLE_的值),A为Offset处值,P为Offset.
Offset Info Type Symbol's Value Symbol's Name
0000000f 00e0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_
00000018 00309 R_386_GOTOFF 00000000 .data
0000001d 00f04 R_386_PLT32 00000000 printf
7: e8 00 00 00 00 call c
c: 5b pop %ebx
d: 81 c3 03 00 00 00 add $0x3,%ebx
13: 83 ec 0c sub $0xc,%esp
16: ff b3 00 00 00 00 pushl 0x0(%ebx)
1c: e8 fc ff ff ff call 1d
call .L3
.L3:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L3], %ebx
subl $12, %esp
pushl )
call
1.2.2 R_386_GOTOFF
R_386_GOTOFF 9 word32 S + A - GOT//静态(局部)变量
将符号地址和GOT地址差值加上Offset处值存入Offset处.
1.2.3 R_386_GOT32
R_386_GOT32 3 word32 G + A - P//外部(全局)变量
G为符号在GOT中地址,A为Offset处值,P为Offset
1.2.4 R_386_PLT32
R_386_PLT32 4 word32 L + A - P//代码
L为符号在plt中的地址,A为Offset处值,P为Offset
2.执行时重定位
2.1 位置相关
2.1.1 R_386_32
2.1.2 R_386_PC32
2.2 位置无关
2.2.1 R_386_RELATIVE
R_386_RELATIVE 8 word32 B + A//局部变量
使用加载地址+Offset处值来重定位
Relocation section '.rel.dyn' at offset 0x330 contains 3 entries:
Offset Info Type Symbol's Value Symbol's Name
000013e8 00008 R_386_RELATIVE //字符串地址
000013ec 00008 R_386_RELATIVE //字符串地址
00001408 01006 R_386_GLOB_DAT 000013ec t
2.2.2 R_386_GLOB_DAT
R_386_GLOB_DAT 6 word32 S //外部全局在PIC so间共享,或PIC so共享可执行文件中的变量
S为调整后的符号值写入Offset处
对于本地全局变量,直接把调整后的符号值写入本地GOT
3b6: 8b 83 10 00 00 00 mov 0x10(%ebx),%eax//%eax中地址值指向.data节
3bc: ff 30 pushl (%eax)//将.data节中的变量值入栈
对于外部全局变量,解析该符号值(即变量地址),写入本地GOT<<<<<
2.2.3 R_386_COPY
R_386_COPY 5 none none//外部全局变量
可执行文件共享PIC so中变量,
由于所有的可执行文件都不需要重定位,所以为可执行文件共享动态
链接库中的全局变量单独设置这个属性,在本地的bss中分配空间,置
R_386_COPY定位类型,而不使用R_386_32定位类型(那样需使代码段可写,
且COW,耗费内存)
6.c
extern char * s;
extern int t;
1.c
char *s="abc";
int t=1;
6.o中
Relocation section '.rel.text' at offset 0x38c contains 5 entries:
Offset Info Type Symbol's Value Symbol's Name
0000000b 00901 R_386_32 00000000 s
00000010 00a02 R_386_PC32 00000000 printf
00000019 00b01 R_386_32 00000000 t
0000001e 00c02 R_386_PC32 00000000 g
00000024 00d01 R_386_32 00000004 u
Symbol table '.symtab' contains 14 entries:
Num: Value Size Type Bind Vis Ndx Name
9: 00000000 0 NOTYPE GLOBAL DEFAULT UND s
10: 00000000 0 NOTYPE GLOBAL DEFAULT UND printf
11: 00000000 0 NOTYPE GLOBAL DEFAULT UND t
12: 00000000 0 NOTYPE GLOBAL DEFAULT UND g
13: 00000004 4 OBJECT GLOBAL DEFAULT COM u
gcc 1.so 6.o -o 6
而可执行文件6中就变成了
Relocation section '.rel.dyn' at offset 0x3f4 contains 3 entries:
Offset Info Type Symbol's Value Symbol's Name
080496b0 01006 R_386_GLOB_DAT 00000000 __gmon_start__
08049784 00105 R_386_COPY 08049784 t
08049788 00905 R_386_COPY 08049788 s
1: 08049784 4 OBJECT GLOBAL DEFAULT 22 t
9: 08049788 4 OBJECT GLOBAL DEFAULT 22 s
可见s,t的Ndx不是UND,而是位于.bss中
将解析到的符号地址处的值(大小由size决定)复制到Offset处。
而同时so的GOT中该变量的地址值被改写成可执行文件中的地址
R_386_COPY read a string of bytes from the "symbol" address
and deposit a copy into this dword; the "symbol" object
contains the length; this is used to copy initialized data
from a library to the main app data space
On i386 the most important ones are the R_386_COPY type,
meaning "just copy the address of the symbol to that address"
2.2.4 R_386_JMP_SLOT
R_386_JMP_SLOT 7 word32 S//代码
其他:
1.如果文件使用了动态链接库,则该文件就有GOT
2.GOT中的信息
[root@proxy ~/3]# objdump -sj .got 6
6: file format elf32-i386
Contents of section .got:
804968c b4960408 00000000 00000000 6a840408 ............j...
804969c 7a840408 8a840408 9a840408 aa840408 z...............
80496ac ba840408 00000000
GOT[0]是.dynsym节的地址
[20] .dynamic DYNAMIC 080496b4 0006b4 0000d0 08 WA 5 0 4
GOT[1]是动态链接库自身的struct link_map*的指针
GOT[2]是_dl_runtime_resolve的地址
GOT[3]..,函数 解析前指向.plt中,解析后执行真正的函数地址
变量加载时解析,指向全局变量地址
3.plt
位置相关:
08048454 <.plt>:
8048454: ff 35 90 96 04 08 pushl 0x8049690
804845a: ff 25 94 96 04 08 jmp *0x8049694
8048460: 00 00 add %al,(%eax)
8048462: 00 00 add %al,(%eax)
8048464: ff 25 98 96 04 08 jmp *0x8049698
804846a: 68 00 00 00 00 push $0x0
804846f: e9 e0 ff ff ff jmp 8048454 <_init+0x18>
8048474: ff 25 9c 96 04 08 jmp *0x804969c
804847a: 68 08 00 00 00 push $0x8
804847f: e9 d0 ff ff ff jmp 8048454 <_init+0x18>
8048484: ff 25 a0 96 04 08 jmp *0x80496a0
PIC:
00000370 <.plt>:
370: ff b3 04 00 00 00 pushl 0x4(%ebx)
376: ff a3 08 00 00 00 jmp *0x8(%ebx)
37c: 00 00 add %al,(%eax)
37e: 00 00 add %al,(%eax)
380: ff a3 0c 00 00 00 jmp *0xc(%ebx)
386: 68 00 00 00 00 push $0x0
38b: e9 e0 ff ff ff jmp 370
其中push $0x0是符号在rel节中的索引数0(字节偏移)