9

我正在研究 64 位机器上的 Linux 2.6.32 上的进程执行。在研究 的输出时/proc/$PID/maps,我观察到一件事:

$ cat /proc/2203/maps | head -1
00400000-004d9000 r-xp 00000000 08:02 1050631              /bin/bash

$ cat /proc/27032/maps | head -1
00400000-00404000 r-xp 00000000 08:02 771580               /sbin/getty

似乎maps所有程序的文件都显示每个程序的可执行代码都加载到从0x00400000.

我知道这些是虚拟地址。但是,我不明白这些地址对于多个同时运行的进程是如何相同的。使用公共起始地址加载所有进程的原因是什么?操作系统如何区分一个进程的虚拟加载点与另一个进程的虚拟加载点?

编辑:

根据我对使用分页的地址空间虚拟化的理解,我认为部分虚拟地址用于通过使用它来索引一个或多个页表来查找内存块(一帧)的物理地址。考虑这种情况。地址看起来是 32 位的(这是另一件让我感到困惑的事情——为什么程序地址是 32 位的,但加载的库的地址是 64 位的?)。将地址分成十位、十位和十二位分别对应于页目录项、页表项和页偏移量,不应0x00400000总是表示“页目录项 1、页表项 0、偏移量 0”,没有什么程序执行地址转换?

我可以看到如何做到这一点的一种方法是,如果操作系统在每次执行任务切换时修改页面目录条目 #1 以指向与程序对应的页表。如果是这样的话,这听起来会增加很多复杂性——鉴于程序代码是与位置无关的,将程序加载到任意虚拟地址并从那里开始不是更容易吗?

4

2 回答 2

8

答案是每个进程都有自己的页表。它们在进程切换时切换。

更多信息请访问http://www.informit.com/articles/article.aspx?p=101760&seqNum=3

当上下文切换发生时,内核会切换页表。在内核映射到每个进程的操作系统上,内核页面可以保留。另一方面,为用户进程提供 4GiB 的操作系统(32 位)在进入内核(系统调用)时也必须进行上下文切换。

虽然虚拟寻址不需要不同的进程拥有不同的页表(依赖关系相反),但我想不出任何当前的操作系统不会为每个进程提供自己的页表。

于 2012-06-01T12:56:42.090 回答
5

问:我知道这些是虚拟地址。

一个好的...

问:但是,我不明白这些地址如何对于多个同时运行的进程是相同的。

A:我以为你刚刚说你理解“虚拟地址”;)?

问:使用共同起始地址加载所有进程的原因是什么?

答:请记住,这是一个虚拟地址,而不是物理地址。为什么没有一些标准的起始地址?

请记住——你不想将起始地址设为“0”——进程可能希望映射许多特定的虚拟地址(尤其是那些低于 640K 的地址),就好像它是一个物理地址一样。

这是一篇很好的文章,涉及其中一些问题。包括“e_entry”:

Linux 上 main() 是如何执行的

于 2012-06-01T05:37:22.497 回答