Linux內存管理圖解(1)邏輯地址轉線性地址

研究內核時間不長,前幾天畫了個內存管理大圖,感覺太亂,準備細分寫點東西也算是整理一下自己的思路。都是一個人瞎琢磨的,周圍沒有可以交流的,不正確的地方請指出來。

一、邏輯地址轉線性地址
   
機器語言指令中出現的內存地址,都是邏輯地址,需要轉換成線性地址,再經過MMU(CPU中的內存管理單元)轉換成物理地址才能夠被訪問到。

我們寫個最簡單的hello world程序,用gcc編譯,再反編譯後會看到以下指令:

  1. mov    0x80495b0, %eax

複製代碼


這裏的內存地址0x80495b0 就是一個邏輯地址,必須加上隱含的DS 數據段的基地址,才能構成線性地址。也就是說 0x80495b0 是當前任務的DS數據段內的偏移。

<ignore_js_op>

在x86保護模式下,段的信息(段基線性地址、長度、權限等)即段描述符佔8個字節,段信息無法直接存放在段寄存器中(段寄存器只有2字節)。Intel的設計是段描述符集中存放在GDT或LDT中,而段寄存器存放的是段描述符在GDT或LDT內的索引值(index)。

Linux中邏輯地址等於線性地址。爲什麼這麼說呢?因爲Linux所有的段(用戶代碼段、用戶數據段、內核代碼段、內核數據段)的線性地址都是從 0x00000000 開始,長度4G,這樣 線性地址=邏輯地址+ 0x00000000,也就是說邏輯地址等於線性地址了。

這樣的情況下Linux只用到了GDT,不論是用戶任務還是內核任務,都沒有用到LDT。GDT的第12和13項段描述符是 __KERNEL_CS 和__KERNEL_DS,第14和15項段描述符是 __USER_CS 和__USER_DS。內核任務使用__KERNEL_CS 和__KERNEL_DS,所有的用戶任務共用__USER_CS 和__USER_DS,也就是說不需要給每個任務再單獨分配段描述符。內核段描述符和用戶段描述符雖然起始線性地址和長度都一樣,但DPL(描述符特權級)是不一樣的。__KERNEL_CS 和__KERNEL_DS 的DPL值爲0(最高特權),__USER_CS 和__USER_DS的DPL值爲3。
用gdb調試程序的時候,用info reg 顯示當前寄存器的值:

  1. cs             0x73     115
  2. ss             0x7b     123
  3. ds             0x7b     123
  4. es             0x7b     123

複製代碼


可以看到ds值爲0x7b, 轉換成二進制爲 00000000 01111011,TI字段值爲0,表示使用GDT,GDT索引值爲 01111,即十進制15,對應的就是GDT內的__USER_DATA 用戶數據段描述符。
從上面可以看到,Linux在x86的分段機制上運行,卻通過一個巧妙的方式繞開了分段。Linux主要以分頁的方式實現內存管理

 

轉自:http://bbs.chinaunix.net/thread-2015599-1-1.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章