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

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

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

_dl_open() >> dl_open_worker() >> _dl_map_object() >> _dl_new_object()
2027 struct link_map *
2028 internal_function
2029 _dl_new_object (char *realname, const char *libname, int type,
2030 struct link_map *loader)
2031
2032 {
2033 struct link_map *l;
2034 int idx;
2035 size_t libname_len = strlen (libname) 1;
2036 struct link_map *new;
2037 struct libname_list *newname;
2038
2039 new = (struct link_map *) calloc (sizeof (*new) sizeof (*newname)
2040 libname_len, 1);
2041
………………..
2046
2047 new->l_name = realname;
2048 new->l_type = type;
2049 new->l_loader = loader;
2050
2051 new->l_scope = new->l_scope_mem;
2052 new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]);
2053
2054 if (GL(dl_loaded) != NULL)
2055 {
2056 l = GL(dl_loaded);
2057 while (l->l_next != NULL)
2058 l = l->l_next;
2059 new->l_prev = l;
2060 /* new->l_next = NULL; Would be necessary but we use calloc. */
2061 l->l_next = new;
2062
2063 /* Add the global scope. */
2064 new->l_scope[idx ] = &GL(dl_loaded)->l_searchlist;
2065 }
2066 else
2067 GL(dl_loaded) = new;
2068 GL(dl_nloaded);
………….
2080
2081 return new;
2082
2083 }

在2039行的内存分配是个把libname 和name的数据结构也一同分配,是一种零用整取的策略。从2043-2053行都是为struct link_map 的成员数据赋值。从2054-2067行则是把新的struct link_map* 加入到一个单链中,这是在以后是很有用的,因为这样在一个执行文档中假如要整体管理他相关的动态链接库,就能够以单链遍历。

假如要加载的动态链接库还没有被映射到进程的虚拟内存空间的话,那只是准备工作,真正的要点在 _dl_map_object_from_fd()这个函数开始的。因为这之后,每一步都有关动态链接库在进程中发挥他的作用而必须的条件。

这上段比较长,所以分段来看,


_dl_open() >> dl_open_worker() >> _dl_map_object() >> _dl_map_from_fd()
1391 struct link_map *
1392 _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
1393 char *realname, struct link_map *loader, int l_type,
1394 int mode)
1395
1396 {
1397
1398 struct link_map *l = NULL;
1399 const ElfW(Ehdr) *header;
1400 const ElfW(Phdr) *phdr;
1401 const ElfW(Phdr) *ph;
1402 size_t maplength;
1403 int type;
1404 struct stat64 st;
1405
1406 __fxstat64 (_STAT_VER, fd, &st);
…………
1413 for (l = GL(dl_loaded); l; l = l->l_next)
1414 if (l->l_ino == st.st_ino && l->l_dev == st.st_dev)
1415 {
……….
1418 __close (fd);
……………
1422 free (realname);
1423 add_name_to_object (l, name);
1424
1425 return l;
1426 }

这里先开始就要从再找一遍,假如找到了已有的struct link_map* 要加载的libname(的而比较的依据是他的和st_ino,这是物理文档在内存中编号,且文档的设备号st_dev相同,这是从比较底层来比较文档,具体的原因,您能够参看我将要发表的《从linux的内存管理看文档共享的实现》)。之所以采取这样再查一遍,因为假如进程从要开始打开动态链接库文档,走到这里可能要经过很长的时间(据我作的实验来看,对第一次打开的文档大概也就在200毫秒左右---------主要的时间是硬盘的寻道和读盘,但这对于电脑的进程而言已是很长的时间了。)所以,有可能别的线程已读入了这个动态链接库,这样就没有必要再做下去了。这和内核在文档的打开文档所用的思想是一致的。


_dl_open() >> dl_open_worker() >> _dl_map_object() >> _dl_map_from_fd()
1427
1428 /* This is the ELF header. We read it in `open_verify'. */
1429 header = (void *) fbp->buf;
1430
1431 l->l_entry = header->e_entry;
1432 type = header->e_type;
1433 l->l_phnum = header->e_phnum;
1434
1435 maplength = header->e_phnum * sizeof (ElfW(Phdr));
1436

这一段所作的为下面的ELF文档的分节映射入内存做一点准备(要读写phdr的数组)。


_dl_open() >> dl_open_worker() >> _dl_map_object() >> _dl_map_from_fd()
1438 /* Scan the program header table, collecting its load commands. */
1439 struct loadcmd
1440 {
1441 ElfW(Addr) mapstart, mapend, dataend, allocend;
1442 off_t mapoff;
1443 int prot;
1444 } loadcmds[l->l_phnum], *c;
1445 size_t nloadcmds = 0;

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