色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁技術文章
文章詳情頁

《Undocumented Windows 2000 Secrets》翻譯 --- 第四章(2)

瀏覽:80日期:2023-08-27 14:16:44

第四章 探索 Windows 2000 的內存管理機制

翻譯: Kendiv( fcczj@263.net )

更新: Sunday, February 14, 2005

聲明:轉載請注明出處,并保證文章的完整性,本人保留譯文的所有權利。

數據結構

本章隨后的示例代碼的某些部分將涉及底層的內存管理機制,在前面我們已快速瀏覽了該機制內部的大致輪廓。為了方便,我用 C 語言定義了幾個數據結構。這是因為 i386 CPU 內部的很多數據項需要使用一個二進制位或一組二進制位,而 C 的位域( bit-fIElds )唾手可得。位域可以很有效的訪問一個大的數據中的一個位或從中提取一組連續的位。微軟的 Visual C/C++ 可以產生非常棒的代碼來完成位域的操作。 列表 4-2 是一系列 CPU 數據類型定義的一部分,該列表包含如下的內容:

l X86_REGISTER 這是一個基本的無符號 32 位整數類型,該類型可描述多個 CPU 寄存器。這包括:通用的、索引、指針、控制、調試和測試寄存器。

l X86_SELECTOR 代表一個 16 位的段選擇器,如 CS 、 DS 、 ES 、 FS 、 GS 和 SS 。在 4-1 4-2 中,選擇器可描述 48 位邏輯地址的高 8 位,或作為描述符表的索引。為了計算的方便, 16 位選擇器的值被擴展到 32 位,不過高 16 位被標識為“保留”。注意, X86_SELECTOR 結構實際是兩個結構的聯合( union )。第一個指定了選擇器的值,該值占用一個 16 位的 Word ,其名字為 wValue ,第二個采用了位域。 RPL 域指定了請求的特權級,在 Windows 2000 上其值或者為 0 (內核模式)或者為 3 (用戶模式)。 TI 位用來選擇 GDT 或 LDT 。

l X86_DESCRIPTOR 定義了由選擇器指向的頁表項的格式。這是一個 64 位的數值,由于歷史演化,該結構比較讓人費解。線性基地址定義了與其相關的段的起始位置,它們分散在三個位域中: Base1 、 Base2 和 Base3 , Base1 是作用最小的部分。段的界限指定了段的大小, The segment limit specifying the segment size minus one is divided into the pair Limitl and Limit2, with the former representing the least significant half. 剩余的位域存放不同的段屬性( cf. Intel 1999c, pp.3-11 )。例如, G 位域定義了段的粒度。如果為零,段的限制按字節指定;否則,限制值為 4KB 的倍數。像 X86_SELECTOR 一樣, X86_DESCRIPTOR 結構由一個 union 組成,以允許按不同的方式解釋它的值。如果你必須復制描述符(在忽略其內部情況下)那么 dValueLow 和 dValueHigh 成員將會很有幫助。

l X86_GATE 該結構看起來有些像 X86_DESCRIPTOR 。事實上,這兩個結構是相關的: X86_DESCRIPTRO 是一個 GDT 項,并描述了一個段的內存屬性, X86_GATE 代表中斷描述符表( IDT )中的一項,并描述了中斷例程的內存屬性。 IDT 可以包含任務、中斷和陷阱門(不! Bill Gates 并沒有存儲在 IDT 中! 哈哈)。 X86_GATE 結構可匹配上述三種類型,并通過 Type 位域來進行區分。 Type 5 表示這是一個任務門; Type 6 和 14 為中斷門; Type 7 和 15 為陷阱門。 Type 中最重要的位是用來描述門的位數的位:該位若為 0 則表示是 16 位門;其余情況表示 32 位門。

l X86_TABLE 是一個巧妙的結構,該結構用來讀取 GDTR 或 IDTR 的當前值,分別通過匯編指令 SGDT (存儲 GDT 寄存器)和 SIDT (存儲 IDT 寄存器)來實現( cf. Intel 1999b, pp.3-636 )。這兩個指令需要一個 48 位的內存操作數,在該操作數中存放限制值和基地址值。通過在結構體中增加一個 DWORD 來對齊 32 位的基地址, X86_TABLE 以一個 16 位的啞元成員 wReserved 開始。根據是否使用了 SGDT 或 SIDT 指令,其基地址將被解釋為一個描述符指針或一個門指針,就像 PX86_DESCRIPTOR 和 PX86_GATE 中的 union 所暗示的那樣。最后的 wLimit 成員在這兩種類型的表中的意義均相同。

