地址。
GOT表的格式和解释是处理器相关的。在32位Intel体系结构下,标号
_GLOBAL_OFFSET_TABLE_可能被用来访问该表。
Figure 2-11: Global Offset Table
extern Elf32_Addr _GLOBAL_OFFSET_TABLE_[];
标号_GLOBAL_OFFSET_TABLE_可能驻留在.got section的中间,允许负的和非负
的下标索引这个数组。
Procedure Linkage Table(PLT过程连接表)
就象GOT重定位把位置无关的地址计算成绝对地址相同,PLT过程连接表重定位
位置无关的函数调用到绝对的地址。从一个可执行或共享的object文档到另外的,
连接编辑器不解析执行的传输(例如函数的调用)。因此,连接编辑器安排程式
的传递控制到PLT中的入口。在SYSTEM V体系下,PLT存在共享文本中,但是他们
使用的地址是在私有的GOT中。符号连接器决定了目标的绝对地址并且修改GOT的
内存映象。因此,在没有危及到位置无关、程式文本的共享能力的情况下。动态
连接器能重定位人口。
Figure 2-12: Absolute Procedure Linkage Table
绝对的过程连接表
.PLT0:pushl got_plus_4
jmp *got_plus_8
nop; nop
nop; nop
.PLT1:jmp *name1_in_GOT
pushl $offset
jmp .PLT0@PC
.PLT2:jmp *name2_in_GOT
pushl $offset
jmp .PLT0@PC
...
Figure 2-13: Position-Independent Procedure Linkage Table
位置无关(或说位置单独)的过程连接表
.PLT0:pushl 4(離)
jmp *8(離)
nop; nop
nop; nop
.PLT1:jmp *name1@GOT(離)
pushl $offset
jmp .PLT0@PC
.PLT2:jmp *name2@GOT(離)
pushl $offset
jmp .PLT0@PC
...
注意:如图所示,PLT的指令使用了不同的操作数地址方式,对绝对代码和
对位置无关的代码。但是,他们的界面对于动态连接器是相同的。
以下的步骤,动态连接器和程式协作(cooperate)通过PLT和GOT来解析符号
引用。
1. 当第一次创建程式的内存映象时,动态连接器为在GOT中特别的变量配置
第二次和第三次的入口。下面关于那些变量有更多的解释。
2. 假如PLT是位置无关的,那么GOT的地址一定是保留在離中的。每个在进程
映象中共享的object文档有他自己的PLT,并且仅仅在同一个object文档中,
控制传输到PLT入口。从而,要调用的函数有责任在调用PLT入口前,配置PLT
地址到寄存器中。
3. 举例说明,假如程式调用函数name1,他的传输控制到标号.PLT1.
4. 第一个指令跳到在GOT入口的name1地址。初始话时,GOT保存着紧跟着的push1
指令的地址,而不是真实的name1的地址。
5. 因此,程式在堆栈中压入(push)一个重定位的偏移量。重定位的偏移量是
一个32位,非负的字节偏移量(从定位表算起)。指派的重定位入口将是
一个R_386_JMP_SLOT类型,他的偏移量指明了GOT入口(在前面的jmp指令中
被使用)。该重定位入口也包含一个符号表的索引,因此告诉动态连接器
哪个符号要被引用,在这里是name1。
6. 在压入(push)一个重定位的偏移量后,程式跳到.PLT0,在PLT中的第一个入口。
push1指令在堆栈中放置第二个GOT入口(got_plus_4 or 4(離))的值,
因此,给动态连接器一个word的鉴别信息。然后程式跳到第三个GOT入口
(got_plus_8 or 8(離)),他传输控制到动态连接器。
7. 当动态连接器接到控制权,他展开堆栈,查看指派的重定位入口,寻找符号的
值,在GOT入口中存储真实的name1地址,然后传输控制想要目的地。
8. PLT入口的并发执行将直接传输控制到name1,而不用第二次调用动态连接器
了。所以,在.PLT1中的jmp指令将转到name1,代替“falling through”
转到pushl指令。
LD_BIND_NOW环境变量能改变动态连接器的行为。假如这个变量为非空,动态
连接器在传输控制到程式前计算PLT入口。换句话说,动态连接器处理重定位
类型为R_386_JMP_SLOT的入口在进程初始化时。否则,动态连接器计算PLT入口
懒惰的,推迟到符号解析和重定位直到一个表入口的第一次执行。
注意:一般来说,以懒惰(Lazy)方式绑定是对全应用程式执行的改进。
因为不使用的符号就不会招致动态连接器做无用功。然而,对一些应用程式,
两种情况使用懒惰(Lazy)方式是不受欢迎的。
第一 初始的引用一个共享object函数比后来的调用要花的时间长,因为动
态连接器截取调用来解析符号。一些应用程式是不能容忍这样的。
第二 假如这个错误发生并且动态连接器不能解析该符号,动态连接器将终止
程式。在懒惰(Lazy)方式下,这可能发生在任意的时候。一再的,一
些应用程式是不能容忍这样的。通过关掉懒惰(Lazy)方式,在应用程
序接到控制前,当在处理初始话时发生错误,动态连接器强迫程式,使
之失败。
Hash Table(哈希表)
Elf32_Word object的哈希表支持符号表的访问。
标号出现在下面帮助解释哈希表的组织,但是他们不是规范的一部分。
Figure 2-14: Symbol Hash Table
nbucket
nchain
bucket[0]
...
bucket[nbucket - 1]
chain[0]
...
chain[nchain - 1]
bucket数组包含了nbucket入口,并且chain数组包含了nchain个入口;索引从0开始。
bucket和chain保存着符号表的索引。Chain表入口类似于符号表。符号表入口的
数目应该等于nchain;所以符号表的索引也选择chain表的入口。
文章整理:西部数码--专业提供域名注册、虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!




