I researched how dlopen() loads a dynamic library in memory under Linux. But I can't find how or where the glibc library creates the read-only area in memory.
Glibc's dlopen() uses the program header to find the segments of type LOAD and maps these into memory. For a dynamic library this are only the first two:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x000000000000075c 0x000000000000075c R E 0x200000
LOAD 0x0000000000000e00 0x0000000000200e00 0x0000000000200e00 0x0000000000000228 0x0000000000000230 RW 0x200000
...
The protection bits (forelast column) are for the first read/execute and for the second read/write. The corresponding sections are:
Section to Segment mapping:
Segment Sections...
00 .note.gnu.build-id .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 .jcr .dynamic .got .got.plt .data .bss
The memory layout of a randomly chosen dynamic library from the init process is as follows:
7f4b67833000-7f4b67837000 r-xp 000000 08:01 393388 /lib/x86_64-linux-gnu/libcap.so.2.25
7f4b67837000-7f4b67a37000 ---p 004000 08:01 393388 /lib/x86_64-linux-gnu/libcap.so.2.25
7f4b67a37000-7f4b67a38000 r--p 004000 08:01 393388 /lib/x86_64-linux-gnu/libcap.so.2.25
7f4b67a38000-7f4b67a39000 rw-p 005000 08:01 393388 /lib/x86_64-linux-gnu/libcap.so.2.25
In this case, there is one additional memory area, that has only protection bit for read set. What is the reason for that and where is this done? And why is the .rodata section contained in the first segment where data is executable?
The loading part is done in elf/dl-load.c:
The interesting function is _dl_map_segments which is called on line 1181 from the _dl_map_object_from_fd function.
This function is defined in the file elf/dl-map-segments.h.
But this function only maps the segments with their protection bits. Am I missing something?