譯注:

列表 4-2 中的這些結構定義可以在隨書光盤的 srccommonincludew2k_spy.h 中找到。

typedef DWORD X86_REGISTER, *PX86_REGISTER, **PPX86_REGISTER;

// -----------------------------------------------------------------

typedef struct _X86_SELECTOR

{

union

{

struct

{

WORD wValue; // packed value

WORD wReserved;

};

struct

{

unsigned RPL : 2; // requested privilege level

unsigned TI : 1; // table indicator: 0=gdt, 1=ldt

unsigned Index : 13; // index into descriptor table

unsigned Reserved : 16;

};

};

}

X86_SELECTOR, *PX86_SELECTOR, **PPX86_SELECTOR;

#define X86_SELECTOR_ sizeof (X86_SELECTOR)

// -----------------------------------------------------------------

typedef struct _X86_DESCRIPTOR

{

union

{

struct

{

DWORD dValueLow; // packed value

DWORD dValueHigh;

};

struct

{

unsigned Limit1 : 16; // bits 15..00

unsigned Base1 : 16; // bits 15..00

unsigned Base2 : 8; // bits 23..16

unsigned Type : 4; // segment type

unsigned S : 1; // type (0=system, 1=code/data)

unsigned DPL : 2; // descriptor privilege level

unsigned P : 1; // segment present

unsigned Limit2 : 4; // bits 19..16

unsigned AVL : 1; // available to programmer

unsigned Reserved : 1;

unsigned DB : 1; // 0=16-bit, 1=32-bit

unsigned G : 1; // granularity (1=4KB)

unsigned Base3 : 8; // bits 31..24

};

};

}

X86_DESCRIPTOR, *PX86_DESCRIPTOR, **PPX86_DESCRIPTOR;

#define X86_DESCRIPTOR_ sizeof (X86_DESCRIPTOR)

// -----------------------------------------------------------------

typedef struct _X86_GATE

{

union

{

struct

{

DWORD dValueLow; // packed value

DWORD dValueHigh;

};

struct

{

unsigned Offset1 : 16; // bits 15..00

unsigned Selector : 16; // segment selector

unsigned Parameters : 5; // parameters

unsigned Reserved : 3;

unsigned Type : 4; // gate type and size

unsigned S : 1; // always 0

unsigned DPL : 2; // descriptor privilege level

unsigned P : 1; // segment present

unsigned Offset2 : 16; // bits 31..16

};

};

}

X86_GATE, *PX86_GATE, **PPX86_GATE;

#define X86_GATE_ sizeof (X86_GATE)

// -----------------------------------------------------------------

typedef struct _X86_TABLE

{

WORD wReserved; // force 32-bit alignment

WORD wLimit; // table limit

union

{

PX86_DESCRIPTOR pDescriptors; // used by sgdt instruction

PX86_GATE pGates; // used by sidt instruction

};

}

X86_TABLE, *PX86_TABLE, **PPX86_TABLE;

#define X86_TABLE_ sizeof (X86_TABLE)

列表 4-2. i386 的寄存器、選擇器、描述符、門和表

接下來的一組與 i386 內存管理相關的結構,它們收錄在 列表 4-3 中,這些結構包括:與請求式分頁相關的結構和 4-3 4-4 給出的幾個成員。

l X86_PDBR 該結構對應 CPU 的 CR3 寄存器,即眾所周知的頁目錄基地址寄存器( PDBR )。其高 20 位為 PFN ,即 4KB 物理頁數組的索引。 PFN=0 對應物理地址 0x00000000 , PFN=1 為 0x00001000 ,依此類推。 20 個位足夠轉換整個 4GB 地址空間。 PDBR 中的 PFN 是物理頁的索引,用來控制整個頁目錄。 PFN 中剩余的位大多數都被保留,但 3 號位例外,它用來控制頁一級的 write-through ( page-level write-through, PWT ), 4 號位如果為 1 ,則禁止頁一級的高速緩沖。

