为什么我的 x64 进程基地址不是从 0x400000 开始的?

why my x64 process base address not start from 0x400000?

我从这个 link Why is address 0x400000 chosen as a start of text segment in x86_64 ABI? 中得知 64 位 Linux 进程起始地址默认应该是 0x400000,但是在我的 Ubuntu 上,我只找到了我的bash 进程从一个非常高的基地址 (0x55971cea6000) 开始。 有谁知道为什么?动态 linker 如何选择 64 位进程的起始地址?

$ uname -r
5.15.0-25-generic

$ cat /etc/*release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04 LTS"
...

$ file /usr/bin/bash
/usr/bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=33a5554034feb2af38e8c75872058883b2988bc5, for GNU/Linux 3.2.0, stripped

$ ld -verbose | grep -i text-segment
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;

$ cat maps
55971ce77000-55971cea6000 r--p 00000000 08:02 153 /usr/bin/bash
55971cea6000-55971cf85000 r-xp 0002f000 08:02 153 /usr/bin/bash
55971cf85000-55971cfbf000 r--p 0010e000 08:02 153 /usr/bin/bash
55971cfc0000-55971cfc4000 r--p 00148000 08:02 153 /usr/bin/bash
55971cfc4000-55971cfcd000 rw-p 0014c000 08:02 153 /usr/bin/bash
55971cfcd000-55971cfd8000 rw-p 00000000 00:00 0 
...

$ readelf -h /usr/bin/bash
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x32eb0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          1394600 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         30
  Section header string table index: 29

I learned from this link Why is address 0x400000 chosen as a start of text segment in x86_64

该地址用于可执行文件(ELF 类型 ET_EXEC)。

I only found my bash process starts from a very high base address (0x55971cea6000). Any one knows why?

因为您的 bash 是(较新的)position-independent 可执行文件(ELF 类型 ET_DYN)。它的行为很像共享库,并在 运行 时间重新定位到随机地址。

您找到的 0x55971cea6000 地址会因一次执行而异。相比之下,ET_EXEC 可执行文件只能 运行 在其“链接地址”加载时正确(通常为 0x400000)。

how does dynamic linker choose the start address for a 64-bit process?

动态链接器不选择可执行文件的起始地址 -- 内核会选择(当动态链接器启动 运行ning 时,可执行文件已经 mmaped内存)。

内核查看 ELF 头中的 .e_type 和第一个程序头的 .p_vaddr 字段,然后从那里开始。 IFF .e_type == ET_EXEC,然后内核将可执行段映射到它们的 .p_vaddr 地址。对于 ET_DYN,如果 ASLR 有效,内核会在随机地址执行 mmaps。