當前位置:首頁 > 公眾號精選 > IOT物聯(lián)網小鎮(zhèn)
[導讀]實模式:bootloader為程序計算段的基地址保護模式:bootloader為自己創(chuàng)建段描述符確定GDT的地址創(chuàng)建代碼段的描述符創(chuàng)建數(shù)據段的描述符創(chuàng)建棧段的描述符段描述符是如何確保段的安全的?段寄存器高速緩存對段寄存器本身的保護對段界限的檢查在上一篇文章中,我們已經順利的從實模...


  • 實模式:bootloader 為程序計算段的基地址


  • 保護模式:bootloader 為自己創(chuàng)建段描述符


    • 確定 GDT 的地址


    • 創(chuàng)建代碼段的描述符


    • 創(chuàng)建數(shù)據段的描述符


    • 創(chuàng)建棧段的描述符


  • 段描述符是如何確保段的安全的?


    • 段寄存器高速緩存


    • 對段寄存器本身的保護


    • 對段界限的檢查


在上一篇文章中,我們已經順利的從實模式,過渡到了保護模式。


保護模式與實模式最本質的區(qū)別就是:保護模式使用了全局描述符表,用來保存每一個程序(bootloader,操作系統(tǒng),應用程序)使用到的每個段信息:開始地址,長度,以及其他一些保護參數(shù)。


這篇文章,我們來看一下bootloader是如何來進行自我進化到保護模式的,然后深入看一下保護模式是如何對內存進行安全保護的。


作為背景知識,我們先來看一下x86中的地址變換過程:


Linux從頭學09:x86 處理器如何進行-層層的內存保護?x86 處理器中的分頁機制是可以被關閉的,此時線性地址就等于物理地址,這也是我們一直討論的情況。


下一篇文章,我們就把 x86 中的分頁機制打開,并與 Linux 中的分段和分頁機制進行對比。


實模式:bootloader 為程序計算段的基地址

在之前的文章:Linux從頭學06:16張結構圖,徹底理解【代碼重定位】的底層原理中,我們討論了bootloader是如何把應用程序讀取到內存中,最后跳入到程序的入口地址的。


這里所說的程序,可以是操作系統(tǒng),也可以是應用程序。


下面這張圖,是程序被加載到內存中之后,header中的信息:


Linux從頭學09:x86 處理器如何進行-層層的內存保護?因為程序是被bootloader動態(tài)讀取到內存中的,它是不知道自己被放在內存中的什么位置,因此它也不知道自己代碼段、數(shù)據段、棧的開始地址。


但是,程序要想能夠正常執(zhí)行,就必須要知道這些信息,那怎么辦?


只有bootloader才能解決問題,因為是它來把程序從硬盤加載到內存中的。


因此,bootloader在跳入程序的入口地址之前,必須把其中的代碼段、數(shù)據段、棧段的基地址計算出來,然后寫入到程序的header中,如下圖所示:


Linux從頭學09:x86 處理器如何進行-層層的內存保護?這樣的話,程序開始執(zhí)行時,就可以從自己的header中獲取到這3個段基地址,并且賦值給相應的寄存器,從而順利的執(zhí)行程序。


也就是說:程序的header空間,充當了bootloader與它進行信息交互的媒介,用來傳遞3個段寄存器的基地址。


以上的這個過程,一直工作在實模式,因此就沒有段描述符什么事情。


在以后文章中,我們還會看到在保護模式下,bootloader仍然會利用OS的header空間,來傳遞段的索引號。然后OS利用這個段索引號,去查找GDT表,從而找到每一個段的基地址以及其他一些保護信息。


保護模式:bootloader 為自己創(chuàng)建段描述符

bootloader從BIOS接管系統(tǒng)之后,剛開始是運行在實模式下的。


當它完成一些準備工作之后,就可以進入保護模式了,也就是把CR0寄存器的bit0設置為1。


這個準備工作中,最重要的就是:建立 GDT 這個表,并且把 GDT 的開始地址,存儲到寄存器 GDTR 中


下面這張圖,是bootloader被加載到內存中的布局圖:


Linux從頭學09:x86 處理器如何進行-層層的內存保護?bootloader被加載到0x0000_7C00地址處。


它最少需要創(chuàng)建3個段描述符:代碼段、數(shù)據段和棧段。


確定 GDT 的地址

在創(chuàng)建段描述符之前,需要先確定: 把 GDT 表放在內存中的什么位置?


暫且就把它放在0x0001_0000這個地址吧,距離零地址64K的位置。


按照處理器的要求,在第1個表項(稱之為 item 或者 entry,每本書上都不一樣)必須為空描述符(index = 0)。


Linux從頭學09:x86 處理器如何進行-層層的內存保護?

創(chuàng)建代碼段描述符

bootloader的代碼放在0x0000_7C00開始的地址,長度是512B。


根據這些信息,就可以構造出代碼段的描述符了:


Linux從頭學09:x86 處理器如何進行-層層的內存保護?

創(chuàng)建數(shù)據段描述符

bootloader待會需要把操作系統(tǒng)或其他應用程序,從硬盤讀取到內存中,例如:讀取到0x0002_0000的位置。