l X86_PDE_4M X86_PDE_4K 是頁目錄項( PDE )的兩個可選方案,用來選擇 4MB 頁或者 4KB 的頁。一個頁目錄中最多包含 1024 個 PDE 。 PFN 是頁幀號,它指向下一級的頁。對于一個 4MB 的 PDE ,其 PFN 位域僅有 10 個位的寬度,可尋址一個 4MB 的數據頁。 4KB 的 PDE 擁有 20 位的 PFN ,可指向一個頁表,由頁表最終選擇一個數據頁。剩余的位用來定義多種屬性。這些屬性中最有趣的是“頁大小”位 PS ,用于控制頁的大小( 0=4KB , 1=4MB )和“存在”位 P ,標識下屬的數據頁( 4MB 模式)或頁表( 4KB 模式)是否存在于物理內存中。

X86_PTE_4K 定義了頁表項(屬于一個頁表)的內部結構。和頁目錄類似,一個頁表可擁有 1024 個項。 X86_PTE_4K 和 X86_PDE_4K 的不同之處為:前者沒有 PS 位,這根本不需要,因為頁的大小肯定是 4KB 。需要注意的是,沒有所謂的 4MB 的 PTE ,因為采用 4MB 頁的內存模式不需要頁表這一中間層。

X86_PNPE 代表一個“不存在的頁”項( page-not-present entry, PNPE ),也就是說,一個 PDE 或 PTE 中的 P 位為 0 。如 Intel 的手冊所說的,保留的第 31 位是“對操作系統或執行體( executive )均可用”( Intel 1999c,pp. 3-28 )。如果一個線性地址映射到了一個 PNPE ,這意味著這個地址或者還未使用或者它所指向的頁已經被置換到了頁面文件中。 Windows 2000 使用 PNPE 保留的第 31 位來存儲頁的信息。有關頁信息的結構沒有文檔記載,不過它類似于名為 PageFile 的第 10 位,如 列表 4-3 所示,如果設置了該位,則表示頁已被置換出物理內存。在這種情況下, Reserved1 和 Reserved2 位域將包含系統在頁面文件中定位該頁的信息,因此,當需要訪問該頁時,可很快的將其換回物理內存。

X86_PE 該結構是為了方便使用而加入的。它僅包含一個 union ,該 union 包括頁項所有可能的狀態,此處的頁項是指: PDBR 的內容、所有 4MB 和 4KB 的 PDE 、 PTE ,以及所有的 PNPE 。

typedef struct _X86_PDBR // page-Directory base register (cr3)

{

union

{

struct

{

DWORD dValue; // packed value

};

struct

{

unsigned Reserved1 : 3;

unsigned PWT : 1; // page-level write-through

unsigned PCD : 1; // page-level cache disabled

unsigned Reserved2 : 7;

unsigned PFN : 20; // page-frame number

};

};

}

X86_PDBR, *PX86_PDBR, **PPX86_PDBR;

#define X86_PDBR_ sizeof (X86_PDBR)

// -----------------------------------------------------------------

typedef struct _X86_PDE_4M // page-directory entry (4-MB page)

{

union

{

struct

{

DWORD dValue; // packed value

};

struct

{

unsigned P : 1; // present (1 = present)

unsigned RW : 1; // read/write

unsigned US : 1; // user/supervisor

unsigned PWT : 1; // page-level write-through

unsigned PCD : 1; // page-level cache disabled

unsigned A : 1; // accessed

unsigned D : 1; // dirty

unsigned PS : 1; // page size (1 = 4-MB page)

unsigned G : 1; // global page

unsigned Available : 3; // available to programmer

unsigned Reserved : 10;

unsigned PFN : 10; // page-frame number

};

};

}

X86_PDE_4M, *PX86_PDE_4M, **PPX86_PDE_4M;

#define X86_PDE_4M_ sizeof (X86_PDE_4M)

// -----------------------------------------------------------------

typedef struct _X86_PDE_4K // page-directory entry (4-KB page)

{

union

{

struct

{

DWORD dValue; // packed value

};

struct

{

unsigned P : 1; // present (1 = present)

unsigned RW : 1; // read/write

unsigned US : 1; // user/supervisor

unsigned PWT : 1; // page-level write-through

unsigned PCD : 1; // page-level cache disabled

unsigned A : 1; // accessed

unsigned Reserved : 1; // dirty

unsigned PS : 1; // page size (0 = 4-KB page)

unsigned G : 1; // global page

unsigned Available : 3; // available to programmer

unsigned PFN : 20; // page-frame number

};

};

}

