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

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

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

这里把数据结构定义在函数内部,能确保这是个局部变量定义,和面向对象中的private的效果是相同的。


_dl_open() >> dl_open_worker() >> _dl_map_object() >> _dl_map_from_fd()
1448 for (ph = phdr; ph < &phdr[l->l_phnum]; ph)
1449 switch (ph->p_type)
1450 {
………..
1454 case PT_DYNAMIC:
1455 l->l_ld = (void *) ph->p_vaddr;
1456 l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
1457 break;
1458
1459 case PT_PHDR:
1460 l->l_phdr = (void *) ph->p_vaddr;
1461 break;
1462
1463 case PT_LOAD:
…………..
1467 c = &loadcmds[nloadcmds ];
1468 c->mapstart = ph->p_vaddr & ~(ph->p_align - 1);
1469 c->mapend = ((ph->p_vaddr ph->p_filesz GL(dl_pagesize) - 1)
1470 & ~(GL(dl_pagesize) - 1));
1471 c->dataend = ph->p_vaddr ph->p_filesz;
1472 c->allocend = ph->p_vaddr ph->p_memsz;
1473 c->mapoff = ph->p_offset & ~(ph->p_align - 1);
…………..
1480 c->prot = 0;
1481 if (ph->p_flags & PF_R)
1482 c->prot |= PROT_READ;
1483 if (ph->p_flags & PF_W)
1484 c->prot |= PROT_WRITE;
1485 if (ph->p_flags & PF_X)
1486 c->prot |= PROT_EXEC;
1488 break;
…………
1493 }

在ELF文档的规范中,根据不同的program header 不同,要实现不同的功能,采用不同的处理策略,具体的内容请参看附录2 中的说明。这里没有出现一般的default 但实际运行和下面的语句是等价的:


default:
continue;

真是达到程式简洁的特点。

但有一个特别要指出的是PT_LOAD的那些,把任何的能够加载的节都在加载的数据结构中loadcmds中构建完成,是个好的想法。特别是指针的妙用,值得学习(1467 c = &loadcmds[nloadcmds ];)。


_dl_open() >> dl_open_worker() >> _dl_map_object() >> _dl_map_from_fd()
1498 c = loadcmds;
…………
1501 maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart;
1502
1503 if (__builtin_expect (type, ET_DYN) == ET_DYN)
1504 {
…………….
1521 l->l_map_start = (ElfW(Addr)) __mmap ((void *)0, maplength,
1522 c->prot, MAP_COPY | MAP_FILE,
1523 fd, c->mapoff);
1524
1525 l->l_map_end = l->l_map_start maplength;
1526 l->l_addr = l->l_map_start - c->mapstart;
………..
1535 __mprotect ((caddr_t) (l->l_addr c->mapend),
1536 loadcmds[nloadcmds - 1].allocend - c->mapend,
1537 PROT_NONE);
1538
1539 goto postmap;
1540 }

在1521-1526行之间就是把整个文档都进行了映射,妙处在1498行和1501行,是把头和尾的两个PT_LOAD program header 的内容都计算在内了。而1503行就是我们这里的情景,因为这是动态链接库的加载。而1535行的修改虚拟内存的属性,就是把映射在最高地址的空白失效。这是一种保护。为了防止有人利用这里大做文章。


_dl_open() >> dl_open_worker() >> _dl_map_object() >> _dl_map_from_fd()
1546 while (c < &loadcmds[nloadcmds])
1547 {
1548
1549 postmap:
1550 if (l->l_phdr == 0
1551 && (ElfW(Off)) c->mapoff <= header->e_phoff
1552 && ((size_t) (c->mapend - c->mapstart c->mapoff)
1553 >= header->e_phoff header->e_phnum * sizeof (ElfW(Phdr))))
……
1555 l->l_phdr = (void *) (c->mapstart header->e_phoff - c->mapoff);
1556
1557 if (c->allocend > c->dataend)
1558 {
………..
1561 ElfW(Addr) zero, zeroend, zeropage;
1562
1563 zero = l->l_addr c->dataend;
1564 zeroend = l->l_addr c->allocend;
1565 zeropage = ((zero GL(dl_pagesize) - 1)
1566 & ~(GL(dl_pagesize) - 1));
1567
1568 if (zeroend < zeropage)
……….
1571 zeropage = zeroend;
1572
1573 if (zeropage > zero)
1574 {
…….
1576 if ((c->prot & PROT_WRITE) == 0)
1577 {
1578 /* Dag nab it. */
1579 __mprotect ((caddr_t) (zero & ~(GL(dl_pagesize)
1580 - 1)), GL(dl_pagesize),
1581 c->prot|PROT_WRITE) < 0);
1582
1583 }
1584 memset ((void *) zero, '', zeropage - zero);
1585 if ((c->prot & PROT_WRITE) == 0)
1586 __mprotect ((caddr_t) (zero & ~(GL(dl_pagesize) - 1)),
1587 GL(dl_pagesize), c->prot);
1588 }
1589
1590 if (zeroend > zeropage)
1591 {
……..
1593 caddr_t mapat;
1594 mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage,
1595 c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
1596 ANONFD, 0);
1597
1598 }
1599 }
1600
1601 c;
1602 }

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