在检查/proc/<PID>/maps
Android (8) 上运行的 aarch64 进程的文件时,我注意到以下部分:
726048e000-7260564000 r-xp 00000000 103:00 5402 /system/lib64/libc++.so
7260564000-7260565000 ---p 00000000 00:00 0
7260565000-726056d000 r--p 000d6000 103:00 5402 /system/lib64/libc++.so
726056d000-726056e000 rw-p 000de000 103:00 5402 /system/lib64/libc++.so
726056e000-7260571000 rw-p 00000000 00:00 0 [anon:.bss]
72605b3000-72605b5000 r-xp 00000000 103:00 5641 /system/lib64/libpackagelistparser.so
这是程序头表libc++.so
:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000009040 0x0000000000009040 0x0001c0 0x0001c0 R 0x8
LOAD 0x000000 0x0000000000009000 0x0000000000009000 0x0d58fc 0x0d58fc R E 0x1000
LOAD 0x0d68e0 0x00000000000e08e0 0x00000000000e08e0 0x007770 0x00aea8 RW 0x1000
DYNAMIC 0x0dbb40 0x00000000000e5b40 0x00000000000e5b40 0x000220 0x000220 RW 0x8
NOTE 0x000200 0x0000000000009200 0x0000000000009200 0x000038 0x000038 R 0x4
GNU_EH_FRAME 0x0d3058 0x00000000000dc058 0x00000000000dc058 0x0028a4 0x0028a4 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0
GNU_RELRO 0x0d68e0 0x00000000000e08e0 0x00000000000e08e0 0x007720 0x007720 RW 0x10
0xe08e0
取第二段的地址LOAD
并加上 的基数0x726048e000
,我得出0x726056e8e0
。但是,如上面的映射文件所示,没有映射的段正确的在那个地址。相反,它与该[anon:.bss]
段重叠。它甚至没有完全包含在段中,因为大小为 时0xaea8
,其结束地址将为0x7260579788
。
答案1
打印的程序头表的最后一列readelf
是p_align
头的成员,它定义了所定义段的对齐要求。来自 Linux 手册页elf(5)
:
该成员保存段在内存和文件中对齐的值。可加载进程段的 p_vaddr 和 p_offset 必须具有一致的值(以页面大小为模)。值 0 和 1 表示不需要对齐。否则,p_align 应为 2 的正整数幂,并且 p_vaddr 应等于 p_offset,以 p_align 为模。
由于对齐值的原因0x1000
,初始化的只读数据段将包含在具有偏移量0x0d6000
(0x0d68e0
向下取整)和大小0x008000
(0x007770
向上取整)的内存映射中,这正是maps
文件显示的内容(第四个字段是文件偏移量)映射长度可以通过减去结束地址和起始地址来计算0x726056d000 - 0x7260565000 = 0x8000
)。下面的两个映射具有相同的对齐方式,通过它们的保护标志可以猜测它们对应于已初始化数据段(.data
)和未初始化数据段(.bss
)。