2010-05-02 99 views
3

我在OSDev wiki上讀到,x86架構的受保護模式允許您爲代碼和數據創建單獨的段,而無法寫入代碼段。 Windows(是的,這是平臺)將新代碼加載到代碼段中,並在數據段中創建數據。但是,如果是這種情況,程序如何知道它必須將段切換到數據段?如果我理解正確,那麼所有的地址說明都指向您運行代碼的段,除非您切換描述符。但是我也讀過,這種扁平內存模型允許你在一個段內運行代碼和數據。但是,我僅在彙編程序方面閱讀。那麼,請問,Windows上的C編譯代碼的情況如何?謝謝。C編譯程序使用哪些段?

回答

2

中有說明兩種含義爲

  • 8086存儲地址段
  • 目標模塊程序部段

首先是有關什麼已加載進入80386+段寄存器;它包含一個物理內存起始地址,內存分配長度,允許的讀/寫/執行訪問,以及它是否從低到高或反之亦然(加上一些更隱蔽的標誌,如「複製參考」)。

第二含義是對象模塊語言的一部分。基本上,存在名爲code的段,名爲data(其包含初始化數據)的段和用於未初始化數據的段(名爲bss(以20世紀60年代裝配器的僞指令命名,意爲塊以符號開始)。當鏈接器將對象模塊組合在一起時,它會將所有代碼段合併到一起,將所有數據段合併到其他位置,並將bss合併到一起。當加載器映射內存地址時,它會查看總代碼空間並分配至少爲該大小的CPU內存分配,並將該段映射到代碼(在虛擬內存情況下)或將代碼讀取到分配的內存中 - 爲此它必須暫時將內存設置爲可寫的數據。寫保護通過CPU的分頁機制以及段寄存器完成。這是爲了防止通過例如錯誤的數據地址來嘗試寫入代碼。加載程序也爲兩個數據段組執行類似的設置。 (除了那些,這裏建立一個堆棧段和分配它,並映射共享的圖像。)

爲86執行指令據,每個操作數具有相關聯的段寄存器。有時這些是明確的,有時它們是隱含的。代碼通過CS隱式訪問,通過SS每當ESPEBP寄存器涉及其暗示堆棧和DS暗示對大多數其他操作數。 ESFSGS必須指定爲在其他情況下的覆蓋,除了一些像movscmps字符串指令。在扁平模型中,儘管CS不允許寫入,但所有段寄存器映射到相同的地址空間。

因此,要回答你的最後一個問題,CPU有四個(或更多)段寄存器設置在一次訪問過程的扁平虛擬內存空間。檢查每個操作數訪問是否適合該指令(例如不遞增CS地址),並且由尋呼保護單元檢查是否允許。

3

你讀到的信息是過時的。自〜1993年以來的Windows版本使用平坦的32位虛擬內存空間。 CS和DS段寄存器的值不再重要,不能更改。代碼和數據仍然有一個概念,現在由內存頁面屬性實現。查看VirtualProtectEx() API function在flNewProtect參數中傳遞的允許值。

您自己很少使用此API,這些屬性由可執行映像加載器和堆管理器設置。

+2

'CS'和'DS' *的值確實很重要 - 它們必須在GDT或LDT中引用有效的描述符。此外'DS' *可以在用戶模式下更改(但大多數程序不這樣做,因爲它很少有用)。 – caf 2010-05-02 23:50:24

+0

謝謝,但我認爲,在保護模式下,您仍然有分割,現在堅持,而不是使用段寄存器使用描述符表。但是在每個描述符表格裏面都有一個用於概念代碼或數據的概念。但平面模式建議代碼和數據在同一個段中,段I表示一個描述符表條目。 – 2010-05-03 09:51:32