那么bootloader就必須能夠訪問到這個位置,并且是以數(shù)據段的讀寫方式。


為了利用全部的4G內存空間,bootloader可以把這4G空間,作為一個數(shù)據段來定義它的描述符,如下:


Linux從頭學09:x86 處理器如何進行-層層的內存保護?

創(chuàng)建棧段描述符

理論上,bootloader可以使用內存中的任意一塊空閑空間,來作為自己的棧。


因為棧在push操作的時候,是向低地址方向增長的。


因此很多書籍都會把棧頂基地址設置為bootloader的開始地址,也就是0x0000_7C00地址處,并且把棧的空間大小限制在4K的范圍。


Linux從頭學09:x86 處理器如何進行-層層的內存保護?根據以上這些信息,就可以創(chuàng)建出棧的段描述符,如下:


Linux從頭學09:x86 處理器如何進行-層層的內存保護?當以上這幾個段的描述符都創(chuàng)建好之后,就可以把GDT的地址(0x0001_0000),設置到 GDTR 寄存器中了。


最后,再把CR0寄存器的bit0設置為1,就正式的進入保護模式來執(zhí)行bootloader中后面的代碼了。


段描述符是如何確保段的安全訪問的?

段寄存器高速緩存

進入保護模式之后,雖然對段寄存器中內容的解釋改變了,但是執(zhí)行每一條指令,還是需要使用到這些段寄存器的: cs, ds, ss等等。


想象一下:每執(zhí)行一條指令,都會從邏輯地址中,獲取到段索引號,然后去查找GDT表,從而定位到段的基地址。


大家都知道程序有個“局部性”原理,也就是連續(xù)執(zhí)行的代碼,都是集中在一段連續(xù)的程序空間中的。


這個連續(xù)的程序空間,它們都是在同一個代碼段中,因此段的基地址都是相同的,那么它們都屬于GDT中同一個代碼段描述符所代表的段空間。


如果每一條指令都去查表,就會影響到程序的執(zhí)行效率。


所以,處理器內部就為每一個段寄存器,安排了一個高速緩存。


拿代碼段寄存器cs來說:當執(zhí)行一條指令的時候,如果它與上一條指令中的段索引號不同,才會根據新的段索引號到GDT中查找相應的段描述符表項。


查找到之后,就把這個表項的內容復制到 cs 寄存器的高速緩存中


當繼續(xù)執(zhí)行后面的指令時,如果邏輯地址中的段索引號沒有變化,處理器就直接從高速緩存中讀取段描述,從而避免了查表操作,提升了系統(tǒng)效率。


對段寄存器本身的保護

當邏輯地址中段寄存器的索引號改變時,就會根據新的索引號,到GDT中去查表。


當然了,這個索引號不能超過 GDT 的界限。


當定位到某一個描述符表項之后,就開始進行一系列檢查。


再來看一下每一個段描述符中8個字節(jié)的內容:


Linux從頭學09:x86 處理器如何進行-層層的內存保護?bit8 ~ bit11定義了當前這個段的類型。


假如: 我們在切換代碼段空間的時候,不小心犯錯,定位到了GDT中的一個數(shù)據段描述符表項,那么處理器就能夠及時發(fā)現(xiàn):


“當前這個段描述符的類型是數(shù)據段,你卻把它當做代碼段來使用,禁止,殺無赦!”


因此,處理器就會拒絕把這個段描述符復制到代碼段的高速緩存中,從而對代碼段寄存器進行了保護。


對段界限的檢查

在通過了第一層的段類型保護之后,還會繼續(xù)對段的界限進行檢查,這就要使用到邏輯地址中的偏移地址(EIP)了。


如果偏移地址超過了描述符中規(guī)定的界限,那么就說明發(fā)生錯誤了。


例如:在bootloader的代碼段描述符中,最大的界限是512B,如果把EIP設置為0x0000_1000,那就肯定錯誤了。


因為這個地址壓根就不屬于代碼段的空間范圍。


對于數(shù)據段來說比較有意思,因為我們把數(shù)據段描述符的基地址設置為0x0000_0000,段的界限是整個4G的空間,所以它可以對整個內存進行操作。


多想一步:


代碼段也是屬于這4G空間,因此可以通過數(shù)據段,來改寫代碼段空間中的指令內容。


也就是說:如果你想修改代碼段的指令,直接通過代碼段來操作是不可以的。


因為代碼段描述符中規(guī)定了:代碼段的內容只能被讀取、執(zhí)行,但是不能被寫入


此時,就可以另辟蹊徑:代碼段也放在4G的空間,那么就可以通過數(shù)據段的可寫特性,來改寫代碼段中的指令。


想一想gdb的調試過程,是不是就利用了這個道理?


在文末的
本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或將催生出更大的獨角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據媒體報道,騰訊和網易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據產業(yè)博覽會開幕式在貴陽舉行,華為董事、質量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據產業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經營業(yè)績穩(wěn)中有升 落實提質增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數(shù)字經濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯(lián)合牽頭組建的NVI技術創(chuàng)新聯(lián)盟在BIRTV2024超高清全產業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術創(chuàng)新聯(lián)...

關鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