ELF文件裡面section的虛擬地址是如何在鏈接(link)時確定的?

我已經自己把問題回答了,原先的理解有點失誤。也謝謝各位的指點。如果我自己的回答里有問題,也歡迎指出。ELF文件裡面section的虛擬地址是如何在鏈接(link)時確定的? - Hao Lee 的回答

原問題如下:

————————————————————————

最近看《程序員的自我修養》這本書,受益良多,但是知道的越多,疑問就越多。有很多問題書中沒有解釋清楚。所以特來諮詢。

ELF文件內各個section的virtual address在鏈接後就會被確定,比如.text的virtual address一般是0x0804800這個虛擬地址。那麼問題就是,所有的ELF都被鏈接成這樣,如果依次運行這些程序,操作系統要把ELF文件映射到虛擬地址空間,但是他發現0x0804800這個虛擬地址已經被其他程序佔領了,這時操作系統會怎麼辦。

所有的ELF都把虛擬地址鏈接成幾乎一樣的,這不會導致衝突嗎。ELF內的地址重定位早在鏈接時就已經完成,不可能在載入時再次改變吧,他要映射的虛擬地址已經被佔領,此時操作系統如何操作。


雖然我工作了兩年之後才知道 MMU 是怎麼回事,但是我上大學之前就知道虛擬地址不會衝突了。當年 OS/2 和 Windows 95 鋪天蓋地的宣傳這個。電腦白痴都能知道了。


通過頁表和MMU,每個page會載入到不同的物理內存地址,所以不會衝突。


虛擬存儲器是一個抽象概念,它為每個進程提供了一個假象,即每個進程都在獨佔地使用主存。

它為每個進程提供了一致的地址空間。

以上引用自CSAPP

回到你的問題,每個進程都用同一個邏輯地址,並不意味著用同一個物理地址。

順便說一句,物理地址是一個連續的大數組,這也是一種抽象。

附:邏輯地址—(段式,段寄存器表)—&>虛擬地址—(頁式,頁表)—&>物理地址

ps,段式在Linux系統里,只是應Intel要求,走走形式。


自問自答吧,看了些資料。

因為一直在看0.12內核代碼,那時的內存管理和現代內核有很大區別,加上最近在看ELF的裝載,各種地址空間概念有點多,所以有點暈。此問題也是一時犯迷糊吧,希望以後能對Linux內核理解越來越深入。

是我自己混淆了,我一開始以為4G的虛擬空間是唯一的,所有進程都來用這唯一的4G虛擬空間,兩個進程要是訪問同樣的虛擬地址,映射到物理地址上也是相同的,然後可能會存在衝突。【此觀點錯誤】

其實每個進程都有自己各自獨立的4G虛擬空間,相互之間是隔離的,
至於隔離的方法就是使得每個進程的頁目錄和頁表內容不同,也就是 [虛擬地址] 到 [物理地址] 的映射函數不同了。這樣即使A和B進程同時映射到各自虛擬空間的0x0804800地址處,分段分頁地址變換機制也會把0x0804800這個虛擬地址映射到不同的物理地址上去。而這個過程,進程自己是看不到的,A和B都認為自己成功訪問了0x0804800這個地址,但是實際上,他們訪問的是各自虛擬空間里「數值相等的」虛擬地址,最終這兩個「數值上相等」的虛擬地址將映射到不同的的物理內存地址處。這就實現了進程隔離。

每個進程都具備4G的虛擬空間,進程的虛擬空間之間相互隔離,互不干涉,每個進程都在自己的世界裡幹活。

不過上面說的都是從操作系統原理的角度說的,放到具體的Linux操作系統上會有點不同。因為Linux內核裡面規定,雖然每個進程各自擁有4G的虛擬空間,但是他們並不能隨意使用這全部的4個G。0-3G是用戶空間,的確是可以自由使用的,但是3G-4G之間內核空間,不能被隨意使用。所以,上面的理論可以完善為,每個進程都有一個大小為4G的虛擬空間,這4G的虛擬空間分為兩部分:

  1. 大小為3G的用戶空間,各進程在「特權級3級」下可以自由獨立使用,各進程的這塊空間是完全獨立的互不影響的,是指向物理內存不同位置的。

  2. 大小為1G的內核空間,各進程在「特權級0級」下才可以使用這塊空間,各進程的這塊空間不是獨立的,是指向同一物理內存位置的。也就是說是所有進程共享的。

這就是我的理解了,如果還有不對的地方請各位指正。


去看操原的頁目錄頁表怎麼映射地址,每個進程都有自己的一個虛擬地址空間,所以即使兩個進程的start地址是在0x080000000都不會有衝突。


先簡略的回答一下,因為每個用戶任務乃至內核都會維護自己的一個頁目錄和頁表,頁目錄的地址是控制寄存器指向的,在切換任務的時候,要切換cr3指向的頁目錄,加上虛擬內存,就是說哪怕兩個任務的線性地址相同,但是也會因為不是同一套頁目錄頁表的關係,經過mmu計算之後,得出的物理地址也會不同


我只說一句。好好找本操作系統原理的書,把內存管理那一章好好看看,就不會有這種問題了。


就這個大一學生都懂的事情還討論這麼久 先別叫自己kernel developer吧。。踏實一點


為什麼叫虛擬內存,就是因為這些看起來一樣的內存地址是虛擬出來的,每個進程會利用MMU和頁表把虛擬內存映射到物理內存,所以不同進程的相同虛擬內存地址可以對應到不同的物理地址。虛擬這種思維可以說是計算機行業用的最為廣泛的概念,是用來管理複雜度的終極手段。


每個進程操作系統都會分配一個0到3G的虛擬地址,通過Mmu轉換到物理地址。


我天,你這個都沒搞清楚,還自稱Linux Kernel Developer……看這問題以為你說的是鏈接的細節,被問題騙進來了


額 認為 樓主是說 elf 被用戶程序 執行 那就不會 有問題 一般來說 一個 process 會新建 一個page directory (額們 假設 2級頁表)那麼就是說 virtual memory 會被 重新映射 通常來說 雖然它們 virtual address 是相同的 physical address 卻不會一樣 或者說 相同 通常是共享的 部分 kernel 會做保護的 比如 只可以 read 或不能訪問 或者… 「…」 表示額 還不能 清晰解釋的 地方

-----------------------------------------

添加 一點東西 就是 轉化的 時候 會flush tlb 或者 at least flush 衝突的 va的 entry


elf 地址包含了 lma 和 vma。vma 是虛擬地址,由操作系統映射到某個真實的物理地址。


os也有能力管理物理地址空間的。so。。。。


推薦閱讀:

Linux 平台下閱讀 Linux 內核源碼好用的工具有哪些?

TAG:操作系統 | Linux | Linux內核 | 操作系統內核 |