2012-03-20 126 views
1

我知道内核负责将虚拟内存映射到实际内存。但是我想知道谁为/ proc/pid/maps文件中显示的进程创建虚拟内存。谁在Linux中创建虚拟内存?

1)它是编译器/连接器的过程中创建一个虚拟存储区和内核只是把它映射到实际内存(因为虚拟内存的区域并不重要,所有它的事项它映射)?

2)抑或是内核本身创建虚拟内存空间,同时派生一个过程,它它映射到实际内存?

最后是什么mmap系统调用做到(1)或(2)?

回答

1

内核是实际创建管理你在/ proc/PID /图看到虚拟内存区域的实体。在保存每个进程(struct task_struct)状态的结构中,有一个struct mm_struct(请参阅linux/sched.h),特别是在struct vm_area_struct * mmap之内。这是由所有内存区域的内核维护的列表(称为区域描述符)映射到进程地址空间。当调用mmap时,会在此列表中添加一个新元素,并随后显示在/ proc/pid/maps中。

注意,大多数文件支持的区域,如/ proc/pid/maps中列出的libc.so在进程启动时由动态链接程序(ld.so)中的代码映射到那里。

还要注意的是,内核之前,不会绝对必要创造了在这些地区的地址的虚拟物理映射。

希望这会有帮助

3

你的断言实际上是正确的(在某种程度上)。

对于可执行ELF文件,链接器依赖链接器脚本为虚拟空间中的地址分配给程序的每个符号(这些都分组为各部分都有起始地址和大小)。您可以看到调用ld --verbose时使用的默认脚本。可以使用诸如readelfobjdump等工具来查看二进制的部分及其地址。 readelf -l /bin/cat。然后,如果您运行cat /proc/self/maps,则应该确定/bin/cat映射的地址是否匹配。因此,execve内核系统调用会这样做:将当前进程的地址空间替换为映射给定参数的可执行文件的新地址空间。

当然,如果代码的每一位被分配你会满足共享库的问题一个静态地址。共享库使用与位置无关的代码,因此它们可以映射到进程地址空间中的任何地方。内核在这里决定如何继续。

mmap既不是(1)或(2),它只是在地址空间的给定地址映射内存或文件的一部分(或让内核决定使用哪个地址)。实际上它用于映射程序使用的共享库。要查看如何运行strace /bin/true并查看execve如何首先调用以从二进制文件创建进程的地址空间,以及如何打开libc文件以及如何通过程序加载器以正确的权限对mmap进行映射:

execve("/bin/true", ["/bin/true"], [/* 69 vars */]) = 0 
... 
open("/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 
mmap(NULL, 3804080, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f224f351000 
mprotect(0x7f224f4e8000, 2097152, PROT_NONE) = 0 
mmap(0x7f224f6e8000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x197000) = 0x7f224f6e8000 

下面的文章也可能是值得一读: