我从
qemu-8.0.5源代码构建了一个
qemu-x86_64
用户级模拟器。当我使用gdb
调试它时,我发现qemu-x86_64
被加载到内存中的高地址(0x555555554000)。较低的内存地址是为客户程序保留的。
据我所知,我们可以在链接器脚本中指定 elf 的基本加载地址。我搜索了源代码树,也没有找到有关链接描述文件的单词,也没有找到地址字符串“0x555555.*”。
那么QEMU是如何让自己加载到高地址的呢?
这是 gdb 中的命令和输出。
~/qemu-8.0.5/build$ gdb ./qemu-x86_64
/* something not important */
(gdb) starti ./test.elf
Program stopped.
0x00007ffff7dd4090 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) i proc mappings
process 26751
Mapped address spaces:
Start Addr End Addr Size Offset Perms objfile
0x555555554000 0x55555572f000 0x1db000 0x0 r-xp /path/to/qemu-8.0.5/build/qemu-x86_64
0x55555592e000 0x555555970000 0x42000 0x1da000 rw-p /path/to/qemu-8.0.5/build/qemu-x86_64
0x555555970000 0x55555597e000 0xe000 0x0 rw-p [heap]
0x7ffff7dd3000 0x7ffff7dfc000 0x29000 0x0 r-xp /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ff7000 0x7ffff7ffa000 0x3000 0x0 r--p [vvar]
0x7ffff7ffa000 0x7ffff7ffc000 0x2000 0x0 r-xp [vdso]
0x7ffff7ffc000 0x7ffff7ffe000 0x2000 0x29000 rw-p /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0 rw-p
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 rw-p [stack]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 --xp [vsyscall]
那么QEMU是如何让自己加载到高地址的呢?
它不是。它加载的地址是 PIE 二进制文件的default加载地址。
通过运行以这种方式构建的
a.out
,您将获得完全相同的结果:
echo "int main() { return 0; }" | gcc -xc - -o a.out -fPIE -pie
附注如果您使用的是 Ubuntu 变体,GCC 可能会默认配置为构建 PIE 二进制文件。