这就是对已被打开了的,就对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
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!