1. 程式人生 > >x86 組合語言:從真實模式到保護模式

x86 組合語言:從真實模式到保護模式

1.邏輯地址的作用:程式在記憶體中載入的位置變了,仍然可以執行。
為了在硬體一級提供對“段地址:偏移地址”記憶體訪問模式的支援,處理器至少要提供兩個段暫存器,分別是程式碼段(Code Segment,CS)暫存器和資料段(Data Segment,DS)暫存器。對 CS 內容的改變將導致處理器從新的程式碼段開始執行。同樣,在開始訪問記憶體中的資料之前,也必須首先設定好 DS 暫存器,使之指向資料段。除此之外,最重要的是,當處理器訪問記憶體時,它把指令中指定的記憶體地址看成是段內的偏移地址,而不是實體地址。這樣,一旦處理器遇到一條訪問記憶體的指令,它將把 DS 中的資料段起始地址和指令中提供的段內偏移相加,來得到訪問記憶體所需要的實體地址。
2.指令預取佇列


這裡寫圖片描述
3.邏輯分段按16位元組對齊的原因:如果你從實體記憶體地址 82255H 處載入程式,由於它根本無法表示
成一個偏移地址為 0000H 的邏輯地址,所以不符合要求,段不能從這裡開始劃分。這裡面的區
別在於,82260H 可以被十進位制數 16(或者十六進位制數 10H)整除,而 82255H 不能。通過這
個例子可以看出,8086 處理器的邏輯分段,起始地址都是 16 的倍數,這稱為是按 16 位元組對齊
的。
段的劃分是自由的,它可以起始於任何 16 位元組對齊的位置,也可以是任意長度,只要不
超過 64KB。比如,段地址可以是 82260H,段的長度可以是 64KB。在這種情況下,該段所對
應的邏輯地址範圍是 8226H:0000H~8226H:FFFFH,其所對應的實體地址範圍是 82260~
9225FH。
同時,正是由於段的劃分非常自由,使得 8086 的記憶體訪問也非常隨意。同一個實體地址,
或者同一片記憶體區域,根據需要,可以隨意指定一個段來訪問它,前提是那個實體地址位於該
段的 64KB 範圍內。也就是說,同一個實體地址,實際上對應著多個邏輯地址。
如果你從實體記憶體地址 82255H 處載入程式,由於它根本無法表示
成一個偏移地址為 0000H 的邏輯地址,所以不符合要求,段不能從這裡開始劃分。這裡面的區
別在於,82260H 可以被十進位制數 16(或者十六進位制數 10H)整除,而 82255H 不能。通過這
個例子可以看出,8086 處理器的邏輯分段,起始地址都是 16 的倍數,這稱為是按 16 位元組對齊
的。
段的劃分是自由的,它可以起始於任何 16 位元組對齊的位置,也可以是任意長度,只要不
超過 64KB。比如,段地址可以是 82260H,段的長度可以是 64KB。在這種情況下,該段所對
應的邏輯地址範圍是 8226H:0000H~8226H:FFFFH,其所對應的實體地址範圍是 82260~
9225FH。
同時,正是由於段的劃分非常自由,使得 8086 的記憶體訪問也非常隨意。同一個實體地址,
或者同一片記憶體區域,根據需要,可以隨意指定一個段來訪問它,前提是那個實體地址位於該
段的 64KB 範圍內。也就是說,同一個實體地址,實際上對應著多個邏輯地址。
4.這裡寫圖片描述

5.硬碟
這裡寫圖片描述
扇區頭包含了每個扇區自己的資訊,主要有本扇區的磁軌號、磁頭號和扇區號,用來
供硬碟定位機構使用。現代的硬碟還會在扇區頭部包括一個指示扇區是否健康的標誌,以及用
來替換該扇區的扇區地址。用於替換扇區的,是一些保留和隱藏的磁軌。
6.在螢幕上顯示文字
顯示卡控制顯示器的最小單位是畫素,一個畫素對應著螢幕上的一個點。螢幕上通常有數十萬乃至更多的畫素,通過控制每個畫素的明暗和顏色,我們就能讓這大量的畫素形成文字和美麗的影象。
這裡寫圖片描述
現在最流行的,是用 24 個位元,即 3 個位元組,來對應一個畫素。因為 2^24=16777216,所以在這種模式下,同屏可以顯示 16777216 種顏色,這稱為真彩色。
這裡寫圖片描述

在計算機中,每個用來顯示在螢幕上的字元,都有一個二進位制程式碼。這些程式碼和普通的二進位制數字沒有什麼不同,唯一的區別在於,傳送這些數字的硬體和接收這些數字的硬體把它們解釋為字元,而不是指令或者用於計算的數字。
這裡寫圖片描述

//將L送到螢幕上
mov ax,0xb800
mov es,ax
mov byte [es:0x00],'L' //等效於:mov byte [es:0x00],0x4c,
在源程式的編譯階段,組合語言編譯器會將它轉換成 ASCII 碼的形式。
mov byte [es:0x01],0x07 //黑底白字,無閃爍,無加亮

