While examining the /proc/<PID>/maps file for an aarch64 process running on an Android (8), I notice this section:

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

Here's the program header table for 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

Taking the address 0xe08e0 of the second LOAD segment and adding the base of 0x726048e000, I come up with 0x726056e8e0. However, as seen in maps file above, there's no segment mapped right at that address. Instead, it overlaps with the [anon:.bss] segment. It's not even fully contained in the segment as, with a size of 0xaea8, its ending address would be 0x7260579788.

1 Answer 1


The last column of the program header table printed by readelf is the p_align member of the header, which defines an alignment requirement for the defined segment. From Linux man page elf(5):

This member holds the value to which the segments are aligned in memory and in the file. Loadable process segments must have congruent values for p_vaddr and p_offset, modulo the page size. Values of zero and one mean no alignment is required. Otherwise, p_align should be a positive, integral power of two, and p_vaddr should equal p_offset, modulo p_align.

Because of the alignment value 0x1000, the initialized, read-only, data segment will be included in a memory mapping with offset 0x0d6000 (0x0d68e0 rounded down) and size 0x008000 (0x007770 rounded up), which is exactly what the maps file shows (the fourth field is the file offset and the mapping length can be calculated by substracting the end and start addresses. 0x726056d000 - 0x7260565000 = 0x8000). The two following mappings have the same alignment, and by their protection flags you can guess they correspond to the initialized data segment (.data) and the uninitialized data segment (.bss).

  • Wouldn't you use the virtual address (0xe08e0) instead of the file offset (0xd68e0)? Aug 28, 2022 at 1:55
  • Also, wouldn't the size in memory be 0xaea8 instead of the file size of 0x7770? Aug 28, 2022 at 1:57
  • Why would the segment be read-only? The program header lists it as RW. Aug 28, 2022 at 2:19
  • 1
    @DanielWalker 1. you'd need to provide the virtual address of the first LOAD segment to check if it matches too. 2. the file size is used for file mapping (5th field in maps is not 00:00), the memory size is used for uninitialized data, which isn't included in the executable image. 3. the GNU_RELRO segment header specifies that during dynamic linking the section should be made read-only after relocations are done. (see ld(1))
    – don_aman
    Aug 28, 2022 at 17:06
  • I've added the full program header table. Aug 29, 2022 at 12:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .