手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>网站运营>建站经验>列表

Intel平台下linux中 ELF文档动态链接的加载、解析及实例分析(二): 函数解析和卸载

来源:互联网 作者:west263.com 时间:2008-04-16
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!

Relocation section '.rel.plt' at offset 0x2c8 contains 1 entries:
Offset Info Type Symbol's Value Symbol's Name
000013b8 00000e07 R_386_JUMP_SLOT 00000000 printf

这个值假如在文档中找到0x13b8(这是相对偏移量)的内容就是


13b8: e6 02


由于intel 是little endian 所以这个数翻译过来是0x02e6,那这里是什么呢?


2e0: ff a3 0c 00 00 00 jmp *0xc(離)
2e6: 68 00 00 00 00 push x0
2eb: e9 e0 ff ff ff jmp 2d0

这下就会全部明白了吧。他就是压入0x0(这其实就是我们前面的printf在rel节中的索引数0------他是第一项)。而下面跳到的就是2d0(这是个相对转移)处


2d0: ff b3 04 00 00 00 pushl 0x4(離)
2d6: ff a3 08 00 00 00 jmp *0x8(離)

前面已说过離得到的是got的起始地址,所以这就是压got[1]入栈,再转移到got[2]中所包含的地址去,您能够看前面在elf_machine_runtime_setup中的2162行和2167行,他就是这个动态链接库自身的struct link_map*的指针,和_dl_runtime_resolve所在的地址。下面一张图就能够形象的说明这一点。

假如是第一次的函数调用,他所走的路线就是我在上图中用红线标出的,而要是在第二次以后调用,那就是蓝线所标明的。原因在前面的代码中已给出了。


82 int _dl_relocate_object (struct link_map* lmap,int lazy_mode)
83 {
84 elf_machine_runtime_setup(lmap,lazy_mode);
85 elf_machine_lazy_rel (lmap,lazy_mode);
86
87 }

这里要分两步来完成,第一步的elf_machine_runtime_setup是把这个动态链接库所代表的数据结构lmap的地址写入一个在ELF文档中特别地方,而elf_machine_lazy_rel是对任何的要被调用的动态链接库外部的函数重定位的实现。这两步很重要,因为假如没有这两步,那要实现动态链接库的函数动态解析是不可能的,这个您能够在上面的 相对转移,绝对转移 中的论述得到周详的了解。


54 void elf_machine_runtime_setup(struct link_map* lmap,int lazy_mode)
55 {
56 Elf32_Addr *got;
57
58 got = (Elf32_Addr *) lmap->l_info[DT_PLTGOT].d_un.d_ptr;
59
60 got[2]=&_dl_runtime_resolve
61 got[1]=lmap;
62 }

明显的,那个被写入的ELF文档中的地址就是他的DT_PLTGOT节中的第二个项目-----第60行的内容。而写入第一项的内容就是要调动的处理函数的地址,这一点在后面所提到的动态解析中的入口地址。


64 void elf_machine_lazy_rel (struct link_map* lmap,int lazy_mode)
65 {
66 Elf32_Addr rel_addr=lmap->l_info[DT_REL].d_un.d_ptr;
67 int rel_num=lmap->l_info[DT_RELSZ].d_un.d_ptr;
68 int i;
69 Elf32_Addr l_addr=lmap->l_addr;
70
71 Elf32_Rel* rel;
72 for (i=0,rel=(Elf32_Rel*)rel_addr;i
73 {
74 Elf32_Addr *const reloc_addr = (void *) (l_addr rel->r_offset);
75 *reloc_addr =l_addr;
76 }
77
78 }

这里的elf_machine_lazy_rel我只列出了在intel平台下的那种情况,其他的还要特别的内容,在这里很明显,我们只是写把原来的在ELF文档的内容加上一个文档加载的地址,这就是lazy mode,因为动态链接库的函数很可能在整个程式运行中不会被调用--------这一点和虚拟内存管理的原理是相同的。

四、动态链接库函数的解析

前面的60行的代码----设定了动态解析的入口地址和给出的在动态链接库中的在达到调用一个外部函数时任何的函数路线,已到了 _dl_runtime_resolve处


2087 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("
2088 .text

2089 .globl _dl_runtime_resolve

2090 .type _dl_runtime_resolve, @function

2091 .align 16

2092 _dl_runtime_resolve:

2093 pushl 陎

2094 pushl 靫

2095 pushl 韝

2096 movl 16(%esp), 韝

2097 movl 12(%esp), 陎

2098 call fixup

2099 popl 韝

2100 popl 靫

2101 xchgl 陎, (%esp)

2102 ret
2103 .size _dl_runtime_resolve, .-_dl_runtime_resolve

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!