免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1954 | 回复: 2
打印 上一主题 下一主题

[内核入门] 关于load_elf_library 函数的一点疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-08-16 12:52 |只看该作者 |倒序浏览

关于linux 系统中用户进程的加载和执行过程,想必坛子中的弟兄们都比较了解了,如果不了解,可以参考这篇文章
http://bbs.chinaunix.net/thread-1929850-1-1.html  ,毛兄这篇文章比较详细的介绍了elf格式的进程加载和执行,
但是关于连接解释器如何加载共享库没有详细介绍,由于linux 共享库加载到进程中的地址是由系统决定的,应该是从进程的开始
地址偏移一个固定地址开始映射共享库,但是load_elf_library 函数中映射共享库的代码居然没有这个偏移量,不知道为什么,

看代码:

static int load_elf_library(struct file *file)
{
        struct elf_phdr *elf_phdata;
        struct elf_phdr *eppnt;
        unsigned long elf_bss, bss, len;
        int retval, error, i, j;
        struct elfhdr elf_ex;

        error = -ENOEXEC;
        retval = kernel_read(file, 0, (char *)&elf_ex, sizeof(elf_ex));
        if (retval != sizeof(elf_ex))
                goto out;

        if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
                goto out;

        /* First of all, some simple consistency checks */
        if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
            !elf_check_arch(&elf_ex) || !file->f_op->mmap)
                goto out;

        /* Now read in all of the header information */

        j = sizeof(struct elf_phdr) * elf_ex.e_phnum;
        /* j < ELF_MIN_ALIGN because elf_ex.e_phnum <= 2 */

        error = -ENOMEM;
        elf_phdata = kmalloc(j, GFP_KERNEL);
        if (!elf_phdata)
                goto out;

        eppnt = elf_phdata;
        error = -ENOEXEC;
        retval = kernel_read(file, elf_ex.e_phoff, (char *)eppnt, j);
        if (retval != j)
                goto out_free_ph;

        for (j = 0, i = 0; i<elf_ex.e_phnum; i++)
                if ((eppnt + i)->p_type == PT_LOAD)
                        j++;
        if (j != 1)
                goto out_free_ph;

        while (eppnt->p_type != PT_LOAD)
                eppnt++;

        /* Now use mmap to map the library into memory. */
        error = vm_mmap(file,
                        ELF_PAGESTART(eppnt->p_vaddr),
                        (eppnt->p_filesz +
                         ELF_PAGEOFFSET(eppnt->p_vaddr)),
                        PROT_READ | PROT_WRITE | PROT_EXEC,
                        MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
                        (eppnt->p_offset -
                         ELF_PAGEOFFSET(eppnt->p_vaddr)));

        if (error != ELF_PAGESTART(eppnt->p_vaddr))
                goto out_free_ph;

        elf_bss = eppnt->p_vaddr + eppnt->p_filesz;
        if (padzero(elf_bss)) {
                error = -EFAULT;
                goto out_free_ph;
        }

        len = ELF_PAGESTART(eppnt->p_filesz + eppnt->p_vaddr +
                            ELF_MIN_ALIGN - 1);
        bss = eppnt->p_memsz + eppnt->p_vaddr;
        if (bss > len)
                vm_brk(len, bss - len);
        error = 0;

out_free_ph:
        kfree(elf_phdata);
out:
        return error;
}
看vm_mmap 函数,此共享库的起始映射地址直接被设置成共享库编译后设置的地址,我认为应该给这个地址加一个固定的偏移量才对,不知道坛子中的弟兄谁对共享库加载过程比较熟悉,帮忙讲一下这个函数。
谢谢

论坛徽章:
0
2 [报告]
发表于 2015-08-17 09:12 |只看该作者
没人顶,自己先顶一下

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
3 [报告]
发表于 2015-08-17 12:19 |只看该作者
没法直接回答楼主的问题,提供一个现象,仅供参考。
同一个程序b,链接两个so,liba1.so和liba2.so,后者的elf内容基本一致,但显然两个库最终会加载到不同的线性地址。
  1. [shlib]$ cat a1.c
  2. int add1(int x)
  3. {
  4.         return x + 1;
  5. }
  6. [shlib]$ cat a2.c
  7. int add2(int x)
  8. {
  9.         return x + 2;
  10. }
  11. [shlib]$ cat Makefile
  12. b: b.c liba1.so liba2.so
  13.         gcc -o $@ $< -Wl,-rpath=./ -L. -la1 -la2
  14. lib%.so: %.c
  15.         gcc -c -fPIC $<
  16.         gcc -o $@ -shared ${<:.c=.o}

  17. [shlib]$ readelf -l -W liba1.so liba2.so
  18. File: liba1.so
  19. Program Headers:
  20.   Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  21.   LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x0005dc 0x0005dc R E 0x200000
  22.   LOAD           0x0005e0 0x00000000002005e0 0x00000000002005e0 0x0001e8 0x0001f8 RW  0x200000
  23.   DYNAMIC        0x000610 0x0000000000200610 0x0000000000200610 0x000180 0x000180 RW  0x8
  24. File: liba2.so
  25. Program Headers:
  26.   Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  27.   LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x0005dc 0x0005dc R E 0x200000
  28.   LOAD           0x0005e0 0x00000000002005e0 0x00000000002005e0 0x0001e8 0x0001f8 RW  0x200000
  29.   DYNAMIC        0x000610 0x0000000000200610 0x0000000000200610 0x000180 0x000180 RW  0x8
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP