80386ASM程式設計基礎(十) (轉)
80386ASM程式設計基礎(十) (轉)[@more@]主要介紹段描述符,段選擇子
在保護下,段是實現虛擬地址到線性地址轉換的基礎。在保護方下,每個段有三個引數:段基址,段界限,段屬性。段基址規定了線性地址空間中段的開始地址,段基址長度為32位,所以任何一個段都可以從32位線性地址空間中的任何一個位元組開始,這一點和實式方式不同,實式方式下要求段的邊界必須被16整除。段界限規定段的大小,段界限用20位表示,而且段界限可以是位元組或4K為單位,這個稱為段的粒度。當段界限以位元組為單位時,那麼段的範圍是1位元組至1M位元組;當段界限是以4K位元組為單位時,那麼段的範圍是4K至4G。段的界限同時也是用來校驗偏移地址的合法性,比如說段A的基址為00123456H,段界限為1000H,如果段界限以位元組為單位,那麼段的範圍是00123456H-00124456H;如果段界限以4K位元組為單位,那麼段的範圍是00123456H-00223456H。事實上,段的界限也可以用來校驗偏移地址的合法性,上面的例子中界限為1000H,那麼偏移地址的範圍就是0-1000H,如果偏移地址不在這個範圍內那就會引起異常。需要說明的是,資料段有點特殊,因為資料段的偏移範圍不僅僅是由段界限來決定,還要由段的擴充套件方向(Extension Direction)來決定,因為要照顧到堆疊段(堆疊段是一種特殊的資料段,它是向低端地址擴充套件的),如果段界限為Limit,段的擴充套件方向為向高階地址擴充套件的話,那麼我們可以斷定它是一普通的資料段,0-Limit是有效的偏移範圍,而Limit以上屬於無效的偏移範圍;如果段界限為Limit,段的擴充套件方向為向低端地址擴充套件的話,那麼可以斷定它是一堆疊段,此時0-Limit是無效的偏移範圍,Limit以上則屬於有效的偏移範圍,正好和向高階地址擴充套件的普通資料段相反。除了堆疊段以外,其它的段均是自然向高階擴充套件。
段基址,段界限及段屬性這三個引數在保護模式下用描述符來描述,每個描述符的長度為8個位元組,每個段都有一個對應的描述符。在保護模式下有三種描述符:段描述符,段描述符,門描述符。
A.儲存段描述符:儲存段是指直接的程式碼段和資料段,儲存段描述符是用來描述儲存段的,也可以說是用來描述程式碼和資料段的,它的長度為8個位元組,該描述符結構示意圖:
第7位元組 第6位元組 第5位元組 第4位元組 第3位元組 第2位元組 第1位元組 第0位元組
|--------|------------------|-----------------------------|-----------------|
|段基址的| | | |
|高8位 |Segment Attributes| 段基址的低24位 | 段界限的低16位 |
| 24~31 | 段屬性,佔用兩 | 0~23 | 0~15 |
| | 個位元組 | | |
|--------|------------------|-----------------------------|-----------------|
| |
| |
_________| |_____________________________
| 15 14 13 12 11 8 7 6 5 3 0|
|---|---|---|---|-------------|---|--- -|---|------------|
| G | D |0 |AVL|段界限的高4位| P | DPL |DT | TYPE |
|---|---|---|---|--- ---------|---|-----|---|------------|
段基址和段界限都被安排在描述符的兩個域中,主要是來看段的屬性:
a.G(第15位),這是段界限粒度,即是說段界限到底是以位元組為單還是以4K位元組為單位。G=0表示段界限是位元組,G=1表示段界限為4K位元組。
b.D(第14位),D是一個很特殊的位,在描述可執行段,向低擴充套件資料段或者由SS暫存器定址的段。在描述可執行段的描述符中,D位決定了指令使用的地址及運算元據預設的大小,D=1表示預設情況下使用32位地址及32位或8位運算元,這樣的程式碼段稱為32位程式碼段;D=0表示預設情況下使用16位地址及16位運算元或8位運算元,這樣的程式碼段稱為16位程式碼段;在向低擴充套件的資料段中,D=1表示段的上部界限為4G,D=0表示段的上部界限為64K;在描述由SS暫存器定址的段中,該位決定使用隱式的堆疊訪問指令使用何種堆疊指標暫存器。D=1表示使用32位堆疊指標暫存器ESP,D=0表示使用16位堆疊指標暫存器SP,隱式的堆疊訪問指令指的是那些指令中沒有明顯對SP或ESP進行操作的指令,比如說PUSH,POP,PUSHA,POPA,PUSHAD,POPAD都屬於隱式的堆疊訪問指令。
c.0(第13位),這一位恆為0,為80386以後的保留的。
d.AVL(第12位),可利用位,主要是為了保持和以後的處理相容。
e.第11位到第8位是段界限的高4位。
f.P(第7位),存在位,P=1表示描述符對轉換地址有效。P=0表示描述符對轉換地址無效,如果使用該描述符將會引起異常。
g.DPL(Descriptor Privelege Level)描述符特權級,共2位,它規定了所述段的特權級別,用於特權檢查,以決定是否能對該段進行訪問。
h.DT(Descriptor Type)描述符的型別,DT=0表示儲存段描述符,DT=0表示系統段描述符和門描述符。
i.TYPE,共4位,說明儲存段的具體屬性:
TYPE0:指示描述符是否被訪問,用A標記,A=0表示描述符未被訪問,A=1表示描述符已被訪問。
TYPE1:根據TYPE3來確定。
TYPE2:根據TYPE3來確定。
TYPE3:指示描述符所描述的段是資料段還是程式碼段,用E標記。E=0表示是不可執行段,是資料段,對應的描述符也就是資料段描述符。E=1表示是可執行段,也就是程式碼段,對就的描述符也就是程式碼段描述符。
如果TYPE3=0,也就是說描述符是資料段描述符,那麼TYPE1指示該資料段是否可寫,用W標記。W=0表示對應的資料段不可寫,只讀。W=1表示對應的資料段可寫。TYPE2則指示資料段的擴充套件方向,用ED標記。ED=0表示向高階擴充套件,ED=1表示向低端擴充套件。
如果TYPE3=1,也就是說描述符是程式碼段描述符,那麼TYPE1指示該程式碼段是否可讀,用符號R標記。R=0表示對應的程式碼段不可讀,只能執行,R=1表示對應的程式碼可讀可執行。TYPE2則指示所描述的程式碼段是否是一致程式碼段,用C表示。C=0表示程式碼段不是一致程式碼段,C=1表示是一致程式碼段。
TYPE3-TYPE0這四位可以列成一個表:
___________________________________________________________________________________
|0000 |只讀 |
|_____|____________________________________________________________________________|
|0001 |只讀,已訪問 |
|_____|____________________________________________________________________________|
|0010 |可讀,可寫 |
|_____|____________________________________________________________________________|
|0011 |讀寫,已訪問 |
|_____|____________________________________________________________________________|
|0100 |只讀,向低擴充套件 |
|_____|____________________________________________________________________________|
|0101 |只讀,向低擴充套件 |
|_____|____________________________________________________________________________|
|0110 |讀/寫,向低擴充套件 |
|_____|____________________________________________________________________________|
|0111 |讀/寫,向低擴充套件,已訪問 |
|_____|____________________________________________________________________________|
|1000 |只執行 |
|_____|____________________________________________________________________________|
|1001 |只執行,已訪問 |
|_____|____________________________________________________________________________|
|1010 |可執行,可讀 |
|_____|____________________________________________________________________________|
|1011 |可執行,可讀,已訪問 |
|_____|____________________________________________________________________________|
|1100 |只執行,一致程式碼段 |
|_____|____________________________________________________________________________|
|1101 |只執行,一致程式碼段,已訪問 |
|_____|____________________________________________________________________________|
|1110 |可執行,可讀,一致程式碼段 |
|_____|____________________________________________________________________________|
|1111 |可執行,可讀,一致程式碼段,已訪問 |
|_____|____________________________________________________________________________|
儲存段描述符的結構可以這樣定義:
DESCRIPTOR STRUCT
Segment_LimitL16 DW 0;段界限的低16位
Segment_BaseL16 DW 0;段基址的低16位
Segment_BaseM8 0;段基址的中間8位
Segment_BaseH8 DB 0;段基址的高8位
Segment_Attributes DW 0;段屬性
DESCRIPTOR ENDS
一個任務有多個段,每個段都有一個描述符。因此在80386下,為了方便管理這些段描述符,將描述符組成一個線性表,稱之為描述符表。在80386下有三種描述符表:GDT(Global Descriptor Table),LDT(Local Descriptor Table),IDT(Interrupt Descriptor Table)。在整個系統中全域性描述符表GDT和中斷描述符表只有一張,區域性描述符表可以由若干張。每個描述符表都形成一個特殊的16位資料段,這樣的特殊資料段最多可以有8192個描述符,具體使用哪一個段描述符,由段的選擇子來確定。每個任務都有自已的區域性描述符表LDT,它包含自已的程式碼段,資料段,堆疊段,也包含該任務使用的一些門描述符。隨著任務的切換,LDT也跟著切換。GDT包含每一個任務都可能或可以訪問的段的描述符,通常包含描述所用的程式碼段,資料段以及堆疊段的描述符,也包含描述任務LDT的描述符。在任務切換時,並不切換GDT。一個任務的整個虛擬地址空間可以分為相等的兩半,一半空間的描述符在全域性描述符表GDT中,一半空的描述符在區域性描述符表LDT中。由於全域性描述符表和區域性描述符表都可以包含最多為8192個描述符,而每個描述符所描述的段的最大長度為4G,因此最大的虛擬地址空間為:8192*4G*2=64TB。
段選擇子用來確定使用描述符表中的哪一個描述符。實式模式下邏輯地址由段地址*16再加上段內偏移地址;保護模式下虛擬地址空間由段選擇子和段內偏移來確定,和實式模式比較,段選擇子代替了段值,實際上透過段選擇子就可以確定了段基址。選擇子的高13位是描述符表中的號,用來確定描述符,因為是13位,所以說最多可以有2的13次方8192個描述符,索引號:0-8191。標記TI指示是從全域性描述符中讀取描述符還是從區域性描述符表中讀取描述符。TI=0指示是從全域性描述符表中讀取描述符,TI=1指示從區域性描述符表讀取描述符。RPL表示請求特權級,用於特權檢查。假設段選擇子為88H,則表示請求的特權級別是0,從全域性描述表中讀取描述表,描述符的索引號為11H。有一個特殊的選擇子稱為空選擇子,它的Index=0(即高13位為0),TI=0,RPL則可以為任意值。當用空選擇子對儲存器進行訪問,會出現異常。空選擇子對應於全域性描述表中的第0個描述符,因此全域性描述符表中的第0個描述符總是不會被訪問。如果TI=1,那麼就不是空選擇子,它指定的是當前區域性描述符表中的第0個描述符。為了更快地從段選擇子中獲得段的基本資訊(段基址,段界限,段屬性),從80386開始為每個段暫存器在上配備了段描述符高速緩衝儲存器,對我們寫程式的人來講,它是不可的。有了這種高速緩衝暫存器後,每當將選擇子裝入段暫存器後,處理器將自動裝入描述符表中相應的描述符,並將描述表的資訊裝入到高速緩衝暫存器,這樣可以加快訪問速度,以下是段選擇子的結構示意圖:
15________________________________________________________________3__2__1_____0
| |TI | RPL |
|________________________________________________________________|___|________|
在保護下,段是實現虛擬地址到線性地址轉換的基礎。在保護方下,每個段有三個引數:段基址,段界限,段屬性。段基址規定了線性地址空間中段的開始地址,段基址長度為32位,所以任何一個段都可以從32位線性地址空間中的任何一個位元組開始,這一點和實式方式不同,實式方式下要求段的邊界必須被16整除。段界限規定段的大小,段界限用20位表示,而且段界限可以是位元組或4K為單位,這個稱為段的粒度。當段界限以位元組為單位時,那麼段的範圍是1位元組至1M位元組;當段界限是以4K位元組為單位時,那麼段的範圍是4K至4G。段的界限同時也是用來校驗偏移地址的合法性,比如說段A的基址為00123456H,段界限為1000H,如果段界限以位元組為單位,那麼段的範圍是00123456H-00124456H;如果段界限以4K位元組為單位,那麼段的範圍是00123456H-00223456H。事實上,段的界限也可以用來校驗偏移地址的合法性,上面的例子中界限為1000H,那麼偏移地址的範圍就是0-1000H,如果偏移地址不在這個範圍內那就會引起異常。需要說明的是,資料段有點特殊,因為資料段的偏移範圍不僅僅是由段界限來決定,還要由段的擴充套件方向(Extension Direction)來決定,因為要照顧到堆疊段(堆疊段是一種特殊的資料段,它是向低端地址擴充套件的),如果段界限為Limit,段的擴充套件方向為向高階地址擴充套件的話,那麼我們可以斷定它是一普通的資料段,0-Limit是有效的偏移範圍,而Limit以上屬於無效的偏移範圍;如果段界限為Limit,段的擴充套件方向為向低端地址擴充套件的話,那麼可以斷定它是一堆疊段,此時0-Limit是無效的偏移範圍,Limit以上則屬於有效的偏移範圍,正好和向高階地址擴充套件的普通資料段相反。除了堆疊段以外,其它的段均是自然向高階擴充套件。
段基址,段界限及段屬性這三個引數在保護模式下用描述符來描述,每個描述符的長度為8個位元組,每個段都有一個對應的描述符。在保護模式下有三種描述符:段描述符,段描述符,門描述符。
A.儲存段描述符:儲存段是指直接的程式碼段和資料段,儲存段描述符是用來描述儲存段的,也可以說是用來描述程式碼和資料段的,它的長度為8個位元組,該描述符結構示意圖:
第7位元組 第6位元組 第5位元組 第4位元組 第3位元組 第2位元組 第1位元組 第0位元組
|--------|------------------|-----------------------------|-----------------|
|段基址的| | | |
|高8位 |Segment Attributes| 段基址的低24位 | 段界限的低16位 |
| 24~31 | 段屬性,佔用兩 | 0~23 | 0~15 |
| | 個位元組 | | |
|--------|------------------|-----------------------------|-----------------|
| |
| |
_________| |_____________________________
| 15 14 13 12 11 8 7 6 5 3 0|
|---|---|---|---|-------------|---|--- -|---|------------|
| G | D |0 |AVL|段界限的高4位| P | DPL |DT | TYPE |
|---|---|---|---|--- ---------|---|-----|---|------------|
段基址和段界限都被安排在描述符的兩個域中,主要是來看段的屬性:
a.G(第15位),這是段界限粒度,即是說段界限到底是以位元組為單還是以4K位元組為單位。G=0表示段界限是位元組,G=1表示段界限為4K位元組。
b.D(第14位),D是一個很特殊的位,在描述可執行段,向低擴充套件資料段或者由SS暫存器定址的段。在描述可執行段的描述符中,D位決定了指令使用的地址及運算元據預設的大小,D=1表示預設情況下使用32位地址及32位或8位運算元,這樣的程式碼段稱為32位程式碼段;D=0表示預設情況下使用16位地址及16位運算元或8位運算元,這樣的程式碼段稱為16位程式碼段;在向低擴充套件的資料段中,D=1表示段的上部界限為4G,D=0表示段的上部界限為64K;在描述由SS暫存器定址的段中,該位決定使用隱式的堆疊訪問指令使用何種堆疊指標暫存器。D=1表示使用32位堆疊指標暫存器ESP,D=0表示使用16位堆疊指標暫存器SP,隱式的堆疊訪問指令指的是那些指令中沒有明顯對SP或ESP進行操作的指令,比如說PUSH,POP,PUSHA,POPA,PUSHAD,POPAD都屬於隱式的堆疊訪問指令。
c.0(第13位),這一位恆為0,為80386以後的保留的。
d.AVL(第12位),可利用位,主要是為了保持和以後的處理相容。
e.第11位到第8位是段界限的高4位。
f.P(第7位),存在位,P=1表示描述符對轉換地址有效。P=0表示描述符對轉換地址無效,如果使用該描述符將會引起異常。
g.DPL(Descriptor Privelege Level)描述符特權級,共2位,它規定了所述段的特權級別,用於特權檢查,以決定是否能對該段進行訪問。
h.DT(Descriptor Type)描述符的型別,DT=0表示儲存段描述符,DT=0表示系統段描述符和門描述符。
i.TYPE,共4位,說明儲存段的具體屬性:
TYPE0:指示描述符是否被訪問,用A標記,A=0表示描述符未被訪問,A=1表示描述符已被訪問。
TYPE1:根據TYPE3來確定。
TYPE2:根據TYPE3來確定。
TYPE3:指示描述符所描述的段是資料段還是程式碼段,用E標記。E=0表示是不可執行段,是資料段,對應的描述符也就是資料段描述符。E=1表示是可執行段,也就是程式碼段,對就的描述符也就是程式碼段描述符。
如果TYPE3=0,也就是說描述符是資料段描述符,那麼TYPE1指示該資料段是否可寫,用W標記。W=0表示對應的資料段不可寫,只讀。W=1表示對應的資料段可寫。TYPE2則指示資料段的擴充套件方向,用ED標記。ED=0表示向高階擴充套件,ED=1表示向低端擴充套件。
如果TYPE3=1,也就是說描述符是程式碼段描述符,那麼TYPE1指示該程式碼段是否可讀,用符號R標記。R=0表示對應的程式碼段不可讀,只能執行,R=1表示對應的程式碼可讀可執行。TYPE2則指示所描述的程式碼段是否是一致程式碼段,用C表示。C=0表示程式碼段不是一致程式碼段,C=1表示是一致程式碼段。
TYPE3-TYPE0這四位可以列成一個表:
___________________________________________________________________________________
|0000 |只讀 |
|_____|____________________________________________________________________________|
|0001 |只讀,已訪問 |
|_____|____________________________________________________________________________|
|0010 |可讀,可寫 |
|_____|____________________________________________________________________________|
|0011 |讀寫,已訪問 |
|_____|____________________________________________________________________________|
|0100 |只讀,向低擴充套件 |
|_____|____________________________________________________________________________|
|0101 |只讀,向低擴充套件 |
|_____|____________________________________________________________________________|
|0110 |讀/寫,向低擴充套件 |
|_____|____________________________________________________________________________|
|0111 |讀/寫,向低擴充套件,已訪問 |
|_____|____________________________________________________________________________|
|1000 |只執行 |
|_____|____________________________________________________________________________|
|1001 |只執行,已訪問 |
|_____|____________________________________________________________________________|
|1010 |可執行,可讀 |
|_____|____________________________________________________________________________|
|1011 |可執行,可讀,已訪問 |
|_____|____________________________________________________________________________|
|1100 |只執行,一致程式碼段 |
|_____|____________________________________________________________________________|
|1101 |只執行,一致程式碼段,已訪問 |
|_____|____________________________________________________________________________|
|1110 |可執行,可讀,一致程式碼段 |
|_____|____________________________________________________________________________|
|1111 |可執行,可讀,一致程式碼段,已訪問 |
|_____|____________________________________________________________________________|
儲存段描述符的結構可以這樣定義:
DESCRIPTOR STRUCT
Segment_LimitL16 DW 0;段界限的低16位
Segment_BaseL16 DW 0;段基址的低16位
Segment_BaseM8 0;段基址的中間8位
Segment_BaseH8 DB 0;段基址的高8位
Segment_Attributes DW 0;段屬性
DESCRIPTOR ENDS
一個任務有多個段,每個段都有一個描述符。因此在80386下,為了方便管理這些段描述符,將描述符組成一個線性表,稱之為描述符表。在80386下有三種描述符表:GDT(Global Descriptor Table),LDT(Local Descriptor Table),IDT(Interrupt Descriptor Table)。在整個系統中全域性描述符表GDT和中斷描述符表只有一張,區域性描述符表可以由若干張。每個描述符表都形成一個特殊的16位資料段,這樣的特殊資料段最多可以有8192個描述符,具體使用哪一個段描述符,由段的選擇子來確定。每個任務都有自已的區域性描述符表LDT,它包含自已的程式碼段,資料段,堆疊段,也包含該任務使用的一些門描述符。隨著任務的切換,LDT也跟著切換。GDT包含每一個任務都可能或可以訪問的段的描述符,通常包含描述所用的程式碼段,資料段以及堆疊段的描述符,也包含描述任務LDT的描述符。在任務切換時,並不切換GDT。一個任務的整個虛擬地址空間可以分為相等的兩半,一半空間的描述符在全域性描述符表GDT中,一半空的描述符在區域性描述符表LDT中。由於全域性描述符表和區域性描述符表都可以包含最多為8192個描述符,而每個描述符所描述的段的最大長度為4G,因此最大的虛擬地址空間為:8192*4G*2=64TB。
段選擇子用來確定使用描述符表中的哪一個描述符。實式模式下邏輯地址由段地址*16再加上段內偏移地址;保護模式下虛擬地址空間由段選擇子和段內偏移來確定,和實式模式比較,段選擇子代替了段值,實際上透過段選擇子就可以確定了段基址。選擇子的高13位是描述符表中的號,用來確定描述符,因為是13位,所以說最多可以有2的13次方8192個描述符,索引號:0-8191。標記TI指示是從全域性描述符中讀取描述符還是從區域性描述符表中讀取描述符。TI=0指示是從全域性描述符表中讀取描述符,TI=1指示從區域性描述符表讀取描述符。RPL表示請求特權級,用於特權檢查。假設段選擇子為88H,則表示請求的特權級別是0,從全域性描述表中讀取描述表,描述符的索引號為11H。有一個特殊的選擇子稱為空選擇子,它的Index=0(即高13位為0),TI=0,RPL則可以為任意值。當用空選擇子對儲存器進行訪問,會出現異常。空選擇子對應於全域性描述表中的第0個描述符,因此全域性描述符表中的第0個描述符總是不會被訪問。如果TI=1,那麼就不是空選擇子,它指定的是當前區域性描述符表中的第0個描述符。為了更快地從段選擇子中獲得段的基本資訊(段基址,段界限,段屬性),從80386開始為每個段暫存器在上配備了段描述符高速緩衝儲存器,對我們寫程式的人來講,它是不可的。有了這種高速緩衝暫存器後,每當將選擇子裝入段暫存器後,處理器將自動裝入描述符表中相應的描述符,並將描述表的資訊裝入到高速緩衝暫存器,這樣可以加快訪問速度,以下是段選擇子的結構示意圖:
15________________________________________________________________3__2__1_____0
| |TI | RPL |
|________________________________________________________________|___|________|
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1004601/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JavaSE基礎程式設計十題Java程式設計
- 計算機基礎與程式設計第十週總結計算機程式設計
- python程式設計基礎Python程式設計
- shell程式設計基礎程式設計
- Socket程式設計基礎程式設計
- Go程式設計基礎Go程式設計
- Shell程式設計-基礎程式設計
- 《計算機基礎與程式設計》第十週學習總結計算機程式設計
- 《轉生成為前端程式設計師01-基礎篇》前端程式設計師
- Java語言程式設計(基礎篇)第十版 5.14Java程式設計
- Java 基礎02Java程式設計基礎Java程式設計
- Windows程式設計系列:圖形程式設計基礎Windows程式設計
- 【socket程式設計基礎模板】程式設計
- QML程式設計 基礎 小白程式設計
- 【程式設計基礎】輸出程式設計
- python 程式設計基礎案例Python程式設計
- 網路程式設計基礎程式設計
- 程式設計基礎知識程式設計
- shell程式設計基礎二程式設計
- 零基礎轉行IT程式設計師的成功祕訣程式設計師
- Linux系統程式設計基礎Linux程式設計
- shader程式設計基礎:畫線程式設計
- Java併發程式設計基礎Java程式設計
- Golang併發程式設計基礎Golang程式設計
- JAVA網路程式設計基礎Java程式設計
- 併發程式設計基礎(下)程式設計
- 併發程式設計基礎(上)程式設計
- Java 基礎程式設計筆記Java程式設計筆記
- Java程式設計基礎33——JDBCJava程式設計JDBC
- React基礎:宣告式程式設計React程式設計
- 0基礎半路轉行學程式設計還來得及嗎?程式設計
- java程式設計師程式設計筆試基礎學習Java程式設計師筆試
- 《java程式設計基礎》java的基礎知識(三)Java程式設計
- 1.2程式設計基礎之變數定義、賦值及轉換程式設計變數賦值
- 0基礎小白轉行程式設計師,企業願意要嗎?行程程式設計師
- Java入門之基礎程式設計Java程式設計
- 併發程式設計——基礎概念(一)程式設計
- 併發程式設計——基礎概念(二)程式設計
- 驅動篇——核心程式設計基礎程式設計