【发布时间】:2011-11-03 12:25:11
【问题描述】:
在 Linux 中,我了解到每个进程都在 32 位机器中存储从 0x08048000 开始的数据(在 64 位机器中从 0x00400000 开始)。
但我不知道从那里开始的原因。 0x08048000之前的内存是干什么用的?
更新: 有些人认为它是为内核映射的。不过据我所知,Linux内核使用的是用户栈之后的高端内存。
【问题讨论】:
标签: linux memory process operating-system
在 Linux 中,我了解到每个进程都在 32 位机器中存储从 0x08048000 开始的数据(在 64 位机器中从 0x00400000 开始)。
但我不知道从那里开始的原因。 0x08048000之前的内存是干什么用的?
更新: 有些人认为它是为内核映射的。不过据我所知,Linux内核使用的是用户栈之后的高端内存。
【问题讨论】:
标签: linux memory process operating-system
答案真的是:一堆东西。可执行文件的加载地址没有神奇的意义,几乎任何东西都可以映射到较低的地址。常见的例子包括:C 库(如 C 库)、动态加载器 ld.so 和内核 VDSO(内核映射的动态代码库,在 x86 Linux 中为内核提供一些接口)。但是你几乎可以使用 mmap() 系统调用映射任何你想要的东西。
例如在我的特定机器上,地图如下(获得但“cat /proc/self/maps”):
gby@watson:~$ cat /proc/self/maps
001c0000-00317000 r-xp 00000000 08:01 245836 /lib/libc-2.12.1.so
00317000-00318000 ---p 00157000 08:01 245836 /lib/libc-2.12.1.so
00318000-0031a000 r--p 00157000 08:01 245836 /lib/libc-2.12.1.so
0031a000-0031b000 rw-p 00159000 08:01 245836 /lib/libc-2.12.1.so
0031b000-0031e000 rw-p 00000000 00:00 0
00376000-00377000 r-xp 00000000 00:00 0 [vdso]
00852000-0086e000 r-xp 00000000 08:01 245783 /lib/ld-2.12.1.so
0086e000-0086f000 r--p 0001b000 08:01 245783 /lib/ld-2.12.1.so
0086f000-00870000 rw-p 0001c000 08:01 245783 /lib/ld-2.12.1.so
08048000-08051000 r-xp 00000000 08:01 2244617 /bin/cat
08051000-08052000 r--p 00008000 08:01 2244617 /bin/cat
08052000-08053000 rw-p 00009000 08:01 2244617 /bin/cat
09ab5000-09ad6000 rw-p 00000000 00:00 0 [heap]
b7502000-b7702000 r--p 00000000 08:01 4456455 /usr/lib/locale/locale-archive
b7702000-b7703000 rw-p 00000000 00:00 0
b771b000-b771c000 r--p 002a1000 08:01 4456455 /usr/lib/locale/locale-archive
b771c000-b771e000 rw-p 00000000 00:00 0
bfbd9000-bfbfa000 rw-p 00000000 00:00 0 [stack]
【讨论】:
0x08048000 东西,将程序与 DYNAMIC flag 链接在一起,使它们的段与 .so 一起分配。
加载可执行代码的起始地址由可执行文件的 ELF 标头确定。例如:
/bin/ls
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08049bb0
没有什么可以阻止可执行文件指定不同的加载地址;不管出于什么原因default linker settings 把它放在那里。您可以使用自定义链接描述文件覆盖。
默认情况下,在 linux/x86 上,您不会看到0x08000000 以下的低地址被大量使用;尽管内核可能会在mmap 调用中请求它,或者如果它的mmap 空间不足。此外,有人提议使用0x00000000 - 0x01000000 范围内的地址进行库映射,以使缓冲区溢出更加困难(通过嵌入 NUL 字节来终止字符串)。
【讨论】:
加载地址是任意的,但使用 SYSV for x86 标准化。每种架构都不同。上面和下面的内容也是任意的,并且经常被库和 mmap() 区域中的链接所占用。
【讨论】:
32 位小型静态应用的 x86 的典型负载图如下所示:
Address Contents
0x08048000 code
0x08052000 data
0x0805A000 bss (zero data)
0x08072000 end of data (brk marker)
0xBFFFE000 stack
所有这些都是相反的 - 堆栈在顶部并在数据向上移动时向下移动。我的猜测是 0x08048000 之前的地址是静态链接的,类似于每个操作系统的 MBR。
【讨论】: