没有合适的资源?快使用搜索试试~ 我知道了~
Intel平台下linux中ELF文件动态链接的加载、解析及实例分析(二)-函数解析与卸载1
需积分: 0 2 下载量 191 浏览量
2022-08-08
23:09:17
上传
评论
收藏 156KB DOCX 举报
温馨提示
试读
20页
50 51 }先说明,其实加载一个动态链接库的依赖动态链接库不是一件简单的事,因为所有的动态链接库可能还有它自己所依赖的动态链
资源详情
资源评论
资源推荐
Intel 平台下 linux 中 ELF 文件动态链接的加载、解
析及实例分析(二): 函数解析与卸载
级别: 中级
王瑞川 (jeppeterone@163.com), linux 爱好者
2003 年 12 月 01 日
上篇文章 Intel 平台下 Linux 中 ELF 文件动态链接的加载、解析及实例分析(一): 加载阐述了 ELF 文件
被加载的时候所经历的一般过程。那我们现在就来解决在上一篇文章的最后所提到的那几个问题,以及那
些在 dl_open_worker 中没有讲解的代码。
相信读者已经看过了 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 这样的有条件转
移指令和无条件转移指令)。然而,如果讲到动态链接库的链接实现则一定要提到这一内容。
所谓相对转移,就是这个二进制代码的中的它是可以在重定位的环境中不经修改,就可以运行的。如下面
的情况,
719: e9 e2 fe ff ff jmp 600 <loop_put_buffer>
变成一般的地址是这样的
movl %eip,%eax
addl $0xfffffee2,%eax
movl %eax,%eip
这里旁边的 719 就是这个 ELF 文件与起始地址相比的偏移量,而在里面的 e9 e2 fe ff ff 如果写成看的往
后退 0x11e 因为这是 ff ff fe e2(intel 是 little endian 表示方法)所表示的 -0x11e 的数。如果把
719 加上 5 再减去 600 就是这个数了。这便是处理器的相对转移。
还有另一种转移方式,就是绝对转移。
2b6: ff d0 call *%eax
剩余19页未读,继续阅读
高工-老罗
- 粉丝: 19
- 资源: 314
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0