Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 加载的ELF段的重叠映射_Linux_Elf_Glibc_Dynamic Loading - Fatal编程技术网

Linux 加载的ELF段的重叠映射

Linux 加载的ELF段的重叠映射,linux,elf,glibc,dynamic-loading,Linux,Elf,Glibc,Dynamic Loading,我想了解动态加载程序如何为ELF段创建映射的细节 考虑一个与GNULD链接的小型共享库。程序标题为: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00095c 0x00095c R E 0x200000 LOAD 0

我想了解动态加载程序如何为ELF段创建映射的细节

考虑一个与GNULD链接的小型共享库。程序标题为:

Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x00095c 0x00095c R E 0x200000 LOAD 0x000df8 0x0000000000200df8 0x0000000000200df8 0x000250 0x000258 RW 0x200000 DYNAMIC 0x000e08 0x0000000000200e08 0x0000000000200e08 0x0001d0 0x0001d0 RW 0x8 GNU_EH_FRAME 0x000890 0x0000000000000890 0x0000000000000890 0x00002c 0x00002c R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10 GNU_RELRO 0x000df8 0x0000000000200df8 0x0000000000200df8 0x000208 0x000208 R 0x1 如果打印可变全局变量的地址,则打印的地址位于第四个映射中

  • 这四种映射的目的是什么?
  • 为什么动态加载程序在没有权限的情况下创建“填充”映射?

  • 解构映射:

    Base address == 7fd1f057b000 Mapping 1: virtual offset 0x000000, size 0x001000, R-X, from file offset 0x0000 Mapping 2: virtual offset 0x001000, size 0x1ff000, ---, from file offset 0x1000 Mapping 3: virtual offset 0x200000, size 0x001000, R--, from file offset 0x0000 Mapping 4: virtual offset 0x201000, size 0x001000, RW-, from file offset 0x1000
    这四种映射的目的是什么?
    为什么动态加载程序在没有权限的情况下创建“填充”映射

    为了理解最终状态,我们需要跟踪动态链接器所采取的操作。它的“指示”是什么?它需要以随机地址(由操作系统选择)加载内存中的
    ET_DYN
    对象。映射必须满足这些“命令”(我省略了PhysAddr,因为它与VirtAddr相同):

    现在,对于所有ELF二进制文件来说,第一件重要的事情是为了正确工作,两个
    LOAD
    段必须通过相同的“基偏移”重新定位。例如,在
    0x1000000
    处加载第一个
    mmap
    段,在
    0x2000000+0x200df8==0x2200df8
    处加载第二个

    因此,动态链接器(我将使用它的
    rtld
    压缩)必须将两个段的
    mmap
    作为单个
    mmap
    (否则,无法保证第二个映射不会干扰已经映射到那里的其他内容)。因此,它执行:

    size_t len = 0x200df8 + 0x258;
    void *base = mmap(0, len, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
    
    在您的特定情况下,
    base==0x7fd1f057b000
    ,我们有一个映射,覆盖
    .text
    .data

    7fd1f057b000-7fd1f077d000 r-xp 0 libmy.so
    
    但是
    rtld
    远未完成。现在,它必须在
    mmap
    上加载
    段的
    .data
    (第二个)
    段加载到正确的位置并具有所需的权限(省略错误检查):

    我们的映射现在如下所示:

    7fd1f057b000-7fd1f077b000 r-xp 0 libmy.so
    7fd1f077b000-7fd1f077d000 rw-p 0 libmy.so
    
    其次,我们的文件非常短(小于4K),如果将地址保留在
    [0x7fd1f057c000,0x7fd1f077b000)
    映射范围内,则当我们更喜欢简单的
    SIGSEGV
    时,可能会产生
    SIGBUS
    或其他令人困惑的错误

    我们可以
    munmap
    这个区域,但这是一个缺点(其他一些小型库可能会降落在这个几乎2MB的区域,并混淆了
    rtld
    中寻找最近基映射的其他部分)。取而代之的是,
    rtld
    保护该区域而不访问,同时保持映射完整:

    mprotect(0x7fd1f057c000, 0x1ff000, PROT_NONE);
    
    现在,我们的内存映射看起来几乎像您观察到的最终结果:

    7fd1f057b000-7fd1f077b000 r-xp 0 libmy.so
    7fd1f057c000-7fd1f077b000 ---p 0 libmy.so
    7fd1f077b000-7fd1f077d000 rw-p 0 libmy.so
    
    7fd1f057b000-7fd1f077b000 r-xp 0 libmy.so
    7fd1f057c000-7fd1f077b000 ---p 0 libmy.so
    7fd1f077b000-7fd1f077c000 r--p 0 libmy.so
    7fd1f077c000-7fd1f077d000 rw-p 0 libmy.so
    
    但是,
    rtld
    还有一件事要做:您的对象请求(通过使用
    GNU RELRO
    段)在重新定位后保护其部分可写数据不被写入。因此,
    rtld
    执行重新定位,然后执行最终的
    mprotect

    mprotect(base + 0x200000, 0xdf8 + 0x208, PROT_READ);
    
    这将导致最终的内存映射(与您观察到的完全匹配):


    我在查找GNU_RELRO的文档时遇到了一些问题

    有一个很好的讨论

    我猜它的VirtAddr和FileSize指定哪些部分应该是只读的

    正确,除了它是
    MemSize
    (但它应该始终匹配
    FileSize

    所以不使用截面表


    动态链接期间从不使用节表,它可以在删除节表的情况下处理完全剥离的二进制文件。节表保留在二进制文件中(默认情况下)只是为了帮助调试。

    有趣的是,内核映射动态加载程序而不使用“填充”映射。“文本”和“数据"动态加载程序映射的段。您的问题中有很多要解包的内容,而且答案很长,需要花费一些时间来编写。为了完整性,请编辑您的问题以添加来自
    readelf-d libmy的输出。因此
    。我保证,它的输出将是相关的。哦,还请显示来自
    readelf-Wl libmy.s的完整输出o
    。这也会相关。我在查找
    GNU_RELRO
    上的文档时遇到一些问题。我猜它的VirtAddr和FileSize指定哪些部分应该是只读的?所以不使用section表?
    7fd1f057b000-7fd1f077b000 r-xp 0 libmy.so
    7fd1f077b000-7fd1f077d000 rw-p 0 libmy.so
    
    mprotect(0x7fd1f057c000, 0x1ff000, PROT_NONE);
    
    7fd1f057b000-7fd1f077b000 r-xp 0 libmy.so
    7fd1f057c000-7fd1f077b000 ---p 0 libmy.so
    7fd1f077b000-7fd1f077d000 rw-p 0 libmy.so
    
    mprotect(base + 0x200000, 0xdf8 + 0x208, PROT_READ);
    
    7fd1f057b000-7fd1f077b000 r-xp 0 libmy.so
    7fd1f057c000-7fd1f077b000 ---p 0 libmy.so
    7fd1f077b000-7fd1f077c000 r--p 0 libmy.so
    7fd1f077c000-7fd1f077d000 rw-p 0 libmy.so