存儲器的保護(二)——《x86彙編語言:從實模式到保護模式》讀書筆記19

接着上一篇博文說。oop

 

5.代碼段執行時的保護

每一個代碼段都有本身的段界限。同棧段一個道理,有效界限和G位相關。spa

G=0:有效界限 = 描述符中的段界限.net

G=1:有效界限 = 描述符中的段界限值 * 0x1000 + 0xFFFcode

當處理器取指令的時候,偏移地址由EIP提供,EIP的範圍應該在 [0,有效界限] 之間(爲了說明問題,我就用數學上的閉區間表示了)。不然會引起異常。blog

對於本代碼,代碼段描述符中的界限值是0x1FF,G=0,那麼有效界限=0x1FF,也就是說這個值就是段內最後一個容許訪問的偏移地址。排序

再舉一個例子,源文件中ip

71         mov dword [es:0x0b8000],0x072e0750 ;字符'P'、'.'及其顯示屬性
72         mov dword [es:0x0b8004],0x072e074d ;字符'M'、'.'及其顯示屬性
73         mov dword [es:0x0b8008],0x07200720 ;兩個空白字符及其顯示屬性
74         mov dword [es:0x0b800c],0x076b076f ;字符'o'、'k'及其顯示屬性

這四行對應的.list文件以下v8

eip的有效值

能夠看到,第71行,mov dword [es:0x0b8000],0x072e0750 這條指令,其偏移地址爲 0xB8~0xC2; 那麼,要想這條指令順利執行,定義代碼段時,有效界限就要大於等於0xC2.當等於0xC2的時候,這條指令能夠順利執行,可是下一條指令的執行會引起異常。字符串

也就是說,若是某條指令的偏移地址爲M~N,那麼這條指令被順利執行的必要條件是集合[M,N]屬於集合[0,代碼段的有效界限]。(請原諒我借用集合來描述,但是我再也想不出什麼簡明的表達了眨眼get

6.數據訪問時的保護

這裏所說的數據段,特指向上擴展的數據段,有別於棧段和向下擴展的數據段。

訪問數據段時,是否越界與操做數的長度有關。

對於向上擴展的數據段,有效界限的計算方法依然是:

G=0:有效界限 = 描述符中的段界限

G=1:有效界限 = 描述符中的段界限值 * 0x1000 + 0xFFF

舉例來講,第74行

74         mov dword [es:0x0b800c],0x076b076f ;字符'o'、'k'及其顯示屬性

這條指令的目的是把0x076b076f寫入偏移地址爲0x0b800c~0x0b800f的4個存儲單元。若是要成功寫入,那麼0x0b800c~0x0b800f必須在數據段的有效界限內。也就是要求:

[0xb800c, 0xb800f] 屬於 [0, 上擴數據段的有效界限]

本代碼中,數據段的有效界限值是0xFFFF_FFFF,也就是說能夠訪問4GB空間內的任何一個單元。

7.使用別名段訪問代碼段對字符排序

104;-------------------------------------------------------------------------------
105     string           db 's0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw.'
106;-------------------------------------------------------------------------------

第105行,定義了一串字符。做者要對這串字符進行升序排序,其實「項莊舞劍;意在沛公」——排序是假,使用別名段是真。由於代碼段是不容許寫入的,因此要修改代碼段,就須要爲之建立一個別名描述符。第3三、34行,程序爲代碼段建立了一個可讀寫的數據段描述符。也就是說,咱們能夠把代碼段當成數據段來用。

33         mov dword [ebx+0x18],0x7c0001ff    ;基地址爲0x00007c00,512字節
34         mov dword [ebx+0x1c],0x00409200    ;粒度爲1個字節,數據段描述符,可讀寫

第5九、60行,把這個別名段的選擇子加載到DS

59         mov eax,0x0018                      
60         mov ds,eax

這裏咱們用冒泡排序法,雖然這個方法效率低,可是很適合初學者入門。關於冒泡排序的知識,請參考其餘資料。

爲了說明問題,我繪製了一張圖,假如一共有5個數,要把它們從左至右按照升序排列,示意圖以下。

冒泡排序示意圖

每比較一次,就把較大的數放在右邊。那麼第一次外循環後,最大的數就冒到了最右邊;第二次外循環後,第二大的數冒到了從右邊數第二個位置;……

若是N個數參加排序,那麼外循環須要(N-1)次。第1次須要(N-1)次比較,第2次須要(N-2)次比較,……第(N-1)次須要一次比較。

說了這麼多,我就是想說清楚代碼。

76         ;開始冒泡排序 
77         mov ecx,pgdt-string-1              ;遍歷次數=串長度-1 
78  @@1:
79         push ecx                           ;32位模式下的loop使用ecx 
80         xor bx,bx                          ;32位模式下,偏移量能夠是16位,也能夠 
81  @@2:                                      ;是後面的32位 
82         mov ax,[string+bx] 
83         cmp ah,al                          ;ah中存放的是源字的高字節 
84         jge @@3 
85         xchg al,ah 
86         mov [string+bx],ax 
87  @@3:
88         inc bx 
89         loop @@2 
90         pop ecx 
91         loop @@1

第77行,剛開始,ECX保存着外循環的次數(字符數-1)。

79行把ECX壓棧是由於內循環也要用這個值(這個值就是本循環比較的次數),並且在內循環中,這個次數會變化。爲了避免破壞外循環的次數,因此要壓棧保存。

第81~89行,是內循環,完成字符對比的工做。首先一次性讀入2個字符到AX中,AL中存放的是前一個(低地址處的)字符,AH中存放的是後一個(高地址處的)字符,若是前者大,則交換AL和AH的內容,而後把AX重寫入原來的存儲單元。接下來,BX加1,以指向下一個字符。

93         mov ecx,pgdt-string
94         xor ebx,ebx                        ;偏移地址是32位的狀況 
95  @@4:                                      ;32位的偏移具備更大的靈活性
96         mov ah,0x07
97         mov al,[string+ebx]
98         mov [es:0xb80a0+ebx*2],ax          ;演示0~4GB尋址。
99         inc ebx
100        loop @@4
101      
102        hlt

排序完畢後,第93~100,用於顯示最終的排序結果。

第98行表示從顯存的第2行第1列(0xb8000 + 0xa0(=160D) = 0xb80a0)開始顯示字符串。當EBX=0、一、2……時,對應的地址是0xb80a0、0xb80a二、0xb80a4……(使用比例因子就是這麼方便大笑),注意,「0xb80a0 + ebx * 2」,這個表達式的值是在指令執行時,由處理器計算出來的。

 

(12章完)

相關文章
相關標籤/搜索