【发布时间】:2020-10-04 20:47:32
【问题描述】:
我想详细了解动态加载器如何为 ELF 段创建映射。
考虑一个与 GNU ld 链接的小型共享库。程序头是:
类型 偏移 VirtAddr PhysAddr FileSiz MemSiz Flg Align 加载 0x000000 0x0000000000000000 0x0000000000000000 0x00095c 0x00095c R E 0x200000 加载 0x000df8 0x0000000000200df8 0x0000000000200df8 0x000250 0x000258 读写 0x200000 动态 0x000e08 0x0000000000200e08 0x0000000000200e08 0x0001d0 0x0001d0 RW 0x8 GNU_EH_FRAME 0x000890 0x0000000000000890 0x0000000000000890 0x00002c 0x00002c R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 读写 0x10 GNU_RELRO 0x000df8 0x0000000000200df8 0x0000000000200df8 0x000208 0x000208 R 0x1这个共享对象可以打印它加载的进程的映射(/proc/self/maps),sn-p:
如果我打印一个可变全局变量的地址,打印的地址在第四个映射中。
- 这四种映射各自的用途是什么?
- 为什么动态加载器会创建一个没有权限的“填充”映射?
解构映射:
基地址 == 7fd1f057b000 映射1:虚拟偏移0x000000,大小0x001000,R-X,从文件偏移0x0000 映射2:虚拟偏移0x001000,大小0x1ff000,---,从文件偏移0x1000 映射3:虚拟偏移0x200000,大小0x001000,R--,从文件偏移0x0000 映射4:虚拟偏移0x201000,大小0x001000,RW-,从文件偏移0x1000我目前的理解:
广告 1。
- 第一个映射是“文本”段(第一个程序头)。
- 第二个映射看起来像一种填充形式(没有权限和大小,因此下一个段的虚拟偏移量为 0x200000)。
- ???
- “数据”段。除了我会说它应该从文件偏移量 0 开始并且大小为 0x2000。该段从文件中的 0xdf8 开始,仍然在第一页上。还有,“文本”段的文件大小怎么会大于“数据”段的偏移量?
Ad 2. 链接器不能只请求在确切的虚拟地址 7fd1f077b000 上进行映射,从而创建一个漏洞吗?为什么要打扰这个映射?
$ readelf -d libmy.so
Dynamic section at offset 0xe08 contains 25 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x5a8
0x000000000000000d (FINI) 0x848
0x0000000000000019 (INIT_ARRAY) 0x200df8
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x200e00
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x0000000000000004 (HASH) 0x190
0x000000006ffffef5 (GNU_HASH) 0x1e0
0x0000000000000005 (STRTAB) 0x380
0x0000000000000006 (SYMTAB) 0x218
0x000000000000000a (STRSZ) 172 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x201000
0x0000000000000002 (PLTRELSZ) 120 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x530
0x0000000000000007 (RELA) 0x470
0x0000000000000008 (RELASZ) 192 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0x450
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x42c
0x000000006ffffff9 (RELACOUNT) 3
0x0000000000000000 (NULL) 0x0
$ readelf -Wl libmy.so
Elf file type is DYN (Shared object file)
Entry point 0x630
There are 6 program headers, starting at offset 64
Program Headers:
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
Section to Segment mapping:
Segment Sections...
00 .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
01 .init_array .fini_array .dynamic .got .got.plt .data .bss
02 .dynamic
03 .eh_frame_hdr
04
05 .init_array .fini_array .dynamic .got
【问题讨论】:
-
有趣的是,内核映射动态加载器而不使用“填充”映射。动态加载器映射的“文本”和“数据”段之间只有很大的差距。
-
您的问题有很多要解开的内容,而且答案很长,需要一段时间才能写出来。为了完整起见,请编辑您的问题以添加来自
readelf -d libmy.so的输出。我保证,它的输出将是相关的。哦,还请显示来自readelf -Wl libmy.so的完整 输出。它也将是相关的。
标签: linux elf glibc dynamic-loading