2012-03-20 102 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 

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