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

Intel平台下Linux中 ELF文档动态链接的加载、解析及实例分析(一): 加载

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

这就是对已被打开了的,就对l_opencount加一返回了。但为什么要在2551行之后作出这一判断呢,那是在下面的代码有关, _dl_map_object_deps会把l_searchlist加载入。


_dl_open() >> dl_open_worker()

2565 /* Load that object's dependencies. */
2566 _dl_map_object_deps (new, NULL, 0, 0, mode & __RTLD_DLOPEN);
……………
2573 l = new;
2574 while (l->l_next)
2575 l = l->l_next;
2576 while (1)
2577 {
2578 if (! l->l_relocated)
2579 {
2580 _dl_relocate_object (l, l->l_scope, lazy, 0);
2581 }
2582
2583 if (l == new)
2584 break;
2585 l = l->l_prev;
2586 }

在这里的_dl_map_object_deps会填充l_searchlist.r_list,对于这个函数和下面的 _dl_relocate_object由于和函数的解析关系比较大,所以我放在《Intel平台下linux中ELF文档动态链接的加载、解析及实例分析(中)-----------函数解析和卸载篇》讲解。但能够把这个当作这个新加载的动态链接库的所依赖的动态链接库的struct link_map* 放入这个指针的列表中(就是l_search_list中),_dl_relocate_object是对这个动态链接库中的函数重定位,而这里用的,这里之所以用的是while (1) 2576行,是因为在前面用的_dl_map_object_deps会把这个动态链接库所依赖的动态链接库也加载进来,这其中就会有没有重定位的。


_dl_open() >> dl_open_worker()
2592 for (i = 0; i < new->l_searchlist.r_nlist; i)
2593 if ( new->l_searchlist.r_list[i]->l_opencount > 1
2594 && new->l_searchlist.r_list[i]->l_type == lt_loaded)
2595 {
2596 struct link_map *imap = new->l_searchlist.r_list[i];
2597 struct r_scope_elem **runp = imap->l_scope;
2598 size_t cnt = 0;
2599
2600 while (*runp != NULL)
2601 {
…………
2605 if (*runp == &new->l_searchlist)
2606 break;
2607
2608 cnt;
2609 runp;
2610 }
2611
2612 if (*runp != NULL)
2613 /* Avoid duplicates. */
2614 continue;
…………
2642 imap->l_scope[cnt ] = &new->l_searchlist;
2643 imap->l_scope[cnt] = NULL;
2644 }

这段代码假如从实现功能上来讲是很简单的,就是在我们刚新加入的动态链接库new中的l_searchlist中(这些都是在前面被 dl_object_deps加载入的被依赖的动态链接库数组)imap->l_scope查找,假如里面runp有&new-> l_searchlist,就不用对原来的imap->l_scope扩充了,但假如没有就要完成2616到2644行的扩充工作。

但在这之后的背景原因,却是&new->l_searchlist其实就是new本身。在一般情况下,假如这个依赖的动态链接库在new被加载之前已加载(具体的原因会在下一篇文章关于动态链接库函数解析中说明),那就会碰到这种情况。而我们又不能确保两个动态链接库之间的互相依赖情况的发生,如下图,那这里的解决办法便是个补救措施了。



_dl_open() >> dl_open_worker()
2647 _dl_init (new, __libc_argc, __libc_argv, __environ);

这是要调用动态链接库自备的初始函数。这有点类似和insmod时调用的init_module的内容。至于这其中所传递的 __libc_argc, __libc_argv, __environ三个参数是在您的可执行文档被运行的时候由bash引入的输入参数和环境变量,一般的动态链接库是没有什么用处了。


_dl_open() >> dl_open_worker() >> _dl_init()
1118 void
1119 internal_function
1120 _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
1121 {
1122
1123 ElfW(Dyn) *preinit_array = main_map->l_info[DT_PREINIT_ARRAY];
1124 ElfW(Dyn) *preinit_array_size = main_map->l_info[DT_PREINIT_ARRAYSZ];
1125 unsigned int i;
1126
1127
1128 ElfW(Addr) *addrs;
1129 unsigned int cnt;
1130
1131
1132 addrs = (ElfW(Addr) *) (preinit_array->d_un.d_ptr main_map->l_addr);
1133 for (cnt = 0; cnt < i; cnt)
1134 (init_t) addrs[cnt]) (argc, argv, env);
………….
1146 i = main_map->l_searchlist.r_nlist;
1147 while (i-- > 0)
1148 call_init (main_map->l_initfini[i], argc, argv, env);
1149
1150
1151
1152
1153 }

先是调用 DT_PREINIT的内容,这是在init之的init方法。我想这个之所以要实现,不光是为让动态链接库的研发者有更好的研发接口,而且还是在以他所依赖的动态链接库之前进行一些初始化工作,借鉴于面向对象的构造函数。

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