linuxlinkerelf

Base virtual address for .text segment of PIE ELF executable on linux x86_64


I see that .text segment of ELF files that linked with -pie argument when loaded into memory locates somewhere in virtual memory addresses like 0x00005xxxxxxxxxxx on linux x86_64. I've checked several running processes and it seems that .text segment's address all of them has prefix 0x00005, I could not find any one with 0x00004 prefix for example.

Is there any reason why dynamic linker chooses this address range (0x00005xxxxxxxxxxx) to locate .text segment? Why it does not select some addresses starting from 4Mb+ like binaries linked without -pie argument?


Solution

  • Is there any reason why dynamic linker chooses this address range (0x00005xxxxxxxxxxx) to locate .text segment?

    The dynamic linker has nothing to do with this.

    The executable is mmaped by the kernel before the first user-space instruction executes (that instruction is the _start in the dynamic loader for dynamically linked binaries), as part of executing the execve system call.

    So you have to look in kernel sources for explanation of why PIE binaries end up in the 0x5... range.

    Looking in fs/binfmt_elf.c you can see that it uses ELF_ET_DYN_BASE, which is defined in arch/x86/include/asm/elf.h as

    #define ELF_ET_DYN_BASE         (mmap_is_ia32() ? 0x000400000UL : \
                                                      (DEFAULT_MAP_WINDOW / 3 * 2))
    

    The DEFAULT_MAP_WINDOW is itself coming from arch/x86/include/asm/page_64_types.h:

    #define DEFAULT_MAP_WINDOW ((1UL << 47) - PAGE_SIZE)
    

    Putting this all together: (1UL << 47) - 4096 == 0x7ffffffff000; 0x7ffffffff000 / 3 * 2 == 0x555555554aaa.

    P.S. Note that .text is a section, not a segment. See also this answer.