X86_PDE_4K, *PX86_PDE_4K, **PPX86_PDE_4K;

#define X86_PDE_4K_ sizeof (X86_PDE_4K)

// -----------------------------------------------------------------

typedef struct _X86_PTE_4K // page-table entry (4-KB page)

{

union

{

struct

{

DWORD dValue; // packed value

};

struct

{

unsigned P : 1; // present (1 = present)

unsigned RW : 1; // read/write

unsigned US : 1; // user/supervisor

unsigned PWT : 1; // page-level write-through

unsigned PCD : 1; // page-level cache disabled

unsigned A : 1; // accessed

unsigned D : 1; // dirty

unsigned Reserved : 1;

unsigned G : 1; // global page

unsigned Available : 3; // available to programmer

unsigned PFN : 20; // page-frame number

};

};

}

X86_PTE_4K, *PX86_PTE_4K, **PPX86_PTE_4K;

#define X86_PTE_4K_ sizeof (X86_PTE_4K)

// -----------------------------------------------------------------

typedef struct _X86_PNPE // page not present entry

{

union

{

struct

{

DWORD dValue; // packed value

};

struct

{

unsigned P : 1; // present (0 = not present)

unsigned Reserved1 : 9;

unsigned PageFile : 1; // page swapped to pagefile

unsigned Reserved2 : 21;

};

};

}

X86_PNPE, *PX86_PNPE, **PPX86_PNPE;

#define X86_PNPE_ sizeof (X86_PNPE)

// -----------------------------------------------------------------

typedef struct _X86_PE // general page entry

{

union

{

DWORD dValue; // packed value

X86_PDBR pdbr; // page-directory Base Register

X86_PDE_4M pde4M; // page-directory entry (4-MB page)

X86_PDE_4K pde4K; // page-directory entry (4-KB page)

X86_PTE_4K pte4K; // page-table entry (4-KB page)

X86_PNPE pnpe; // page not present entry

};

}

X86_PE, *PX86_PE, **PPX86_PE;

#define X86_PE_ sizeof (X86_PE)

列表 4-3. i386 的 PDBR 、 PDE 、 PTE 和 PNPE

列表 4-4 中,我增加了線性地址的結構化表示。這些結構是 4-3 4-4 中的“線性地址”的正式形式。

l X86_LINEAR_4M 該結構是指向 4MB 數據頁的線性地址的正式形式,如 4-4 所示。頁目錄索引( PDI )是一個頁目錄的索引,頁目錄地址由 PDBR 給出,使用 PDI 可選擇頁目錄中的一個 PDE 。 22 位的 Offset 成員指向一個目標地址,此目標地址對應 4MB 的物理頁。

l X86_LINEAR_4K 是一個 4KB 線性地址類型的變量,如 4-3 所示。該結構由三個位域組成:和 4MB 地址類似,高 10 位為 PDI ,用來選擇一個 PDE ;頁表索引 PTI 的任務與 PDI 相似,指向由 PDE (該 PDE 由前面的 PDI 指定)確定的頁表中的一個 PTE ;剩余的 12 個位是在 4KB 物理頁中的偏移量。

l X86_LINEAR 是另一個為使用方便而加入的結構。該結構只是簡單的將 X86_LINEAR_4K 和 X86_LINEAR_4M 聯合為一個數據類型。詳見 列表 4-4

typedef struct _X86_LINEAR_4M // linear address (4-MB page)

{

union

{

struct

{

PVOID pAddress; // packed address

};

struct

{

unsigned Offset : 22; // offset into page

unsigned PDI : 10; // page-directory index

};

};

}

X86_LINEAR_4M, *PX86_LINEAR_4M, **PPX86_LINEAR_4M;

#define X86_LINEAR_4M_ sizeof (X86_LINEAR_4M)

// -----------------------------------------------------------------

typedef struct _X86_LINEAR_4K // linear address (4-KB page)

{

union

{

struct

{

PVOID pAddress; // packed address

};

struct

{

unsigned Offset : 12; // offset into page

unsigned PTI : 10; // page-table index

unsigned PDI : 10; // page-directory index

};

};

}

X86_LINEAR_4K, *PX86_LINEAR_4K, **PPX86_LINEAR_4K;

#define X86_LINEAR_4K_ sizeof (X86_LINEAR_4K)

// -----------------------------------------------------------------