7.段之間的批量資料傳送
movsb 和 movsw 指令執行時,原始資料串的段地址由 DS 指定,偏移地址由 SI 指定,簡寫為DS:SI;要傳送到的目的地址由 ES:DI 指定;傳送的位元組數(movsb)或者字數(movsw)由 CX 指定。除此之外,還要指定是正向傳送還是反向傳送,正向傳送是指傳送操作的方向是從記憶體區域的低地址端到高地址端;反向傳送則正好相反。正向傳送時,每傳送一個位元組(movsb)或者一個字(movsw),SI 和 DI 加 1 或者加 2;反向傳送時,每傳送一個位元組(movsb)或者一個(movsw)時,SI 和 DI 減去 1 或者減去 2。不管是正向傳送還是反向傳送,也不管每次傳送的是位元組還是字,每傳送一次,CX 的內容自動減一。
8.計算1+2+……+100,並列印

jmp near start
message db '1+2+3+...+100='

start:
         mov ax,0x7c0           ;設定資料段的段基地址
         mov ds,ax
         mov ax,0xb800          ;設定附加段基址到顯示緩衝區
         mov es,ax

         ;以下顯示字串
         mov si,message         
         mov di,0
         mov cx,start-message
     @g:
         mov al,[si]
         mov [es:di],al
         inc di
         mov byte [es:di],0x07
         inc di
         inc si
         loop @g

         ;以下計算1100的和
         xor ax,ax
         mov cx,1
     @f:
         add ax,cx
         inc cx
         cmp cx,100
         jle @f

         ;以下計算累加和的每個數位
         xor cx,cx              ;設定堆疊段的段基地址
         mov ss,cx
         mov sp,cx
         mov bx,10
         xor cx,cx
     @d:
         inc cx
         xor dx,dx
         div bx
         or dl,0x30 //數字的二進位制碼,為num+00110000;
         push dx
         cmp ax,0
         jne @d
         ;以下顯示各個數位
     @a:
         pop dx
         mov [es:di],dl
         inc di
         mov byte [es:di],0x07
         inc di
         loop @a
         jmp near $

times 510-($-$$) db 0
                 db 0x55,0xaa
//times 510-($-$$) db 0 表示填充 510-($-$$) 這麼多個位元組的0
這裡面的$表示當前指令的地址,$$表示程式的起始地址(也就是最開始的7c00),所以$-$$就等於本條指令之前的所有位元組數。510-($-$$)的效果就是,填充了這些0之後,從程式開始到最後一個0,一共是510個位元組。再加上最後的dw兩個位元組(0xaa55是結束標誌),整段程式的大小就是512個位元組,剛好佔滿一個扇區。

9.游標
游標(Cursor)是在螢幕上有規律地閃動的一條小橫線,通常用於指示下一個要顯示的字元位置,這對很多年齡比較大的人來說很熟悉(前提是他們以前也用過計算機)。在那個時代,還沒有基於圖形顯示技術的 Windows,所有的軟體都在文字模式下工作,而基於硬體的游標只在文字模式下才會出現。
10.中斷
中斷就是打斷處理器當前的執行流程,去執行另外一些和當前工作不相干的指令,執行完之後,還可以返回到原來的程式流程繼續執行。這就好比是你正在用手機聽歌,突然來電話了。處理器(當然,手機也是有處理器的)必須中斷歌曲的播放,來處理這件更為重要的事件。
11.實時時鐘
實時時鐘是全天候跳動的,即使是在你關閉了計算機的電源之後,原因在於它由主機板上的一個小電池提供能量。它為整臺計算機提供一個基準時間,為所有需要時間的軟體和硬體服務。

12.32位模式
在 32 位模式下,對記憶體的訪問從理論上來說不再需要分段,因為它有 32 根地址線,可以自由訪問任何一個記憶體位置。但是,IA-32 架構的處理器是基於分段模型的,因此,32 位處理器依然需要以段為單位訪問記憶體,即使它工作在 32 位模式下。
不過,它也提供了一種變通的方案,即,只分一個段,段的基地址是 0x00000000,段的長度(大小)是 4GB。在這種情況下,可以視為不分段,即平坦模型(Flat Mode)。
在 32 位模式下,處理器要求在載入程式時,先定義該程式所擁有的段,然後允許使用這些段。定義段時,除了基地址(起始地址)外,還附加了段界限、特權級別、型別等屬性。當程式訪問一個段時,處理器將用韌體實施各種檢查工作,以防止對記憶體的違規訪問。在 32 位模式下,傳統的段暫存器,如 CS、SS、DS、ES,儲存的不再是 16位段基地址,而是段的選擇子,即,用於選擇所要訪問的段,因此,嚴格地說,它的新名字叫做段選擇器。除了段選擇器之外,每個段暫存器還包括一個 64 位的不可見部分,稱為描述符快取記憶體器,裡面有段的基地址和各種訪問屬性。這部分內容程式不可訪問,由處理器自動使用。
13.http://www.cnblogs.com/tgycoder/p/6116690.html 分頁看這個
14.亂序執行

這裡寫圖片描述
15.暫存器重新命名
這裡寫圖片描述
16.分支目標預測
這裡寫圖片描述
17.補充的操作
1.shl dword [eax*2+0x08],cl 2.idiv r/m32//被除數是 64 位的,高 32 位在 EDX 暫存器;低 32 位在 EAX 暫存器。除數是 32 位的,位於 32 位的暫存器,或者存放有 32 位實際運算元的記憶體地址。指令執行後,32 位的商在 EAX 暫存器,32 位的餘數在 EDX 暫存器。
3.push byte 0x55
18.全域性描述符表
在保護模式下,對記憶體的訪問仍然使用段地址和偏移地址,但是,在每個段能夠訪問之前,必須先進行登記。
這裡寫圖片描述