1. 程式人生 > >linux 程序的虛擬地址和核心中的虛擬地址有什麼關係

linux 程序的虛擬地址和核心中的虛擬地址有什麼關係

按照以前書上,或linux核心2.6核心的邏輯地址使用者空間邏輯地址 (邏輯地址有時也被叫虛擬地址) 都是位於 0x00000000~0xFFFFFFFF 這段虛擬地址空間 ,其中使用者空間邏輯地址 位於邏輯地址 0x00000000~ 0xBFFFFFFF ,共3g , 核心邏輯地址是 0xC0000000~0XFFFFFFFF,共1g。而且這個地址空間對於每個程序來說都是獨立的。

這裡解釋一下獨立是什麼含義。

看一下這個圖
每個程序看到的 地址空間都是一樣的,比如.text 都是從0x80048000 開始,然後使用者棧都是從0xBFFFFFFF 向低地址增長,核心地址空間都是0xC0000000~0xFFFFFFFF。 每個程序看到的 地址空間都是一樣的,比如.text 都是從0x80048000 開始,然後使用者棧都是從0xBFFFFFFF 向低地址增長,核心地址空間都是0xC0000000~0xFFFFFFFF。

但是,每個程序的邏輯地址0x08048000 ~ system break 以及stack中對應的內容應該是不一樣的(除非兩個共享地址空間,那就是執行緒了)。 那問題來了,不同程序 有相同的邏輯地址,但是卻又不同的內容,這怎麼實現呢?

這就要靠 每個程序的的頁表
了。每個程序都有一個自己的頁表,使得 某邏輯地址對應於某個實體記憶體。 正因為 每個程序都有一個自己的頁表,使得相同的邏輯地址對映到 不同的實體記憶體。對於執行緒 ,它也有自己的頁表,只是頁表的 邏輯地址 對映到的實體記憶體相同。

那程序的頁表是怎樣的呢?首先,核心本身就有一個頁表了,而且 對於normal_area 都是一一對映到實體記憶體的,具體可查一下網上資料關於低端記憶體和高階記憶體。 這裡可以不用知道到底怎麼對映,只需要知道 核心中有一個頁表, 能把核心邏輯地址對映到核心實體地址

這個核心邏輯地址對於每一個程序來說都應該是一樣的,所以 ,在建立程序表時候,就可以直接拷貝該核心的頁表,作為該程序 的頁表的一部分,另外對於 該程序的使用者部分的頁表,可以簡單地理解為 把邏輯地址 對映到一個 空閒的 實體記憶體區域。

每當切換到另一個程序時,就要設定這個程序的頁表,通過 設定MMU的某些暫存器 ,然後 MMU 就可以把 cpu 發出的邏輯地址 轉化為 實體地址了。

雖然看起來 ,該程序 擁有 0x00000000~0xFFFFFFFF 的 邏輯地址空間 ,但是0xC0000000~0xFFFFFFFF 這段是核心的邏輯地址 ,在使用者態時訪問會出錯,許可權不夠,如果想訪問,需要切換到核心態 ,可以通過 系統呼叫等。系統呼叫代表某個程序運行於核心,此時,相當於該程序可以訪問0xC0000000~0xFFFFFFFF 這個地址了(但實際上 只能訪問 該程序的某個8KB的核心棧 ,這裡不是很確定,因為每個程序都有自己獨立的8KB的核心棧,你應該是不能訪問別的核心的核心棧),此時可以把使用者空間邏輯地址 在 核心邏輯地址 之間 進行記憶體拷貝。

另外 0X00000000 ~0x08048000 是不能給使用者訪問的,這裡面是一些C執行庫的內容。訪問會報segement fault 錯誤。

另外linux 對只讀的內容可以共享,在實體記憶體中只有一份拷貝。這樣,即使在邏輯地址上看起來有很多c庫等執行庫在裡面,但整個記憶體只有一份拷貝,當然,對於可寫的資料段,每個程序都應該有獨立一份。