《x86匯編語言:從實模式到保護模式》筆記


x86匯編語言筆記

8086通用寄存器

16位寄存器:AX、BX、CX、DX、SI、DI、BP、SP。

前4個可分為高8位和低8位來使用:AH、AL、BH、BL、CH、CL、DH、DL。

內存分段

采用分段技術解決地址重定位問題,在硬件級別用兩個段寄存器來支持,代碼段寄存器CS和數據段寄存器DS。

實模式下CPU訪問物理地址的方式:段基址:偏移地址

8086段寄存器

  • 代碼段寄存器:CS
  • 數據段寄存器:DS
  • 附加段寄存器:ES
  • 棧段寄存器:SS

如何訪問指令?

當程序開始時,CS指向代碼段的起始地址,IP指令指針指向段內偏移。即CS:IP

注意:一般沒有指定段寄存器時,默認使用DS。

如何訪問數據?

在訪問內存單元時,則采用DS:偏移地址

注意1:由於8086提供20位的物理地址,所以在計算物理地址時,要將段寄存器左移4位再加上偏移地址。由此可以得出8086最大只能訪問1MB的內存空間。

注意2:內存是以字節為單位,內存中的每一個字節都對應一個物理地址。

計算機的啟動流程

image-20220122202902641

注意:主引導扇區的最有兩個字節是0x55和0xaa。

顯存

顯存存在於顯卡之中,一般CPU是通過把顯存映射到0xB8000~0xBFFFF這部分內存空間,來直接訪問顯存,顯卡在加電自檢后會初始化為80 * 25模式,即屏幕上顯示25行,每行80個字符,每屏總共2000個字符。

顯卡通過ASCII編碼來識別CPU傳入顯存的數據。

屏幕上每個字符對應着顯存中的連續兩個字節,前一個字節為字符的ASCII代碼,后一個字節為字符的顯示屬性。

image-20220122205323064

image-20220122205336604

image-20220122204330102

注意:Intel的處理器不允許把一個立即數傳送到段寄存器,必須通過其他寄存器來中轉。

mov指令

mov 目的操作數, 源操作數

注意:mov指令不允許目的操作數和源操作數都為內存單元,並且目的操作數不能為立即數。

注意:內存的增長是從低地址到高地址的。


除法

無符號除法指令:div

  • 16位除法:

    被除數放在ax寄存器中。

    格式:

    div x ;這里的x可以代表寄存器或者[內存單元]或者立即數
    

    \[ax / x = s \cdots m \]

    參數:

    • x:除數。
    • s:表示商,放在al寄存器。
    • m:表示余數,放在ah寄存器。
  • 32位除法:

    被除數的高16位放在dx寄存器中,低16位放在ax中。

    格式:

    div x ;這里的x可以代表寄存器或者[內存單元]或者立即數
    

    \[(dx << 4 + ax) / x = s \cdots m \]

    參數:

    • x:除數。
    • s:表示商,放在ax寄存器。
    • m:表示余數,放在dx寄存器。

在段之間批量傳送數據

使用movsb和movsw指令可以在兩個段之間批量傳送數據。movsb每次傳送一個字節,movsw每次傳送一個字。

格式:

; 重復執行
rep movsb ; rep指令前綴表示cx寄存器的值不為0,則重復執行該指令。
rep movsw
; 只執行一次
movsb
movsw

參數:

  • 源地址:DS:SI,即段地址由DS寄存器提供,SI寄存器提供偏移地址。
  • 目的地址:ES:DI,即段地址由ES寄存器提供,DI寄存器提供偏移地址。
  • 數量:由CX寄存器指定。

傳送方向:

  • 正向:從低地址到高地址,每次使SI和DI加1或2。
  • 反向:從高地址到低地址,每次使SI和DI減1或2。

一個特殊的寄存器flag

通過cld指令來將flag寄存器的DF位設置為0,std指令將flag寄存器的DF位設置位1。

