2104
2105 ");
从这里定义的名称ELF_MACHINE_RUNTIME_TRAMPOLINE,我们就能够看出这个函数不简单(TRAMPOLINE在英语中是蹦床的意思,就是要make your brain curving的那种怪怪的东西),后面的代码也确实说明了这一点。
在前面的.text是下面的代码是可执行,.globl _dl_runtime_resolve是表明这个函数是全局性的,假如没有这一项,那我们前面看的got[2]=& _dl_runtime_resolve就不能编译通过-----编译器可能很难找到他的定义。.type _dl_runtime_resolve, @function是函数说明。 .align 16处便是16字节对齐。
我们知道在前面的调用函数过程中已压入了两个参数(第一个是动态链接库的struct link_map* 指针,另一个是rel的索引值)这里先保存以前的寄存器值,而到这个时候16(%esp)就是第二个参数,12(%esp)第一个参数,这里作的原因是下面的fixup的函数以寄存器传递参数。
我先不管fixup具体内容是什么,单就看他结束的内容就很能说明代码作者的优秀。先pop两个寄存器的值,而又xchg 陎,(%esp)和栈顶的内容,这有两个目的,一是恢复了eax的值,另一个作用是栈顶是函数返回的地址,而fixup返回的eax就是我们想找的函数有内存中的地址。这就自然跳到那个地方去了。但假如您认为这就好了,那也错了,因为您不要忘记我们之前还压入了两个参数在栈中。所以用了ret ,这在intel的指令中表示
的组合。(很出色!!!!!!!)
您还能够参看《程式的链接和装入及Linux下动态链接的实现》 网址为 http://www-900.ibm.com/developerWorks/cn/linux/l-dynlink/index.shtml 里面的有一幅图正好说明此的ELF_MACHINE_RUNTIME_TRAMPOLINE。
那直接看fixup函数的内容
124 Elf32_Addr fixup(struct link_map* lmap,Elf32_Word reloc_offset) 125 { 126 Elf32_Sym* symtab=lmap->l_info[DT_SYMTAB].d_un.d_ptr; 127 char* strtab=lmap->l_info[DT_STRTAB].d_un.d_ptr; 128 Elf32_Rel* reloc = (Elf32_Rel*) (lmap->l_info[DT_JMPREL].d_un.d_ptr reloc_offset); 129 Elf32_Sym* sym=&symtab[Elf32_R_SYM(reloc->r_info)]; 130 char* symname=sym->st_name strtab; 131 Elf32_Addr reloc_addr=lmap->l_addr reloc->r_offset; 132 133 Elf32_Addr symaddr=0; 134 135 136 137 symaddr=do_lookup(lmap,symname); 138 139 140 141 if (symaddr>0) 142 { 143 *reloc_addr=symaddr; 144 return symaddr; 145 } 146 147 exit(-2); 148 149 150 151 152 153 }
|
这里是给出了从一个动态链接库中可重定向的reloc_offset得到要解析函数的名称,假如用图示的方式表示就如下图:

您可能会想:其实还能够用另一种方法,就是把这个reloc sym的st_value直接写入前面的这个调用重定向函数相对应的got中。这样解析时的速度会更快。但现实这样却可能对整个ELF文档结构体系带来很大的麻烦。我将对每一点说明:
- 假如是这个reloc sym的地址,那对于一个动态链接库而言,他的加载地址本身就是动态确定的。
- 假如用的是那个Elf32_Sym的st_value地址,那倒是能够和lmap->l_i nfo[DT_STRTAB]一起得到这个sym的name,但假如考虑到在编译的时候有些函数是只对本模块有效,可见的,如在一个文档中定义为 static的函数,则他就是局部可见的,那个时候就不可能是解析为这个函数,而且对c 函数更有更为复杂的情况,这样就会需要一个字段来表示他的属性,这就是要有了st_info这个数据成员变量。这也就要有了sym的参和了。
- 光有Elf32_Sym还是不行,因为就重定位而言他本身更有一点信息,就是这一个relocation symbol是在本地解析,还是在另外一个真正意义上的动态链接库内被解析,这一情况主要是发生在几个文档编写的模块中,他们编写的一些函数就在链接的时候被确定了,而另一些则没有,区分的就是relocation 中的r_info了。
从上面的分析来看,一种规范的设计有许多的考虑因素,假如只单一的考虑,那是不行的,特别是要对多个操作系统和平台统一的规范,不能因为就是考虑效率一条就能够了。
在143行是对前面要重定位的函数实现真正的解析函数到位,这样在这个函数被再次调用的时候就不用再来一次了,本来这时就对这个 relocation symbol r_info的判断,现在都已略去了。
真正的解析在do_lookup中实现了,我这里还是他的实现伪代码:
90 Elf32_Addr do_lookup(struct link_map* lmap,char* symname) 91 { 92 struct link_map* search_lmap=NULL; 93 Elf32_Sym* symtab; 94 Elf32_Sym* sym; 95 char* strtab; 96 char* find_name; 97 int symindx; 98 99 Elf32_Word hash=elf_hash_name(symname); 100 for_each_search_lmap_in_search_list(lmap,search_lmap) 101 { 102 symtab=search_lmap->l_info[DT_SYMTAB].d_un.d_ptr; 103 strtab=search_lmap->l_info[DT_STRTAB].d_un.d_ptr; 104 for (symindx=search_lmap->l_buckets[hash % search_lmap->l_nbuckets]; 105 symindx!=0;symindx=search_lmap->l_chain[symindx]) 106 { 107 sym=&symtab[symindx]; 108 109 find_name=strtab sym->st_name; 110 if (strcmp(find_name,symname)==0) 111 return sym->st_value search_lmap->l_addr; 112 } 113 114 return 0; 115 116 117 118 } 119 }
文章整理:西部数码--专业提供域名注册、虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!
| | 版权所有 西部数码(www.west263.com)
CopyRight (c) 2002~2007 west263.com all right reserved.
公司地址:四川成都市万和路90号天象大厦4楼 邮编:610031
电话总机:028-86263408 86263960 86264018 86267838 86262244 86263408 售前咨询:总机转201 202 203 204 205 206 207 208 售后服务:总机转211
212 213 214 217 218 晚上0点以后拔分机225 |
| 财务咨询:总机转224
223 传真:028-86264041 财务QQ: 635483282
售前咨询QQ: 327314358 241975952 275026793 408235859 2182518 499513144 售后服务QQ: 634349278 809071471 307742704 512359778 287976517 363783715 在线咨询
《中华人民共和国增值电信业务经营许可证》编号:川B2-20030065号
|
|