I’m currently playing around with ELF binaries and how they are loaded in the memory in Linux Kernel. I am really confused about how PT_LOAD segments are loaded into memory. I have a ELF executable file named test.elf:
root@ubuntu-s-4vcpu-8gb-amd-sgp1-01:~/C# readelf -l test.elf
Elf file type is DYN (Position-Independent Executable file)
Entry point 0x10c0
There are 13 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000002d8 0x00000000000002d8 R 0x8
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000718 0x0000000000000718 R 0x1000
LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000
0x0000000000000259 0x0000000000000259 R E 0x1000
LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000
0x0000000000000124 0x0000000000000124 R 0x1000
LOAD 0x0000000000002da0 0x0000000000003da0 0x0000000000003da0
0x0000000000000274 0x0000000000000278 RW 0x1000
DYNAMIC 0x0000000000002db0 0x0000000000003db0 0x0000000000003db0
0x00000000000001f0 0x00000000000001f0 RW 0x8
NOTE 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000030 0x0000000000000030 R 0x8
As you can see from the output above, the file has four PT_LOAD segments. I would expect it to be loaded in the memory with four segments. However, when I am checking /proc/pid/maps , it shows that the running process has five segments loaded from the executable file.
root@ubuntu-s-4vcpu-8gb-amd-sgp1-01:~/C# cat /proc/209183/maps
55acd5d31000-55acd5d32000 r--p 00000000 fc:01 517731 /root/C/test.elf
55acd5d32000-55acd5d33000 r-xp 00001000 fc:01 517731 /root/C/test.elf
55acd5d33000-55acd5d34000 r--p 00002000 fc:01 517731 /root/C/test.elf
55acd5d34000-55acd5d35000 r--p 00002000 fc:01 517731 /root/C/test.elf
55acd5d35000-55acd5d36000 rw-p 00003000 fc:01 517731 /root/C/test.elf
55acd6e88000-55acd6ea9000 rw-p 00000000 00:00 0 [heap]
7f85da4fe000-7f85da501000 rw-p 00000000 00:00 0
7f85da501000-7f85da529000 r--p 00000000 fc:01 31232 /usr/lib/x86_64-linux-gnu/libc.so.6
7f85da529000-7f85da6be000 r-xp 00028000 fc:01 31232 /usr/lib/x86_64-linux-gnu/libc.so.6
7f85da6be000-7f85da716000 r--p 001bd000 fc:01 31232 /usr/lib/x86_64-linux-gnu/libc.so.6
I also notice that the third and fourth segment have the same offset and permissions. After a lot of searching, I still do not figure out why. I also check the sections resided in the segments and there is nothing special about those sections.
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
03 .init .plt .plt.got .plt.sec .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .dynamic .got .data .bss
06 .dynamic
07 .note.gnu.property
08 .note.gnu.build-id .note.ABI-tag
09 .note.gnu.property
10 .eh_frame_hdr
11
12 .init_array .fini_array .dynamic .got
Can anyone explain this, I really want to know the reason behind this difference!
I expect it to have only four segments
Anh Phan is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.