如何在同时运行的不同进程上多次使用相同的Linux程序加载内存地址?

sus*_*its 9 linux linux-kernel

我正在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
Run Code Online (Sandbox Code Playgroud)

似乎maps所有程序的文件都显示每个程序的可执行代码都是从一个内存块开始加载的0x00400000.

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

编辑:

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

我可以看到如何做到这一点的一种方法是,如果操作系统在每次执行任务切换时修改了页面目录条目#1以指向与该程序相对应的页面表.如果是这种情况,那听起来似乎增加了许多复杂性 - 假设程序代码与位置无关,那么只是将程序加载到任意虚拟地址并且从那里开始就不容易了吗?

Dou*_*der 8

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

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

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

虽然虚拟寻址不需要不同的进程来拥有不同的页表,(依赖性是另一种方式),但我想不出任何当前的操作系统都没有为每个进程提供自己的页表.


pau*_*sm4 5

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

一个好的...

问:但是,我不知道这些地址对于多个并发运行的进程是如何相同的.

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

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

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

请记住 - 您不希望将起始地址设置为"0" - 有许多特定的虚拟地址(特别是640K以下的虚拟地址),进程可能希望将其映射为物理地址.

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

如何在Linux上执行main()