typedef struct _X86_LINEAR // general linear address

{

union

{

PVOID pAddress; // packed address

X86_LINEAR_4M linear4M; // linear address (4-MB page)

X86_LINEAR_4K linear4K; // linear address (4-KB page)

};

}

X86_LINEAR, *PX86_LINEAR, **PPX86_LINEAR;

#define X86_LINEAR_ sizeof (X86_LINEAR)

列表 4-4. i386 的線性地址

宏和常量

列表 4-5 給出的定義是對 列表 4-2 列表 4-4 所示結構的補充,讓我們可以更容易的和 i386 內存管理一起工作。 列表 4-5 的定義可以分為三大組。第一組用于控制線性地址:

1. X86_PAGE_MASK X86_PDI_MASK X86_PTI_MASK 都是位掩碼( bit mask ),用來選擇線性地址中的某一部分。它們都基于常量: PAGE_SHIFT (12) 、 PDI-SHIFT (22) 和 PTI-SHIFT (12) ,這些常量定義于 Windows 2000 DDK 的頭文件 ntddk.h 中。 X86_PAGE_MASK 等價于 0xFFFFF000 ,可有效的屏蔽 4KB 線性地址( X86_LINEAR_4K )中的偏移量部分。 X86_PDI_MASK 等價于 0xFFC00000 ,顯然這可從線性地址中提取高 10 位的 PDI 。 X86_PTI_MASK 等價于 0x003FF0000 ,用于屏蔽線性地址中除 PTI 外的所有位。

2. X86_PAGE() X86_PDI() X86_PTI() 使用上面的常量來計算給定線性地址的頁索引、 PDI 和 PTI 。 X86_PAGE() 一般用來從 Windows 2000 的 PTE 數組(該數組首地址為: 0xC0000000 )中讀取一個 PTE 。 X86_PDI() 和 X86_PTI() 只是針對給定的指針,簡單的使用 X86_PDI_MASK 或 X86_PTI_MASK ,并將得到的索引移動到最右邊。

3. X86_OFFSET_4M() X86_OFFSET_4K() 分別從 4MB 或 4KB 線性地址中提取偏移量部分。

4. X86_PAGE_4M X86_PAGE_4K 根據 DDK 中的常量 PDI_SHIFT 和 PTI_SHIFT 來計算 4MB 和 4KB 頁的大小。 X86_PAGE_4M=4,194,304 , X86_PAGE_4K=4,096 。注意, X86_PAGE_4K 等價于 DDK 常量 PAGE_SIZE ,該常量也定義于 ntddk.h 中。

5. X86_PAGES_4M X86_PAGES_4K 分別表示 4GB 地址空間中可容納的 4MB 或 4KB 頁的總數。 X86_PAGES_4M 等價于 1,024 , X86_PAGES_4K 等價于 1,048,576 。

#define X86_PAGE_MASK (0 - (1 << PAGE_SHIFT))

#define X86_PAGE(_p) (((DWORD) (_p) & X86_PAGE_MASK) >> PAGE_SHIFT)

#define X86_PDI_MASK (0 - (1 << PDI_SHIFT))

#define X86_PDI(_p) (((DWORD) (_p) & X86_PDI_MASK) >> PDI_SHIFT)

#define X86_PTI_MASK ((0 - (1 << PTI_SHIFT)) & ~X86_PDI_MASK)

#define X86_PTI(_p) (((DWORD) (_p) & X86_PTI_MASK) >> PTI_SHIFT)

#define X86_OFFSET(_p,_m) ((DWORD_PTR) (_p) & ~(_m))

#define X86_OFFSET_4M(_p) X86_OFFSET (_p, X86_PDI_MASK)

#define X86_OFFSET_4K(_p) X86_OFFSET (_p, X86_PDI_MASK|X86_PTI_MASK)

#define X86_PAGE_4M (1 << PDI_SHIFT)

#define X86_PAGE_4K (1 << PTI_SHIFT)

#define X86_PAGES_4M (1 << (32 - PDI_SHIFT))

#define X86_PAGES_4K (1 << (32 - PTI_SHIFT))

// -----------------------------------------------------------------

#define X86_PAGES 0xC0000000

#define X86_PTE_ARRAY ((PX86_PE) X86_PAGES)

#define X86_PDE_ARRAY (X86_PTE_ARRAY + (X86_PAGES >> PTI_SHIFT))

// -----------------------------------------------------------------

#define X86_SEGMENT_OTHER 0

#define X86_SEGMENT_CS 1

#define X86_SEGMENT_DS 2

#define X86_SEGMENT_ES 3

#define X86_SEGMENT_FS 4

#define X86_SEGMENT_GS 5

#define X86_SEGMENT_SS 6

#define X86_SEGMENT_TSS 7

// -----------------------------------------------------------------

#define X86_SELECTOR_RPL 0x0003

#define X86_SELECTOR_TI 0x0004

#define X86_SELECTOR_INDEX 0xFFF8

#define X86_SELECTOR_SHIFT 3

#define X86_SELECTOR_LIMIT (X86_SELECTOR_INDEX >>

X86_SELECTOR_SHIFT)

// -----------------------------------------------------------------

#define X86_DESCRIPTOR_SYS_TSS16A 0x1

#define X86_DESCRIPTOR_SYS_LDT 0x2

#define X86_DESCRIPTOR_SYS_TSS16B 0x3

#define X86_DESCRIPTOR_SYS_CALL16 0x4

#define X86_DESCRIPTOR_SYS_TASK 0x5

#define X86_DESCRIPTOR_SYS_INT16 0x6

#define X86_DESCRIPTOR_SYS_TRAP16 0x7

#define X86_DESCRIPTOR_SYS_TSS32A 0x9

#define X86_DESCRIPTOR_SYS_TSS32B 0xB

#define X86_DESCRIPTOR_SYS_CALL32 0xC

#define X86_DESCRIPTOR_SYS_INT32 0xE

#define X86_DESCRIPTOR_SYS_TRAP32 0xF

// -----------------------------------------------------------------

#define X86_DESCRIPTOR_APP_ACCESSED 0x1

#define X86_DESCRIPTOR_APP_READ_WRITE 0x2

#define X86_DESCRIPTOR_APP_EXECUTE_READ 0x2

#define X86_DESCRIPTOR_APP_EXPAND_DOWN 0x4

#define X86_DESCRIPTOR_APP_CONFORMING 0x4

#define X86_DESCRIPTOR_APP_CODE 0x8

列表 4-5. 附加的 i386 內存管理相關定義

第二組宏和常量與 Windows 2000 的 PDE 、 PTE 數組有關。和其他幾個系統地址不同,這些數組的基地址并沒有在系統啟動時作為一個全局變量出現,而是被定義成了一個常量。可以通過反編譯內存管理 API 函數: MmGetPhysicalAddress() 和 MmIsAddressValid() 來證明,在這些函數里,這些地址都以“魔術數字”的形式出現。這些常量并沒有包括在 DDK 頭文件中,不過 列表 4-5 展示了如何定義它們。

l X86_PAGES 是一個硬編碼的地址和指針(指向 0xC0000000 ), 0xC0000000 是 Windows 2000 的 PTE 數組開始的地方。

X86_PTE_ARRAY 等價于 X86_PAGES ,但是被轉型為 PX86_PE ,也就是說,指向一個 X86_PE 類型的數組, X86_PE 定義于列表 4-2 。

X86_PDE_ARRAY 是一個巧妙的定義,它通過 PTE 數組的位置來計算 PDE 數組的基地址,這需要用到 PTI_SHIFT 常量。將線性地址映射為 PTE 地址的通用格式為:(( LinearAdress >> 12 ) *4 ) +0xC0000000 ,線性地址 0xC0000000 轉換后的地址為頁目錄的基地址。

列表 4-5 的最后兩部分包括選擇器和特殊類型的描述符,以及對 列表 4-2 的補充。

l X86_SELECTOR_RPL 、 X86_SELECTOR_TI 和 X86_SELECTOR_INDEX 都是位掩碼,分別對應 X86_SELECTOR 結構中的 RPL 、 TI 和 Index 成員。

l X86_SELECTOR_SHIFT 是一個右移因子,用來使選擇器的 Index 的數值向右對齊。

l X86_SELECTOR_LIMIT 定義了選擇器可使用的最大索引值,該限制為 8,191 。這個值確定了描述符表的最大尺寸。每個選擇器索引均指向一個描述符,每個描述符包含 64 個位(即 8 個字節)。所以,描述符表的最大尺寸為: 8,192*8=64KB 。

l X86_DESCRIPTOR_SYS_* 是一組常量,用于定義系統描述符類型。如果描述符的 S 位被設為 0 ,那么描述的 Type 成員將采用這一組類型中的某一個。請參考 列表 4-2 中的 X86_DESCRIPTOR 的定義。系統描述符類型在 Intel 手冊中有詳細介紹( Intel 1999c, pp. 3-15f ), 4-1 給出了所有可用的系統描述符類型。

列表 4-5 中的 X86_DESCRIPTOR_APP_* 常量也可用于定義描述符的 Type 成員,前提是描述符的 S 位不為 0 。此時,該應用程序描述符可能需要引用一個代碼或數據段。因為應用程序描述符類型的屬性受 Type 域的第四個位影響,所以 X86_DESCRIPTOR_APP_* 常量被定義為單位掩碼( single-bit mask ),這樣一些位就可針對數據和代碼段有不同的解釋。

l X86_DESCRIPTOR_APP_ACCESSED 如果一個段可以被訪問,則采用

l X86_DESCRIPTOR_APP_READ_WRITE 決定一個數據段是否允許只讀或讀 / 寫訪問。

l X86_DESCRIPTOR_APP_CONFORMATING 說明一個代碼段是否相匹配。也就是說,它是否可以被以被弱特權代碼( less privileged code )調用(參考 Intel 1999c,pp. 4-13ff )。

l X86_DESCRIPTOR_APP_CODE 用來區別代碼段和數據段。注意,堆棧屬于數據段的范疇,而且必須總是可寫的。

稍后,當下一章中的 Memory Spy 程序開始運行時,我們將重溫系統描述符。 4-1 算是 i386 內存管理的一個簡短總結。有關本話題的更多內容,請參考 Intel Pentium 手冊( Intel 1999a , 1999b , 1999c )。

表 4-1. 系統描述符類型

X86_DESCRIPTOR_SYS_TSS16A

0x1

16 位任務狀態段(可用)

X86_DESCRIPTOR_SYS_LDT

0x2

本地描述符表( LDT )

X86_DESCRIPTOR_SYS_TSS16B

0x3

16 位任務狀態段(繁忙)

X86_DESCRIPTOR_SYS_CALL16

0x4

16 位調用門

X86_DESCRIPTOR_SYS_TASK

0x5

任務門

X86_DESCRIPTOR_SYS_INT16

0x6

16 位中斷門

X86_DESCRIPTOR_SYS_TRAP16

0x7

16 位陷阱門

X86_DESCRIPTOR_SYS_TSS32A

0x9

32 位任務狀態段(可用)

X86_DESCRIPTOR_SYS_TSS32B

0xB

32 位任務狀態段(繁忙)

X86_DESCRIPTOR_SYS_CALL32

0xC

32 位調用門

X86_DESCRIPTOR_SYS_INT32

0xE

32 位中斷門

X86_DESCRIPTOR_SYS_TRAP32

0XF

32 位陷阱門

標簽: Windows系統
主站蜘蛛池模板: 在线毛片一区二区不卡视频 | 91精品欧美综合在线观看 | 亚洲免费色| 久久99精品久久久久久久野外 | 丝袜一级片 | 中文字幕有码视频 | 欧美xxxxx色视频在线观看 | 久久国产精品高清一区二区三区 | 日本欧美三级 | 免费a级毛片大学生免费观看 | 老太婆性杂交毛片 | 欧美日韩 在线播放 | 黄色网址网站 | 亚洲国产欧美精品一区二区三区 | 国产精品精品国产 | 国产一级视频在线 | 91大神大战丝袜美女在线观看 | 国产在线一区二区 | 日本三级全黄三级a | 国产不卡精品一区二区三区 | 全部免费a级毛片 | 鲁丝片一区二区三区免费 | 99毛片| 免费国产成人高清在线看软件 | 欧美一级第一免费高清 | 美女张开腿让男人桶的 视频 | 午夜桃色剧场 | 亚洲精品成人 | 欧美极品在线播放 | 最新国产成人综合在线观看 | 免费看真人a一级毛片 | 三a毛片 | 午夜私人影院免费体验区 | 成人国产片免费 | 亚洲欧美日韩中文字幕在线一 | 一级毛片一片毛 | av在线手机播放 | 一区自拍 | 国产亚洲精 | 国产亚洲综合成人91精品 | 午夜精品久久久久久毛片 |