ZF位表示運算結果是否為0。

  • 1:運算結果為0
  • 0:運算結果不為0

DF位表示movsb/movsw指令是正向還是反向。

  • 0:正向
  • 1:反向

image-20220123204058429


關於使用寄存器提供偏移地址的問題

在8086處理器上只能使用BX、SI、DI、BP寄存器來提供偏移地址。


加一和減一、加法和減法

加一和減一對應的指令為incdec

加法和減法對應的指令為addsub


負數相關指令

  • neg 寄存器:將對應寄存器的值變為負數。
  • cbw:無操作數,將AL寄存器的數值擴展到AX寄存器。
  • cwd:無操作數,將AX寄存器的數值擴展到DX和AX寄存器中,DX存高16位,AX存低16位。

jns指令

標志寄存器的SF位:當計算結果的最高位是0時,該位為0,否則為1。

jns指令,當標志寄存器的SF位為0時,則進行跳轉。

標記寄存器的其他標志位

  • 奇偶標志位PF:當運算結果的低8位中,有偶數個1則PF為1,否則為0。
  • 進位標志位CF:當進行算術運算時,如果有向最高位進位或借位,則CF為1,否則為0。
  • 溢出標志位OF:如果發生溢出則為1,否則為0。

指令對標志寄存器的影響:

image-20220123215129845

條件跳轉指令

根據標志跳轉:

  • jz:ZF為1則轉移,jnz:ZF為0則轉移。
  • jo:OF為1則轉移,jno:OF為0則轉移。
  • jc:CF為1則轉移,jnc:CF為0則轉移。
  • jp:PF為1則轉移,jnp:PF為0則轉移。

根據比較結果跳轉:

可以通過cmp指令進行比較。

image-20220123215659834

image-20220123215722000

根據CX寄存器進行跳轉:

jcxz:如果CX寄存器為0,則進行跳轉。


棧段

由SS寄存器來確定段地址,SP寄存器確定偏移地址。

壓棧:push指令,會將SP的內容減去操作數的字長,再把操作數壓入棧中。

彈棧:pop指令,會將SP的內容加上操作數的字長,再把棧頂的數據彈出。

注意:實模式下,棧的大小為64KB。


尋址方式

  • 寄存器尋址

  • 立即尋址

  • 內存尋址

    • 直接尋址

    • 基址尋址:使用BX和BP寄存器進行尋址

      注意:BP寄存器默認使用SS段寄存器,使得棧內數據可以像數據段一樣訪問。

    • 變址尋址:使用SI和DI寄存器進行尋址

    • 基址變址寄存器:同時使用BX/BP和SI/DI寄存器進行尋址


I/O端口讀寫方式

I/O端口的范圍:0 ~ 65535(0x0 ~ 0xffff)。

  • 讀取I/O端口

    in 存放位置, 端口號
    

    存放位置:必須是AL或AX寄存器。

    端口號:立即數或DX寄存器。

  • 寫入I/O端口

    out 端口號, 寫入數據
    

    端口號:立即數或DX寄存器。

    寫入數據:必須是AL或AX寄存器。

一些磁盤相關的知識:

  • LBA28邏輯扇區編制法:即通過28個bit來表示邏輯扇區號,而不關心扇區的具體位置。(從0開始算起)

  • 端口號:

    端口號 含義
    1f2 表示要讀取的扇區數
    1f3 表示邏輯扇區號的0~7位
    1f4 表示邏輯扇區號的8~15位
    1f5 表示邏輯扇區號的16~23位
    1f6 低4位存放邏輯扇區號的24~27位,第4位表示硬盤號(0主盤,1從盤),第6位表示扇區編制方式(0:CHS、1:LBA)
    1f7 命令端口:寫入0x20表示讀硬盤請求,狀態端口:第7位表示硬盤忙碌狀態(0不忙,1忙碌),第3位表示硬盤數據是否准備好(1:ok,0:no),第0位表示讀取數據是否出錯(1出錯,0沒出錯)
    1f0 硬盤接口的數據端口(16位端口),當硬盤准備好后,可以從這個端口讀取數據

    image-20220124155733782

