2011-11-17 14 views
3

我有一個令人困惑的概念,關於在x86 linux機器上分割分頁的過程。如果有人澄清從開始到結束所涉及的所有步驟,會很高興。根據頁面分割內存的程序壽命

x86使用分頁分段內存技術進行內存管理。

任何人都可以解釋一下從一個可執行.elf格式文件從硬盤加載到主內存到它死亡的時刻發生了什麼。編譯時,可執行文件有不同的部分(文本,數據,堆棧,堆,bss)。這將如何加載?他們將如何在頁面分割內存技術下建立起來。

想知道如何爲加載的程序設置頁表?想知道如何設置GDT表。寄存器如何加載?爲什麼說它的邏輯地址(當MMU的分段單元是一個32位的機器時,它是48位(16位段選擇器+ 32位偏移量),其他16位將如何存儲?從ram訪問的任何東西必須是32位或4字節如何訪問16位的其餘部分(要加載到段寄存器)?

在此先感謝問題可以有很多事情,但希望得到澄清的可執行文件的整個生命週期。會很高興,如果一些答案,向上拉動此討論。

回答

1

有沒有這樣的事情,頁面分割,至少不在官方文檔。有在一起並或多或少彼此獨立地工作的兩個不同的機制:

  1. 形式16-bit segment selector value:16/32/64-bit segment offset value的邏輯地址翻譯,即,一對2號的成32/64-bit virtual address
  2. virtual address翻譯爲32/64-bit physical address

邏輯地址是您的應用程序直接操作的內容。然後按照上面的兩步轉換將它們轉換成RAM將理解的物理地址。

在第一步中,GDT(或者它可以是LDT,取決於選擇器值)由選擇器索引以找到相關段的基地址和大小。虛擬地址將是段基址和偏移量的總和。段描述符中的段大小和其他內容是提供保護所必需的。

在第二步中,頁表通過虛擬地址的不同部分進行索引,並且層次結構中的最後一個索引表給出了RAM在地址總線上出現的最終物理地址。就像段描述符一樣,頁表項不僅包含地址,還包含保護控制位。

這就是關於它的機制。

現在,在許多x86操作系統中,用於應用程序的段選擇器是固定的,它們在所有這些選擇器中是相同的,它們從不改變,它們指向基址等於0且段大小等於可能的最大值(例如,在非64位模式下爲4GB)。這樣的GDT設置實際上意味着第一步沒有任何有用的工作,並且邏輯地址的偏移部分轉換爲數字上相同的虛擬地址。

這使段選擇器的值幾乎沒用。它們仍然必須加載到CPU的段寄存器中(非64位模式至少包括CS,SS,DS和ES),但超出這一點時,它們可能會被遺忘。

這個全部內容(除了Linux相關的細節和ELF格式)在Intel和AMD的x86 CPU手冊中或直接在後面進行了解釋。你會在那裏找到更多的細節。

+0

謝謝亞歷克斯,我已經理解90%的解釋...想問...在非x86系統的情況下,如何評估段選擇器?另外,爲什麼偏移量(邏輯地址中的第二個數字)是16/32/64? –

+0

糾正我....當一個程序從硬盤進入內存;程序段被分配了邏輯地址(16位選擇器+ 32偏移量)?這個16位選擇器是如何發現的(是由編譯器完成的)...在選擇器加載到GDT的時候,GDT表中沒有與當前程序對應的條目嗎?如果是的話,GDT表格條目是如何填充的? –

+0

並非所有CPU都具有與x86 CPU段等同的功能。如果他們這樣做,他們的工作方式取決於CPU。我無法談論抽象的非x86 CPU的具體細節,至少需要首先選擇一個特定的CPU。 :) x86 CPU在操作數大小及其在內存中的尋址方面有幾種不同的操作模式。 –

0

也許讀Assembly HOWTO。當一個Linux進程開始使用execvesystem call執行一個ELF可執行文件,它基本上(有點) mmap - 一些段(和初始化寄存器,以及堆棧的一小部分)。另請閱讀SVR4 x86 ABI supplement及其x86-64 variant。不要忘記,Linux進程只能看到內存映射其address space,只在乎virtual memory

上有Operating Systems(= OS)kernels許多好書,尤其是通過A.Tanenbaum &通過M.Bach,有的在linux kernel

注意:在Linux上幾乎(幾乎)未使用段寄存器。

+0

感謝巴西爾..將按照 –

2

Unix傳統上通過分頁來實現保護。 286+提供分段功能,386+提供分頁功能。每個人都使用分頁,很少有人真正使用分段。

在x86中,每個內存操作數都有一個隱式段(因此地址實際上是16位選擇器+ 32位偏移量),具體取決於所使用的寄存器。所以如果你訪問[ESP + 8]隱含段寄存器是SS,如果你訪問[ESI]隱含段寄存器是DS,如果你訪問[EDI+4]隱含段寄存器是ES,...你可以通過段前綴覆蓋覆蓋這個。

Linux和幾乎所有現代x86操作系統都使用平面內存模型(或類似的東西)。在平坦的內存模型下,每個段都提供對整個內存的訪問權限,基數爲0,限制爲4Gb,因此您不必擔心分段帶來的複雜問題。基本上有4個部分:內核空間代碼(RX),內核空間數據(RW),用戶空間代碼(RX),用戶空間數據(RW)。

ELF文件由一些標題組成,用於「編程段」和「段」。部分用於鏈接。程序段用於加載。程序段通過mmap()映射到內存中,這樣就設置了具有適當權限的頁表項。

現在,較早的x86 CPU的分頁機制只提供了RW訪問控制(讀權限意味着執行權限),而分段提供了RWX訪問控制。結束權限考慮了分段和分頁(例如:RW(數據段)+ R(只讀頁面)= R(只讀),而RX(代碼段)+ R(只讀頁面)= RX執行))。

因此,有些補丁通過分段提供執行預防:例如, OpenWall通過縮小代碼段(具有執行權限的代碼段)並在頁錯誤處理程序中爲需要從高內存地址執行的任何事情提供特殊模擬來提供非可執行堆棧(例如:GCC蹦牀,創建的自修改代碼在堆棧上高效地實現嵌套功能)。

+0

感謝ninjali,這更接近我所尋找的。 –

+0

感謝ninjali,這更接近我所尋找的。所以當mmap()ing時,程序的段被分配一些虛擬地址。 (設置頁表)。我們如何評估分段選擇器?特別是如何評估隱式段?它在表格中被硬編碼了嗎? –

+0

@kernel_os:請注意,x86段與ELF程序段無關。 – ninjalj