转载自:IBM developerWorks 中国网站
王瑞川(jeppeterone@163.com)
从事 Linux 研发工作
2003 年 12 月
相信读者已看过了Intel平台下Linux中 ELF文档动态链接的加载、解析及实例分析(一): 加载的内容了,了解了ELF文档被加载的时候所经历的一般过程。那我们现在就来解决在上一篇文章的最后所提到的那几个问题,连同那些在dl_open_worker中没有讲解的代码。
一、_dl_map_object_deps 函数分析
由于源代码过分的冗长,并且由于效率的考虑,使原本很简单的代码变成了一件 TRAMPOLINE 的事情,所以我对他进行了大幅度的改变,不但删除了任何不必要的代码,而且还用伪代码来展现他最初的设计思想。
13 _dl_map_object_deps (struct link_map *lmap) 14 15 { 16 17 struct list_head* add_list; 18 char* load_dl_name; 19 struct link_map* curlmap; 20 Elf32_Dyn* needed_dyn; 21 struct link_map* new_lmap; 22 int lmap_count=1; 23 24 add_lmap_to_list(lmap,add_list); 25 26 for_each_in_list(add_list,curlmap) 27 { 28 for_every_DT_NEEDED_section(curlmap,needed_dyn) 29 { 30 load_dl_name= get_needed_name(curlmap,needed_dyn); 31 32 new_lmap=_dl_map_object(load_dl_name); 33 34 35 add_to_list_tail_uniq(add_list,new_lmap); 36 } 37 } 38 39 lmap_count=count_the_list(lmap); 40 41 lmap->l_initfini=(struct link_map**)malloc ((2*lmap_count 1)*(struct link_map*)); 42 43 lmap->l_searchlist.r_list=&lmap->l_initfini[lmap_count 1]; 44 lmap->l_searchlist.r_nlist=lmap_count; 45 46 47 copy_each_add_list_to_searchlist(lmap,add_list,lmap_count); 48 49 free_the_add_list(add_list); 50 51 }
|
先说明,其实加载一个动态链接库的依赖动态链接库不是一件简单的事,因为任何的动态链接库可能更有他自己所依赖的动态链接库,假如采用递归简单方法实现不但是不可能的-----因为您能够参看第一篇的文章,那里提到了一个在加载动态链接库中的加锁问题,而且也是没有必要的,您并不能确保这样的动态链接库依赖关系会不会形成一个依赖循环,就像下面的一张图所显示的那样:

这样最简单的想法就是我们不重复的加载任何的动态链接库,这里就用一个单链实现-----在原来的程式中也是用这个方法,但那里用来分配的方法是在栈中直接实现,这样能够加快程式的运行,但程式可读性大大减弱了。
23 行就首先就把 lmap 自己加入这个 struct list 中去,在 26 行的 for_each_in_list(add_list,curlmap) 其实是就是把 curlmap=curlmap->next,并判断他的 curlmap!=NULL,
28 行的 for_every_DT_NEEDED_section(curlmap,needed_dyn)
主要就是 needed_dyn=curlmap->l_info[DT_NEEDED]; 但这里要注意的是,在一个动态链接库中可能有不只一个,就像在 readelf -a 的例子
Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libstdc -libc6.2-2.so.3] 0x00000001 (NEEDED) Shared library: [libm.so.6] 0x00000001 (NEEDED) Shared library: [libc.so.6]
|
更确切的是要在 lmap-> l_ld 的 dynamic section 中查找他的 d_tag 为 DT_NEEDED 中
30 行的 get_needed_name 用的方法是这样的
load_dl_name=curlmap->l_addr need_dyn->d_un.d_ptr curlmap->l_i nfo[DT_STRTAB];
|
很明显这里就会把这个动态链接库映射来完成他的加载,而 35 行是要把 add_list 扩充,这里只会对同一个动态链接库加载一次,所以不会有前面的循环加载,再回过头来看 26 行到 37 行之间的那个循环,假如在 35 行中加入了那个没有重复的动态链接库。那整个循环就可能继续循环下去。
从 39 行到 51 行之中就把这个函数中已得到的依赖动态链接库 copy 入 l_searchlist 和 l_initfini 这两个的重要数组中, 巧妙的是他们采用了一起分配的。最后前面的那个临时单链表。
二、相对转移,绝对转移
在学习汇编语言的时候,我们对不同的寻址方式肯定有很深的印象。但对于在汇编语言中同样重要的转移指令,只是一笔带过(用到了call 和 jxx ----------- 这里的 jxx 是指如 jmp jae jbe 这样的有条件转移指令和无条件转移指令)。然而,假如讲到动态链接库的链接实现则一定要提到这一内容。
所谓相对转移,就是这个二进制代码的中的他是能够在重定位的环境中不经修改,就能够运行的。如下面的情况,
文章整理:西部数码--专业提供域名注册、虚拟主机服务
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号
|