image-20220124160018268


過程調用

call指令:

近調用的原理是先把IP寄存器的值壓入棧中,再修改IP寄存器,而遠調用則是分別把CS和IP寄存器的值壓入棧,再修改CS和IP寄存器的值。

  • 直接近調用

    call 立即數
    
  • 間接近調用

    call 寄存器/[內存地址]
    
  • 直接遠調用

    call 段地址:偏移地址
    
  • 間接遠調用

    call far [內存地址]
    

    這種方式會從對應的內存地址中獲取兩個字的數據,前一個字作為段地址,后一個字作為偏移地址。

返回指令:

ret的原理是彈出棧中的值到IP寄存器,retf的原理是先彈出到IP寄存器,再彈到CS寄存器。

  • ret:相對近返回
  • retf:相對遠返回

abc、shr、ror指令

  • abc:同add指令差不多,但是會加上CF位的值(CF是表示是否進位)。
  • shr:邏輯右移,類似C語言中的>>
  • shl:邏輯左移,類似C語言中的<<
  • ror:循環右移,將移出的bit放到左邊空缺的位置,同時送入CF標志位。
  • rol:循環左移,將移出的bit放到右邊空缺的位置,同時送入CF標志位。

image-20220124172321064


無條件跳轉指令

  • 相對短轉移:立即數表示偏移量

    jmp short 立即數
    
  • 相對近轉移:立即數表示偏移量

    jmp near 立即數
    ; 或
    jmp 立即數
    
  • 間接絕對近轉移:寄存器或內存地址表示偏移地址

    jmp near 寄存器/[內存地址]
    ; 或
    jmp 寄存器/[內存地址]
    
  • 直接絕對遠轉移

    jmp 段地址:偏移地址
    
  • 間接絕對遠轉移

    jmp far 寄存器/[內存地址]
    

偽指令resb

  • resb

    從當前位置開始,保留指定數量的字節,但不初始化它們的值。(區分db、dw、dd、dq)

  • resw:與resb相同,但是單位為字。

  • resd:與resb相同,但是單位為雙字。


光標操作

屏幕上光標的位置保存在顯卡內部的兩個光標寄存器(8位)中,合起來是一個16位數值,表示在第幾個位置(\(0 \sim {(80 * 25) - 1}\))。

注意:文字模式下,屏幕顯示80*25個字符。

讀取光標:

步驟:

  1. 向端口號0x3d4的索引寄存器指定索引,0xe是光標位置的高8位,0xf是光標位置的低8位。
  2. 通過端口號0x3d5的數據寄存器讀取數據。

設置光標:

步驟:

  1. 向端口號0x3d4的索引寄存器寫入光標位置的索引。
  2. 向端口號0x3d5的數據寄存器寫入光標位置。

乘法

mul指令

mul 寄存器/[內存地址]
  • 8位乘法:將mul指令里指定的值乘以AL寄存器中的值,並把結果保存到AX寄存器中。
  • 16位乘法:將mul指令里指定的值乘以AX寄存器中的值,並把結果的高16位保存到DX,低16位保存到AX中。

cpuid指令

用於返回處理器的標識和特性信息。

在eax寄存器中指定要返回CPU信息。返回結果放在eax、ebx、ecx或edx中。


eflags寄存器

image-20220126165237566


comvcc指令

可以看成mov指令加上條件判斷功能,與cmptest指令配合使用。

偽代碼:

if (condition) {
    mov dest, source
}

sgdt指令

格式:sgdt 寄存器/[內存單元]

把gdtr寄存器的內容保存到指定位置。


