进入保护模式(三)——《x86汇编语言:从实模式到保护模式》读书笔记17
(十)保護模式下的棧
76 ;以下用簡單的示例來幫助闡述32位保護模式下的堆棧操作 77 mov cx,00000000000_11_000B ;加載堆棧段選擇子 78 mov ss,cx 79 mov esp,0x7c00第77~79行用來初始保護模式下的棧。棧段描述符是GDT中第3個(從0開始數)描述符,這個描述符的線性基地址是0x0000_0000,段界限是0x0000_7a00,粒度是字節,B=1,屬于可讀可寫、向下擴展的數據段。
我在博文數據段描述符和代碼段描述符(一)——《x86匯編語言:從實模式到保護模式》讀書筆記10中已經說過,
對于向上擴展的段(E=0),邏輯地址中的偏移值范圍可以從0到(界限值*粒度);
對于向下擴展的段(E=1),邏輯地址中的偏移范圍可以從(界限值*粒度)到0xFFFF(當B=0時)或者0xFFFF_FFFF(當B=1時)。
所以,對于描述符中的棧段,偏移范圍是0x0000_7a00~0xffff_ffff. 仔細琢磨一下,這和我們的想法不是那么一致,因為代碼79行,令ESP的初值是0x7c00,也就是說,我們本打算定義一個偏移范圍是0x0000_7a00~0x0000_7c00的棧段。
因為線性基地址是0x0000_0000,也就是說描述符定義的棧段,實際可以訪問的物理空間是0x0000_7a00~0xffff_ffff,但是我們卻希望這個棧可以訪問的物理空間是0x0000_7a00~0x0000_7c00。示意圖(根據原書的圖11-14改編而成)如下圖所示。雖然這個棧不完美,但是不用擔心,我們會在后面的學習中用更好的方法來創建棧。
(十一)驗證32位下的棧操作
隱式的棧操作(如push、pop、call、ret、iret等)涉及兩個段,一個是指令所在的代碼段,一個是棧段。之前的博文我們說過,對于可執行代碼段,
D=1:默認是32位地址和32位或8位的操作數
D=0:默認是16位地址和16位或8位的操作數
注意:指令前綴0x66可以用來選擇非默認值的操作數大小;前綴0x67可以用來選擇非默認值的地址大小
對于棧段,
B=1:棧指針使用ESP
B=0:棧指針使用SP
就本文的實驗代碼,其代碼段描述符的D位是1,其棧段描述符的B位也是1. 所以,當進行隱式的棧操作時,默認是32位操作數(比如壓棧的時候,壓入的是雙字),且用ESP進行操作。
所以,下面的代碼就用來驗證這個事實。
81 mov ebp,esp ;保存堆棧指針 82 push byte '.' ;壓入立即數(字節) 83 84 sub ebp,4 85 cmp ebp,esp ;判斷壓入立即數時,ESP是否減4 86 jnz ghalt 87 pop eax 88 mov [0x1e],al ;顯示句點 89 90 ghalt: 91 hlt ;已經禁止中斷,將不會被喚醒在閱讀這段代碼的時候,我多少有點懷疑:書上說的到底是不是真的?我想通過實踐來檢驗:探究一下PUSH指令在16位模式和32位模式下的執行規律。經過一番折騰,終于有了結果。請參考我的博文? 16位模式/32位模式下PUSH指令探究——《x86匯編語言:從實模式到保護模式》讀書筆記16
第81行,復制esp的值給ebp;第82行,壓入一個字節(byte關鍵字不能省略);理論上,把ebp的值減去4后(第84行),應該和此時esp的值相等。為了證明這一點,第85行比較ebp和esp的值,如果不相等,就跳轉到91行執行停機指令;如果相等,就把字符“.”顯示在之前的字符串后面。
OK,第11章的內容已經學習完了。最后我們看一下代碼的運行結果吧,結果就是在屏幕的左上角顯示“Protect mode OK.”
(完)
總結
以上是生活随笔為你收集整理的进入保护模式(三)——《x86汇编语言:从实模式到保护模式》读书笔记17的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二叉树的字符图形显示程序_每个程序员都必
- 下一篇: gsensor 车辆碰撞算法_AEB安全