1. what is 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可以被放在記憶體的任何位置,那麼當程式設計師通過段暫存器來引用乙個段描述符時,cpu必須知道gdt的入口,也就是基位址放在**,所以intel的設計者門提供了乙個暫存器gdtr用來存放gdt的入口位址,程式設計師將gdt設定在記憶體中某個位置之後,可以通過lgdt指令將gdt的入口位址裝入此積存器,從此以後,cpu就根據此積存器中的內容作為gdt的入口來訪問gdt了。
gdt是protected mode所必須的資料結構,也是唯一的——不應該,也不可能有多個。另外,正象它的名字(global descriptor table)所揭示的,它是全域性可見的,對任何乙個任務而言都是這樣。
除了gdt之外,ia-32還允許程式設計師構建與gdt類似的資料結構,它們被稱作ldt(local descriptor table),但與gdt不同的是,ldt在系統中可以存在多個,並且從ldt的名字可以得知,ldt不是全域性可見的,它們只對引用它們的任務可見,每個任務最多可以擁有乙個ldt。另外,每乙個ldt自身作為乙個段存在,它們的段描述符被放在gdt中。
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中的索引值——這一點和剛才所討論的通過段積存器引用段的模式是一樣的。
寫blog的緣由
首先說明一下,寫這些東西主要有兩個原因 乙個是由於寫作能力太差,平時文件結構設計時,總是黔驢技窮 另乙個是為了記錄一些日常故事,時間珍貴,當作乙個回味的回憶。以前上學的時候,每次語文考試都爛的要命,基本沒有及格的時候,120分的試卷基本能得50分左右。說來實在有點不好意思,到現在都沒有弄明白發音是幾...
部落格開通的緣由
今天,把部落格開通了,不為神馬,也不假意說為了大家方便 但是真的有這方面的原因,嘿嘿 我開通部落格就是因為我在工作中,有時候只是乙個很小的問題,我想不出來,輸入我想法的關鍵字,卻要很久才能找到我想要的答案。我的一些部落格,都是我遇到的,或者在書上看到的,如果我看到很好的部落格,有關的我一定把鏈結記得...
閏年演算法的緣由
根據這個寫出的程式的核心演算法就是 if n 4 0 n 100 0 n 400 0 但是到底是為什麼要這麼算呢,本來按照我自己的理解,好像只要是4的倍數就應該是閏年,所以對這個演算法一直沒有深入的理解,一直不知道它的原理,所以就自己搜了一下資料,了解了一下,終於弄明白了 關於公曆閏年是這樣規定的 ...