movzx/movsx指令

  • movzx:帶零擴展傳送指令

    格式:movzx r16/r32, r8/r16/m8/m16

    把指定8位/16位寄存器/內存單元的數據放到16/32位寄存器中,並且將高位設置為0。

  • movsx:帶符號擴展傳送指令

    格式:movsx r16/r32, r8/r16/m8/m16

    把指定8位/16位寄存器/內存單元的數據放到16/32位寄存器中,並且將高位設置為跟符號位一致。


cmps指令

cmp指令的升級版,通過cx(16位)或ecx(32位)寄存器來指定比較次數,ds:si/esi寄存器指定源地址,es:di/edi寄存器指定目的地址,並根據eflags寄存器中的df位來決定地址變化的方向,\(df=0\)則正向比較,地址遞增,\(df=1\)則反向比較,地址遞減,如果沒有加上rep指令前綴,則只比較一次。

cmpsb ;字節比較
cmpsw ;字比較
cmpsd ;雙字比較

有關的rep指令前綴:

  • rep:一直重復到cx寄存器的值為0。
  • repz/repe:一直重復到cx寄存器的值為0或比較的內容不相等。
  • repnz/repne:一直重復到cx寄存器的值為0或比較的內容相等。

image-20220126173106954


調用門

調用門(Call Gate)用於不同特權級的程序之間進行控制轉移。本質上只是一個描述符(不同於代碼段和數據段)。

image-20220126200038307

調用門的特權級檢查規則:

image-20220126203513197


pushf/popf指令

把16位的flags寄存器/32位的eflags寄存器壓或彈棧到flag寄存器中。


GDT、LDT和TSS的關系

image-20220126204826235


任務切換與特權級切換的區別

image-20220126205808314


任務門

image-20220126210543989

image-20220126211109269

注意:任務是不可重入的。

任務切換:

  • 中斷引起:

    在保護模式下,產生中斷后CPU會根據中斷號查詢中斷描述符表,如果對應的中斷描述符是一個任務門,那么就會進行任務切換。

  • 使用遠過程調用指令引起:

    在使用遠過程調用指令時,CPU會去GDT中查找對應的段描述符,如果該描述符為任務門描述符,則會發起任務切換。


頁目錄項和頁表項的結構

image-20220127171112427

參數解釋:

參數 含義
P 該頁表/頁是否存在於內存中,1存在,0不存在
RW 讀寫位,0該頁只讀,1可讀可寫
US 用戶/管理位,1允許所有特權級訪問,0只允許特權級為0、1、2的程序訪問
PWT 頁級通寫位,與高速緩存相關
PCD 頁級高速緩存禁止位
A 訪問位,表示該頁是否被訪問過
D 臟位,表示該頁是否被寫過
PAT 頁屬性表支持位,與高速緩存相關
G 全局位,表示該頁是否為全局性的,如果是,則一直保留在高速緩存中
AVL 被處理器忽略,軟件可使用

CR3寄存器的內容

image-20220127175857850


bts指令

將指定位置的bit設置為1,並將其舊值設置到eflags寄存器的CF位中。

格式:

bts r/m16, r16
bts r/m32, r32

保護模式下的中斷和異常向量分配

在實模式下,是由中斷向量表定義了中斷的入口地址(位於內存最低端的1KB),而保護模式下,是由中斷描述符表(IDT)定義了中斷的入口。(由idtr寄存器指定了中斷描述符表所在位置)

中斷描述符表里面保存了中斷門、陷阱門和任務門。

image-20220127203910140

中斷門、陷阱門:

image-20220127204617586

中斷描述符寄存器:

image-20220127204549991

保護模式下的中斷處理過程:

image-20220127204822859

保護模式下通過中斷實現任務切換:

image-20220127205126792


bound指令

用於檢查數組是否超出索引(這個數組是指源操作數所指向的內存單元里面存放了上限和下限,大小為雙字)

格式:

bound r16, m16
bound r32, m32

ud2指令

該指令無操作數,執行該指令會引發一個無效操作碼異常。

格式:

ud2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM