我正在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“,无论什么程序执行地址转换?
我可以看到如何做到这一点的一种方法是,如果OS在每次执行任务切换时修改了页面目录条目#1以指向与该程序相对应的页面表。如果是这种情况,那听起来会增加许多复杂性 - 假设程序代码与位置无关,那么只是将程序加载到任意虚拟地址并从那里开始就不容易了吗?
答案 0 :(得分:8)
答案是每个进程都有自己的页表。切换过程时会切换它们。
http://www.informit.com/articles/article.aspx?p=101760&seqNum=3的更多信息。
内核在发生上下文切换时切换页表。在内核映射到每个进程的操作系统上,内核页面可以保留。另一方面,为用户进程提供4GiB的操作系统(32位)在进入内核(系统调用)时也必须进行上下文切换。
虽然虚拟寻址不需要不同的进程来拥有不同的页表,(依赖性是另一种方式),但我不能想到任何当前的操作系统都没有为每个进程提供自己的页表。 / p>
答案 1 :(得分:5)
问:我知道这些是虚拟地址。
A:好......
问:但是,我不知道这些地址是如何相同的 多个并发运行的进程。
答:我以为你刚才说你理解“虚拟地址”;)?
问:使用公共起始地址进行加载的原因是什么 所有过程?
答:请记住,这是虚拟地址 - 不是物理地址。为什么不有一些标准的起始地址?
请记住 - 您不希望将起始地址设为“0” - 有许多特定的虚拟地址(特别是640K以下的虚拟地址),进程可能希望将其映射为物理地址。 / p>
这是一篇很好的文章,涉及其中的一些问题。包括“e_entry”: