Windows内核的表学习总结
生活随笔
收集整理的這篇文章主要介紹了
Windows内核的表学习总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
SSDT - 系統服務描述符表
SSDT(System Services Descriptor Table),系統服務描述符表。這個表就是一個把ring3的Win32?
API和ring0的內核函數聯系起來。SSDT并不僅僅只包含一個龐大的地址索引表,它還包含著一些其它有
用的信息,諸如地址索引的基地址、服務函數個數等。
中文名系統服務描述符表 外文名 System Services Descriptor Table 別 ? ?稱 SSDT 包 ? ?含 服務
函數個數
目錄
1 簡介
2 SSDT的結構
簡介
通過修改此表的函數地址可以對常用windows函數進行hook,從而實現對一些關心的系統動作進行過濾、
監控的目的。一些HIPS、防毒軟件、系統監控、注冊表監控軟件往往會采用此接口來實現自己的監控模
塊,
SSDT到底是什么呢?打一個比方,SSDT相當于系統內部API的指向標,作用就是告訴系統,需要調用的
API在什么地方。
SSDT的結構
:
引用:
typedef struct _SYSTEM_SERVICE_TABLE
{
PVOID ServiceTableBase; //這個指向系統服務函數地址表
PULONG ServiceCounterTableBase;
ULONG NumberOfService; //服務函數的個數
ULONG ParamTableBase;
}SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE;
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
SYSTEM_SERVICE_TABLE ntoskrnel; //ntoskrnl.exe的服務函數
SYSTEM_SERVICE_TABLE win32k; //win32k.sys的服務函數,(gdi.dll/user.dll的內核支持)
SYSTEM_SERVICE_TABLE NotUsed1;
SYSTEM_SERVICE_TABLE NotUsed2;
}SYSTEM_DESCRIPTOR_TABLE,*PSYSTEM_DESCRIPTOR_TABLE;
實際上內核中存在兩個系統服務描述符表,一個是KeServiceDescriptorTable(由ntoskrnl.exe導出)
,一個是KeServieDescriptorTableShadow(沒有導出)。
從上述結構中,我們可以看出,KeServieDescriptorTableShadow不但包含了ntoskrnel項,而且還包含
了win32k項,而KeServiceDescriptorTable僅僅包含一個ntoskrnel項。
我們用WinDbg看看,到底這個KeServiceDescriptorTable是什么東西。
引用:
lkd> dd KeServiceDescriptorTable
80553380 81f61008 00000000 0000013d 81e62358
80553390 00000000 00000000 00000000 00000000
805533a0 00000000 00000000 00000000 00000000
805533b0 00000000 00000000 00000000 00000000
805533c0 00002710 bf80c217 00000000 00000000
805533d0 f8951a80 f80839e0 81f433a8 806e0f40
805533e0 00000000 00000000 00000000 00000000
805533f0 83740440 01c8eac3 00000000 00000000
我們可以看出,函數表基地址為81f61008,存在0000013d個服務項
我們繼續看看81f61008地址的內存塊內,到底放了些什么。
引用:
lkd> dd 81f61008
81f61008 80599746 805e6914 805ea15a 805e6946
81f61018 805ea194 805e697c 805ea1d8 805ea21c
81f61028 8060b880 8060c5d2 805e1cac 805e1904
81f61038 805ca928 805ca8d8 8060bea6 805ab334
81f61048 8060b4be 8059dbbc 805a5786 f8807de8
81f61058 804ffed0 8060c5c4 8056be64 805353f2
81f61068 80604b90 805b19c0 805ea694 80619a56
81f61078 805eeb86 80599e34 80619caa 805996e6
這里面的數據到底表示什么呢?實際上,這表示的是一個入口地址。我們對其中一個地址進行反匯編看
看
引用:
lkd> u 80599746
nt!NtConnectPort+0x60:
80599746 689c000000 push 9Ch
8059974b 6820a14d80 push offset nt!FsRtlLegalAnsiCharacterArray+0x1680 (804da120)
80599750 e8abebf9ff call nt!wctomb+0x45 (80538300)
80599755 64a124010000 mov eax,dword ptr fs:[00000124h]
8059975b 8a8040010000 mov al,byte ptr [eax+140h]
80599761 884590 mov byte ptr [ebp-70h],al
80599764 84c0 test al,al
80599766 0f84b9010000 je nt!NtConnectPort+0x23f (80599925)
========
中斷描述符表
中斷描述符表(Interrupt Descriptor Table,IDT)將每個異常或中斷向量分別與它們的處理過程聯系起來。與GDT和LDT表類似,IDT也是由8字節長描述符組成的一個數組。與GDT不同的是,表中第1項
可以包含描述符。為了構成IDT表中的一個索引值,處理器把異常或中斷的向量號乘以8。因為最多只
有256個中斷或異常向量,所以IDT無需包含多于256個描述符。IDT中可以含有少于256個描述符,因為
只有可能發生的異常或中斷才需要描述符。不過IDT中所有空描述符項應該設置其存在位(標志)為0
。
IDT表可以駐留在線性地址空間的任何地方,處理器使用IDTR寄存器來定位IDT表的位置。這個寄存器
中含有IDT表32位的基地址和16位的長度(限長)值,如圖4-26所示。IDT表基地址應該對齊在8字節邊
界上以提高處理器的訪問效率。限長值是以字節為單位的IDT表的長度。
中斷描述符表IDT和寄存器IDTR
LIDT和SIDT指令分別用于加載和保存IDTR寄存器的內容。LIDT指令用于把內存中的限長值和基地址操
作數加載到IDTR寄存器中。該指令僅能由當前特權級CPL是0的代碼執行,通常被用于創建IDT時的操作
系統初始化代碼中。SIDT指令用于把IDTR中的基地址和限長內容復制到內存中。該指令可在任何特權
級上執行。
如果中斷或異常向量引用的描述符超過了IDT的界限,處理器會產生一個一般保護性異常
在實地址模式中,CPU把內存中從0開始的1K字節作為一個中斷向量表。表中的每個表項占四個字節,由
兩個字節的段地址和兩個字節的偏移量組成,這樣構成的地址便是相應中斷處理程序的入口地址。但是
,在保護模式下,由四字節的表項構成的中斷向量表顯然滿足不了要求。這是因為,?除了兩個字節的段
描述符,偏移量必用四字節來表示;?要有反映模式切換的信息。因此,在保護模式下,中斷向量表中的
表項由8個字節組成,中斷向量表也改叫做中斷描述符表IDT(InterruptDescriptor Table)。其中的每
個表項叫做一個門描述符(gate descriptor),“門”的含義是當中斷發生時必須先通過這些門,然后
才能進入相應的處理程序。
門描述符
· 中斷門(Interrupt gate)
其類型碼為110,中斷門包含了一個中斷或異常處理程序所在段的選擇符和段內偏移量。當控制權通過中
斷門進入中斷處理程序時,處理器清IF標志,即關中斷,以避免嵌套中斷的發生。中斷門中的DPL
(Descriptor Privilege Level)為0,因此,用戶態的進程不能訪問Intel的中斷門。所有的中斷處理
程序都由中斷門激活,并全部限制在內核態。
· 陷阱門(Trap gate)
其類型碼為111,與中斷門類似,其唯一的區別是,控制權通過陷阱門進入處理程序時維持IF標志位不變
,也就是說,不關中斷。
· 系統門(System gate)
這是Linux內核特別設置的,用來讓用戶態的進程訪問Intel的陷阱門,因此,門描述符的DPL為3。通過
系統門來激活4個Linux異常處理程序,它們的向量是3、4、5及128,也就是說,在用戶態下,可以使用
int3、into、bound 及int0x80四條匯編指令。
最后,在保護模式下,中斷描述符表在內存的位置不再限于從地址0開始的地方,而是可以放在內存的任
何地方。為此,CPU中增設了一個中斷描述符表寄存器IDTR,用來存放中斷描述符表在內存的起始地址。
中斷描述符表寄存器IDTR是一個48位的寄存器,其低16位保存中斷描述符表的大小,高32位保存IDT的基
址.
========
GDT 與 LDT
http://www.cnblogs.com/hicjiajia/archive/2012/05/25/2518684.html很長時間沒碰組成原理和操作系統,忘得差不多了,今天學內核需要一些基礎知識,搜了些文章補習一
下,這篇講描述符表的文章比較不錯:
原文地址:http://blog.csdn.net/billpig/article/details/5833980
另外,在oldlinux上有一篇帖子也是討論這個的,看完上面的文章再看這篇帖子就比較明了了:
原文地址:http://www.oldlinux.org/oldlinux/viewthread.php?tid=9420
保護模式下的段寄存器 由 16位的選擇器 與 64位的段描述符寄存器 構成
段描述符寄存器 : 存儲段描述符
選擇器 ? ? ? ? ? ?: 存儲段描述符的索引
PS:原先實模式下的各個段寄存器作為保護模式下的段選擇器,80486中有6個(即CS,SS,DS,ES,FS,GS)80
位的段寄存器,同時提供6個段左右機器當前運行的地址空間。由選擇器CS對應表示的段仍為代碼段,選
擇器SS對應表示的段仍為堆棧段
?(1)全局描述符表GDT(Global Descriptor Table)在整個系統中,全局描述符表GDT只有一張(一個
處理器對應一個GDT),GDT可以被放在內存的任何位置,但CPU必須知道GDT的入口,也就是基地址放在哪
里,Intel的設計者門提供了一個寄存器GDTR用來存放GDT的入口地址,程序員將GDT設定在內存中某個位
置之后,可以通過LGDT指令將GDT的入口地址裝入此積存器,從此以后,CPU就根據此寄存器中的內容作
為GDT的入口來訪問GDT了。GDTR中存放的是GDT在內存中的基地址和其表長界限。
GDTR結構
(2)段選擇子(Selector)由GDTR訪問全局描述符表是通過“段選擇子”(實模式下的段寄存器)來完
成的,如圖三①步。段選擇子是一個16位的寄存器(同實模式下的段寄存器相同)如圖四
selector
段選擇子包括三部分:描述符索引(index)、TI、請求特權級(RPL)。他的index(描述符索引)部分
表示所需要的段的描述符在描述符表的位置,由這個位置再根據在GDTR中存儲的描述符表基址就可以找
到相應的描述符(如圖三①步)。然后用描述符表中的段基址加上邏輯地址(SEL:OFFSET)的OFFSET就
可以轉換成線性地址(如圖三②步),段選擇子中的TI值只有一位0或1,0代表選擇子是在GDT選擇,1代
表選擇子是在LDT選擇。請求特權級(RPL)則代表選擇子的特權級,共有4個特權級(0級、1級、2級、3
級)。
關于特權級的說明:任務中的每一個段都有一個特定的級別。每當一個程序試圖訪問某一個段時,就將
該程序所擁有的特權級與要訪問的特權級進行比較,以決定能否訪問該段。系統約定,CPU只能訪問同一
特權級或級別較低特權級的段。
例如給出邏輯地址:21h:12345678h轉換為線性地址
a. 選擇子SEL=21h=0000000000100 0 01b 他代表的意思是:選擇子的index=4即100b選擇GDT中的第4個
描述符;TI=0代表選擇子是在GDT選擇;左后的01b代表特權級RPL=1
b. OFFSET=12345678h若此時GDT第四個描述符中描述的段基址(Base)為11111111h,則線性地址
=11111111h+12345678h=23456789h
(3)局部描述符表LDT(Local Descriptor Table)局部描述符表可以有若干張,每個任務可以有一張
。我們可以這樣理解GDT和LDT:GDT為一級描述符表,LDT為二級描述符表。如圖
gdt尋址
LDT和GDT從本質上說是相同的,只是LDT嵌套在GDT之中。LDTR記錄局部描述符表的起始位置,與GDTR不
同LDTR的內容是一個段選擇子。由于LDT本身同樣是一段內存,也是一個段,所以它也有個描述符描述它
,這個描述符就存儲在GDT中,對應這個表述符也會有一個選擇子,LDTR裝載的就是這樣一個選擇子。
LDTR可以在程序中隨時改變,通過使用lldt指令。如上圖,如果裝載的是Selector 2則LDTR指向的是表
LDT2。舉個例子:如果我們想在表LDT2中選擇第三個描述符所描述的段的地址12345678h。
1. 首先需要裝載LDTR使它指向LDT2 使用指令lldt將Select2裝載到LDTR
2. 通過邏輯地址(SEL:OFFSET)訪問時SEL的index=3代表選擇第三個描述符;TI=1代表選擇子是在LDT
選擇,此時LDTR指向的是LDT2,所以是在LDT2中選擇,此時的SEL值為1Ch(二進制為11 1 00b)。
OFFSET=12345678h。邏輯地址為1C:12345678h
3. 由SEL選擇出描述符,由描述符中的基址(Base)加上OFFSET可得到線性地址,例如基址是11111111h
,則線性地址=11111111h+12345678h=23456789h
4. 此時若再想訪問LDT1中的第三個描述符,只要使用lldt指令將選擇子Selector 1裝入再執行2、3兩步
就可以了(因為此時LDTR又指向了LDT1)
由于每個進程都有自己的一套程序段、數據段、堆棧段,有了局部描述符表則可以將每個進程的程序段
、數據段、堆棧段封裝在一起,只要改變LDTR就可以實現對不同進程的段進行訪問。
段描述符:
P,present位,1表示所描述的段存在(有效),為0表示所描述的段無效,使用該描述符會引起異常?
DPL,Descriptor privilege,描述符特權級別,說明所描述段的特權級別?
DT,描述符類型位,1說明當前描述符為存儲段描述符,0為系統描述符或門描述符.?
TYPE:?
位0:A(accessed)位,表明描述符是否已被訪問;把選擇子裝入段寄存器時,該位被標記為1?
位3:E(EXECUTABLE?)位,0說明所描述段為數據段;1為可執行段(代碼段)?
當為數據段時,?
? ?位1為W位,說明該數據段是否可寫(0只讀,1可寫)?
? ?位2為ED位,說明該段的擴展方向(0向高位擴展,1向低位擴展)?
當為可執行段是,?
? ?位1為R位,說明該執行段是否可讀(0只執行,1可讀)?
? ?位2為C位,0說明該段不是一致碼段(普通代碼段),1為一致碼段?
G為粒度位,0說明LIMIT粒度為字節,1為4K字節.?
D位:?
? ?1.在可執行段中,D為1,表示使用32位地址,32/8位操作數;為0表示使用16位地址,16/8位操作數?
? ?2.在由SS尋址的段描述符(堆棧段?)中,D為1表示隱含操作(如PUSH/POP)使用ESP為堆棧指針,/
? ? ?為0使用SP(隱含操作:未明確定義段屬性類型USE16/USE32?66H,67H?)?
? ?3.在向低擴展的存儲段中,D為1,表示段的上限為4G;為0上限為64K
?
存儲段描述符的結構表示:
分段管理可以把虛擬地址轉換成線性地址,而分頁管理可以進一步將線性地址轉換成物理地址。當CR0中
的PG位置1時,啟動分頁管理功能,為0時,這禁止啟動分頁管理功能,并且把線性地址作物理地址使用
。
虛擬地址轉為線性地址:
線性地址= 段基指 + 偏移地址
32位線性地址轉為物理地址:
32位分為:
頁目錄索引:占最高10位,指示頁目錄表中第幾個頁表描述符
頁表索引:占12位到21位,也是10位。指示這頁表中第幾個頁描述符
頁描述符:線性地址的低12位為頁內偏移量。
========
GDT、GDTR、LDT、LDTR的學習
http://blog.csdn.net/yeruby/article/details/39718119#t3 ?目錄(?)[+]
GDT的由來:
在Protected Mode下,一個重要的必不可少的數據結構就是GDT(Global Descriptor Table)。
為什么要有GDT?我們首先考慮一下在Real Mode下的編程模型:
在Real Mode下,我們對一個內存地址的訪問是通過Segment:Offset的方式來進行的,其中Segment是一
個段的Base Address,一個Segment的最大長度是64 KB,這是16-bit系統所能表示的最大長度。而
Offset則是相對于此Segment Base Address的偏移量。Base Address+Offset就是一個內存絕對地址。由
此,我們可以看出,一個段具備兩個因素:Base Address和Limit(段的最大長度),而對一個內存地址
的訪問,則是需要指出:使用哪個段?以及相對于這個段Base Address的Offset,這個Offset應該小于
此段的Limit。當然對于16-bit系統,Limit不要指定,默認為最大長度64KB,而 16-bit的Offset也永遠
不可能大于此Limit。我們在實際編程的時候,使用16-bit段寄存器CS(Code Segment),DS(Data?
Segment),SS(Stack Segment)來指定Segment,CPU將段積存器中的數值向左偏移4-bit,放到20-bit
的地址線上就成為20-bit的Base Address。
到了Protected Mode,內存的管理模式分為兩種,段模式和頁模式,其中頁模式也是基于段模式的。也
就是說,Protected Mode的內存管理模式事實上是:純段模式和段頁式。進一步說,段模式是必不可少
的,而頁模式則是可選的——如果使用頁模式,則是段頁式;否則這是純段模式。
既然是這樣,我們就先不去考慮頁模式。對于段模式來講,訪問一個內存地址仍然使用Segment:Offset
的方式,這是很自然的。由于 Protected Mode運行在32-bit系統上,那么Segment的兩個因素:Base?
Address和Limit也都是32位的。IA-32允許將一個段的Base Address設為32-bit所能表示的任何值
(Limit則可以被設為32-bit所能表示的,以2^12為倍數的任何指),而不像Real Mode下,一個段的
Base Address只能是16的倍數(因為其低4-bit是通過左移運算得來的,只能為0,從而達到使用16-bit
段寄存器表示20-bit Base Address的目的),而一個段的Limit只能為固定值64 KB。另外,Protected?
Mode,顧名思義,又為段模式提供了保護機制,也就說一個段的描述符需要規定對自身的訪問權限
(Access)。所以,在Protected Mode下,對一個段的描述則包括3方面因素:【Base Address, Limit,?
Access】,它們加在一起被放在一個64-bit長的數據結構中,被稱為段描述符。這種情況下,如果我們
直接通過一個64-bit段描述符來引用一個段的時候,就必須使用一個64-bit長的段寄存器裝入這個段描
述符。但Intel為了保持向后兼容,將段寄存器仍然規定為16-bit(盡管每個段寄存器事實上有一個64-
bit長的不可見部分,但對于程序員來說,段寄存器就是16-bit的),那么很明顯,我們無法通過16-bit
長度的段寄存器來直接引用64-bit的段描述符。
怎么辦?解決的方法就是把這些長度為64-bit的段描述符放入一個數組中,而將段寄存器中的值作為下
標索引來間接引用(事實上,是將段寄存器中的高13 -bit的內容作為索引)。這個全局的數組就是GDT
。事實上,在GDT中存放的不僅僅是段描述符,還有其它描述符,它們都是64-bit長。GDT是Protected?
Mode所必須的數據結構,也是唯一的。另外,正像它的名字(Global Descriptor Table)所揭示的,它
是全局可見的,對任何一個任務而言都是這樣。
GDT的構成:
GDT的結構圖如下:(GDT表相當于一個64bit的數組)
1、G:
(1)、G=0時,段限長的20位為實際段限長,最大限長為2^20=1MB
(2)、G=1時,則實際段限長為20位段限長乘以2^12=4KB,最大限長達到4GB
2、D/B:
當描述符指向的是可執行代碼段時,這一位叫做D位,D=1使用32位地址和32/8位操作數,D=0使用16位地
址和16/8位操作數。如果指向的是向下擴展的數據段,這一位叫做B位,B=1時段的上界為4GB,B=0時段
的上界為64KB。如果指向的是堆棧段,這一位叫做B位,B=1使用32位操作數,堆棧指針用ESP,B=0時使
用16位操作數,堆棧指針用SP。
3、DPL:特權級,0為最高特權級,3為最低,表示訪問該段時CPU所需處于的最低特權級
4、type : 類型
(1)、type<8時:數據段
(2)、type>=8時:代碼段
GDTR是什么?
GDT可以被放在內存的任何位置,那么當程序員通過段寄存器來引用一個段描述符時,CPU必須知道GDT的
入口,也就是基地址放在哪里,所以Intel的設計者門提供了一個寄存器GDTR用來存放GDT的入口地址,
程序員將GDT設定在內存中某個位置之后,可以通過LGDT指令將GDT的入口地址裝入此寄存器,從此以后
,CPU就根據此寄存器中的內容作為GDT的入口來訪問GDT了。
LDT是什么?
除了GDT之外,IA-32還允許程序員構建與GDT類似的數據結構,它們被稱作LDT(Local Descriptor?
Table,局部描述符表),但與GDT不同的是,LDT在系統中可以存在多個,并且從LDT的名字可以得知,
LDT不是全局可見的,它們只對引用它們的任務可見,每個任務最多可以擁有一個LDT。另外,每一個LDT
自身作為一個段存在,它們的段描述符被放在GDT中。
?LDT只是一個可選的數據結構,你完全可以不用它。使用它或許可以帶來一些方便性,但同時也帶來復
雜性,如果你想讓你的OS內核保持簡潔性,以及可移植性,則最好不要使用它。
LDTR是什么?
IA-32為LDT的入口地址也提供了一個寄存器LDTR,因為在任何時刻只能有一個任務在運行,所以LDT寄存
器全局也只需要有一個。如果一個任務擁有自身的LDT,那么當它需要引用自身的LDT時,它需要通過
lldt指令將其LDT的段描述符裝入此寄存器。lldt指令與lgdt指令不同的時,lgdt指令的操作數是一個
32-bit的內存地址,這個內存地址處存放的是一個32-bit GDT的入口地址,以及16-bit的GDT Limit。而
lldt指令的操作數是一個16-bit的選擇子,這個選擇子主要內容是:被裝入的LDT的段描述符在GDT中的
索引值。
至此,我們可以這樣理解GDT和LDT:GDT為一級描述符表,LDT為二級描述符表。如圖:
、
例如:如果我們想在表LDT2中選擇第三個描述符所描述的段的地址12345678h。
1. 首先需要裝載LDTR使它指向LDT2:使用指令lldt將Select2裝載到LDTR。
2. 通過邏輯地址(SEL:OFFSET)訪問時SEL的index=3代表選擇第三個描述符;TI=1代表選擇子是在LDT
選擇,此時LDTR指向的是LDT2,所以是在LDT2中選擇,此時的SEL值為1C h(二進制為11 1 00b),
OFFSET=12345678h。邏輯地址為1C:12345678h。
3. 由SEL選擇出描述符,由描述符中的基址(Base)加上OFFSET可得到線性地址,例如基址是11111111h
,則線性地址=11111111h+12345678h=23456789h。
4. 此時若再想訪問LDT1中的第三個描述符,只要使用lldt指令將選擇子Selector 1裝入再執行2、3兩步
就可以了(因為此時LDTR又指向了LDT1)。
由于每個進程都有自己的一套程序段、數據段、堆棧段,有了局部描述符表則可以將每個進程的程序段
、數據段、堆棧段封裝在一起,只要改變LDTR就可以實現對不同進程的段進行訪問。
段選擇子是什么?
引用GDT和LDT中的段描述符所描述的段,是通過一個16-bit的數據結構來實現的,這個數據結構叫做
Segment Selector——段選擇子。它的高13位作為被引用的段描述符在GDT/LDT中的下標索引,bit 2用
來指定被引用段描述符被放在GDT中還是到LDT中,bit 0和bit 1是RPL——請求特權等級,被用來做保護
目的。如圖所示:
前面所討論的裝入段寄存器中作為GDT/LDT索引的就是Segment Selector,當需要引用一個內存地址時,
使用的仍然是Segment:Offset模式,具體操作是:在相應的段寄存器裝入Segment Selector,按照這個
Segment Selector可以到GDT或LDT中找到相應的Segment Descriptor,這個Segment Descriptor中記錄
了此段的Base Address,然后加上Offset,就得到了最后的內存地址。
段選擇子包括三部分:描述符索引(index)、TI、請求特權級(RPL)。它的index(描述符索引)部分
表示所需要的段的描述符在描述符表的位置,由這個位置再根據在GDTR中存儲的描述符表基址就可以找
到相應的描述符。然后用描述符表中的段基址加上邏輯地址(SEL:OFFSET)的OFFSET就可以轉換成線性
地址,段選擇子中的TI值只有一位0或1,0代表選擇子是在GDT選擇,1代表選擇子是在LDT選擇。請求特
權級(RPL)則代表選擇子的特權級,共有4個特權級(0級、1級、2級、3級)。
關于特權級的說明:任務中的每一個段都有一個特定的級別。每當一個程序試圖訪問某一個段時,就將
該程序所擁有的特權級與要訪問的特權級進行比較,以決定能否訪問該段。系統約定,CPU只能訪問同一
特權級或級別較低特權級的段。
例如給出邏輯地址:21h:12345678h 轉換為線性地址的步驟如下:
(1)、選擇子SEL=21h=0000000000100 0 01b 它代表的意思是:選擇子的index=4即選擇GDT中的第4個
描述符;TI=0代表選擇子是在GDT選擇;最后的01代表特權級RPL=1
(2)、OFFSET=12345678h若此時GDT第四個描述符中描述的段基址(Base)為11111111h,則線性地址
=11111111h+12345678h=23456789h
關系:
計算機由實模式進入到保護模式要加載gdt,保護模式下的段寄存器由16位的選擇器與64位的段描述符寄
存器構成。
段描述符寄存器: 存儲段描述符;
選擇器:存儲段描述符的索引;
原先實模式下的各個段寄存器作為保護模式下的段選擇器,80486中有6個(即CS,SS,DS,ES,FS,GS)16位的
段寄存器
GDT可以被放在內存的任何位置,但CPU必須知道GDT的入口,也就是基地址放在哪里,Intel的設計者門
提供了一個寄存器GDTR用來存放GDT的入口地址,程序員將GDT設定在內存中某個位置之后,可以通過
LGDT指令將GDT的入口地址裝入此積存器,從此以后,CPU就根據此寄存器中的內容作為GDT的入口來訪問
GDT了。GDTR中存放的是GDT在內存中的基地址和其表長界限。
48bit的GDTR的結構:
由GDTR訪問GDT是通過“段選擇子”(實模式下的段寄存器)來完成的,即:
GDTR(48bit)+Segment Selector(由實模式下的段寄存器充當,16bit)= GDT中的某一項 (64bit)
Tips:
(1)、GDT中的所有描述符(除0項外,包括LDT描述符這種類型的描述符)都指定一個段,GDT中的LDT描
述符指定的是一個特殊的段, 這個段中只能存放LDT表,之所以說GDT中一個描述符是一個LDT段的描述符
,是因為這個描述符中有屬性說明這是一個LDT段.
(2)、
GDTR是一個48位的全局描述符寄存器,高32位存放GDT的基址,低16位存放GDT限長。
LDTR是一個16位的局部描述符寄存器,高13位存放LDT在GDT中的索引值。
GDT類似于一個 “數組” ,“數組元素” 可以是段描述符,也可以是LDT描述符。
例如:
若給定一個邏輯地址是 a:b ,根據邏輯地址的a(段選擇符)的T1位確定是選擇GDT還是LDT。
a、若是T1位選擇GDT,根據GDTR找到GDT的基址,根據a的 3~15位確定它的段描述符X在GDT中的位置
(GDTR即基址+a的3-15bit即相對位置):確定段描述符X,再根據段描述符提取出其中包含的段基址信
息,段基址+b(段內偏移),最終確定線性地址。
2)若是T1位選擇LDT,根據GDTR找到GDT的基址,根據LDTR的高13位確定它的LDTX描述符在GDT中的位置
(GDTR基址+LDTR13bit即相對位置):確定LDTX描述符。LDTX描述符可以確定LDT的基址(LDTX描述符確
定LDT表在內存中的起始位置),再根據段選擇符a確定的相對位置,可以確定LDT中的私有段描述符Y。
接下來同上面的:再根據段描述符提取出其中包含的段基址信息,段基址+b(段內偏移),最終確定線
性地址。
GDT中包含的段描述符X和LDT中包含的私有段描述符Y,所占空間相同。
GDT中包含的段描述符X和GDT中包含的LDT描述符,所占用空間相同。
結論是:LDT不包含在GDT中。GDT中只是包含了LDT描述符(一個指向LDT起始地址的指針)。
本文轉載自:《GDT與LDT》、《GDT詳解》和linux的GDT和LDT
========
總結
以上是生活随笔為你收集整理的Windows内核的表学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 魔影病毒学习总结
- 下一篇: 图解首次使用流光5.0