基礎知識 機器語言 機器語言是機器指令的集合 機器指令是一臺機器可以正確執行的命令 機器指令由一串二進位數表示 彙編語言 彙編語言的主體是彙編指令 彙編指令是機器指令便於記憶的書寫格式 彙編指令是機器指令的助記符 彙編語言的組成 彙編指令:機器碼的助記符,有對應的機器碼 偽指令::沒有對應的機器碼, ...
基礎知識
機器語言
-
機器語言是機器指令的集合
-
機器指令是一臺機器可以正確執行的命令
-
機器指令由一串二進位數表示
-
彙編語言
- 彙編語言的主體是彙編指令
- 彙編指令是機器指令便於記憶的書寫格式
- 彙編指令是機器指令的助記符
彙編語言的組成
- 彙編指令:機器碼的助記符,有對應的機器碼
- 偽指令::沒有對應的機器碼,由編譯器執行,計算器並不執行
- 其他符號:如 + 、- 、* 、/ 等,由編譯器識別,沒有對應的機器碼
彙編語言的種類
- 8086彙編(8086處理器是16bit的CPU)
- Win32彙編
- Win64彙編
- AT&T彙編(Mac、iOS模擬器)
- ARM彙編(嵌入式、iOS真機)
彙編無法得到高級語言,因為不同高級語言在彙編上是相同的
匯流排
匯流排是一根根導線的集合
每一個CPU新片都有許多管腳,這些管腳和匯流排相連,CPU通過匯流排和外部器件進行交互。
匯流排的分類
地址匯流排:定址,找到地址對應的存儲空間
地址匯流排決定了CPU的定址能力,8086地址匯流排寬度是20,所以它的定址能力是1M $(2^{20})$
定址能力的計算:首先明白匯流排就是導線,導線能夠傳遞的是電信號,電信號分為兩種:高電平信號、低電平信號,高電平信號即 1,低電平信號即 0。假如匯流排匯流排的寬度是 3 ,那麼 3 根導線高電平為 1 ,低電平為 0 ,它們最大能夠傳遞的值只有 $2^3$ 種:000,001,010,011,100,101,110,111。
數據匯流排:傳遞,CPU和記憶體之間傳遞具體數據
數據匯流排決定了CPU單次數據的傳送量,也就是數據傳送的速度。8086的數據匯流排寬度是16,所以單次最大能夠傳遞2個位元組的數據。
單次數據傳送量的計算:數據匯流排的寬度是16,同地址線一樣,16根線代表16位0或1,即16位二進位數據,一次最多能夠傳送16個二進位位。一個位元組是8位,16位即2個位元組。所以8086單次能夠傳遞的最大數據量就是2個位元組。
8088的數據匯流排寬度是8,8086的數據匯流排寬度是16,分別向記憶體中寫入89D8H時(89D8H即16進位的89D8,彙編語言中末尾加H代碼16進位)。一個16進位代表4個二進位位,兩個16進位代表8個二進位位即1個位元組,四個16進位即2個位元組。因為8088數據線寬度是8,一次只能傳遞一個位元組,所以8088傳遞89D8H需要傳2次,第一次傳D8,第二次傳89。而8086只需要一次就能夠將89D8傳遞完成。
控制匯流排:控制,告訴記憶體需要進行讀還是寫操作
控制匯流排決定了CPU的控制能力,代表CPU有多少種控制能力。
CPU從記憶體中讀取數據的步驟
- CPU通過 地址線 找到需要讀取數據的地址
- 通過 控制線 告訴記憶體進行讀取操作
- 記憶體通過 數據線 返回數據給CPU
CPU 如何控制外設
CPU通過匯流排向介面卡發送命令,介面卡根據命令控制外設工作
記憶體
所有的記憶體單元都有唯一的地址,這個地址叫做物理地址。
8086CPU的地址匯流排是20根,那麼它能夠訪問的記憶體空間的地址值範圍即 0x00000 - 0xFFFFF(上面已經說明過,一個16進位位=4個二進位位),通過這個範圍可以定位 $2^{20}$ 個不同的記憶體單元,所以8006的記憶體空間大小為1M。
- 0x00000 - 0x9FFFF:主存儲空間,可讀可寫
- 0xA0000 - 0xBFFFF:顯存地址空間,數據顯示在顯示器上
- 0xC0000 - 0xFFFFF:ROM,只讀
8086的定址方式
上面提到8086的地址匯流排寬度為20,定址能力為1M,但是實際上8086是一個16位架構的CPU,它內部能夠一次性處理、傳輸、暫存的數據只有16位。這就意味這8086實際上只能夠直接送出16的地址,但是它的地址匯流排寬度又是20位,意味這這樣就有4位是無法使用的,它的實際定址能力只能夠是64KB。那麼它是如何做到實現1M的定址能力呢,具體步驟如下:
- CPU中的相關部件提供兩個16的地址,一個成為段地址,一個成為偏移地址。
- 段地址和偏移地址通過內部匯流排送入地址加法器。
- 地址加法器將兩個16位地址合成一個20位的物理地址。
- 地址加法器通過內部匯流排將20位物理地址送入輸入輸出控制電路。
- 輸入輸出控制電路將20位物理地址送入地址匯流排。
- 20位的物理地址被地址匯流排送到記憶體。
位元組與字
彙編語言沒有數據類型的概念,它是直接操作記憶體的,彙編語言的數據存儲單位有兩個:
- 位元組:byte,1個位元組由8bit組成,可以存儲在8位寄存器中。
- 字:word,1個字由2個位元組組成,這兩個位元組分別成高位元組和低位元組。
寄存器
寄存器是CPU非常重要的部件,可以通過改變寄存器的值來實現對程式的控制。不同CPU的寄存器個數和結構一般都不相同,下麵是8086CPU寄存器的結構,8086CPU有14個寄存器,所有寄存器都是16位的。
字在寄存器中的存儲
在CPU中,16位寄存器存儲一個字,高八位存儲高位位元組,低八位存儲地位位元組
在記憶體中,字的地位位元組存放在低地址單元,高位位元組存放在高地址單元
數據寄存器
數據寄存器由AX(Accumulator Register)、BX(Base Address Register)、CX(Count Register)、DX(Data Register)組成,雖然上圖裡邊每個每一個寄存器都分成了兩塊,但它依然是一個寄存器。
由於8086之前的CPU是8位的架構,所以8086為了相容8位的程式,每個16位數據寄存器都可以當作兩個單獨的8位寄存器來使用。AX寄存器可以分成兩個獨立的8位寄存器,高8位為AH,低8位為AL。BX、CX、DX同理。
除了四個數據寄存器之外,其它的寄存器均不可以分為兩個獨立的8位寄存器。獨立的意思是:當AH和AL做為8位寄存器使用時,可以看作它們是互不相關的,形式上可以看作兩個完全獨立的寄存器。
既然數據寄存器可以當作兩個獨立的寄存器,那麼它們既可以用整個寄存器的16位存放一個數據,也可以高8位和低8位分別存放一個數據共存放兩個數組。
AX(accumulate)
AX 作為累加器用,所以它是算術運算的主要寄存器。在乘、除等指令中指定用來存放操作數。
另外,所有的I/O指令都使用這一寄存器與外部設備傳送信息。
BX(base)
BX 在計算存儲器地址時,它經常用作基址寄存器。
CX(count)
CX 常用來保存計數值,如在移位指令、迴圈和串處理指令中用作隱含的計數器。
DX(data)
DX 一般在作雙字長運算時把DX和AX組合在一起存放一個雙字長數,DX用來存放高位字。
此外,對某些I/O操作,DX可用來存放I/O的埠地址。
段寄存器(Segment Register)
前面關於8086的定址方式裡邊提到,8086需要16位的段地址和偏移地址合成20位地址,其中的段地址就由段寄存器提供。段寄存器一共有四個,每個段寄存器的作用都不相同。
CS 代碼段寄存器(Code Segment Register)
CS和IP配合使用,它們指示了CPU當前要讀取指令的地址。任何時候,8086CPU都會將CS:IP指向的指令做為下一條需要取出執行的指令。
指令執行的過程:
-
從CS:IP指向的代碼段記憶體單元讀取指令,讀取的指令進入指令緩衝器。
-
IP = IP+讀取指令的長度,進而可以讀取下一條指令。
-
返回步驟1。
在記憶體或者磁碟上中,指令和數據沒有任何區別,都是二進位信息。 CPU在工作時,有時候把信息當作指令,有時候看作數據,同樣的信息賦予不同的意義。
CPU根據什麼將記憶體中的數據信息當作指令? 通過CS:IP指向的記憶體單元內容看作指令。
DS 數據段寄存器(Data Segment Register)
DS是用來操作記憶體時提供段地址的,假如需要將記憶體中10000H 存入1122H,直接這樣寫是不可以的:
mov 1000H:[0H],1122H
因為彙編語言又如下要求:
- 不能直接給記憶體地址賦值,必須通過DS:[偏移地址]指向記憶體。
- 不能直接給DS賦值,需要通過寄存器中轉
正確做法是:
mov ax,1000H
mov ds,ax
mov [0H],1122H
SS 堆棧段寄存器(Stack Segment Register)
配合SP使用,SS:SP指向棧頂元素
其他寄存器
SI 源變址寄存器(Source Index Register)
一般與DS聯用,用來確定數據段中某一單元的地址
與自動增量和自動減量的功能,方便用於變址
DI 目的變址寄存器(Destination Index Register)
與SI相同
BP 基址指針寄存器(Base Pointer Register)
可以作為堆棧區中的一個基地址以便訪問堆棧中的信息
8086專用寄存器
IP 指令指針寄存器(Instruction Pointer Register)
它用來存放代碼段中的偏移地址。在程式運行的過程中,它始終指向下一條指令的首地址,它與段寄存器CS聯用確定下一條指令的物理地址。當這一地址送到存儲器後,控制器可以取得下一條要執行的指令,而控制器一旦取得這條指令就馬上修改IP的內容,使它指向下一條指令的首地址。
可見,電腦就是用IP寄存器來控制指令序列的執行流程的,因此IP寄存器是電腦中很重要的一個控制寄存器。
SP 堆棧指針寄存器(Stack Pointer Register)
存放棧頂的偏移地址
FLAGS 標誌寄存器 / PSW 程式狀態寄存器(Program Status Word Register)
存放條件碼標誌,控制標誌和系統標誌
條件碼標誌
條件碼標誌用來記錄程式中運行結果的狀態信息,它們是根據有關指令的運行結果由CPU自動設置的。由於這些狀態信息往往作為後續條件轉移指令的轉移控制條件,所以稱為條件碼。它包括以下6位:
- OF 溢出標誌(overflow flag)
- 在進行有符號數運算過程中,如操作數超出了機器能表示的範圍稱為溢出。
- 有溢出,OF = 1 OV
- 無溢出,OF = 0 NV
- 在進行有符號數運算過程中,如操作數超出了機器能表示的範圍稱為溢出。
- SF 符號標誌(sign flag)
- 將結果視為有符號數
- 記錄運算結果的符號(符號位)
- 符號位為1時(負數),SF = 1 NG
- 符號位為0時(非負),SF = 0 PL
- ZF 零標誌(zero flag)
- 指令的運算結果是否是0
- 結果是 0 ,ZF = 1 ZR
- 1 表示 ”邏輯真“
- 結果不是0,ZF = 0 NZ
- 0 表示 ”邏輯假“
- 結果是 0 ,ZF = 1 ZR
- 指令的運算結果是否是0
- CF 進位標誌(carry flag)
- 進行無符號數運算時從最高有效位產生了進位值,或從更高位產生了借位值
- 有進位或借位,CF = 1 CY
- 無進位或借位,CF = 0 NC
- 進行無符號數運算時從最高有效位產生了進位值,或從更高位產生了借位值
- PF 奇偶標誌(parity flag)
- 用來為機器中傳送信息時可能產生的代碼出錯情況提供檢驗條件。
- 記錄指令執行後結果所有二進位位中 1 的個數
- 1的個數為偶數,PF = 1 PE
- 1的個數為奇數,PF = 0 PO
- AF 輔助進位標誌(auxiliary carry flag)
控制標誌
控制標誌位為方向標誌(direction flag,DF),在串處理指令中控制處理信息的方向用。
- 當DF位為1時,每次操作後使變址寄存器SI和DI減小,這樣就使串處理從高地址向低地址方向處理。
- 當DF位為0時,則使SI和DI增大,使串處理從低地址向高地址方向處理
系統標誌
系統標誌位可以用於I/O、可屏蔽中斷、程式調試、任務切換和系統工作方式等的控制。一般應用程式不必關心或修改這些位的狀態,只有系統程式員或需要編製低層I/O 設備控制等程式時才需要訪問其中的有關位。
- 陷阱標誌(trap flag,TF),用於調試時的單步方式操作。當TF位為1時,每條指令執行完後產生陷阱,由系統控制電腦;當TF位為0時,CPU正常工作,不產生陷阱。
- 中斷標誌(interrupt flag,IF),當IF位為1時,允許CPU響應可屏蔽中斷請求,否則關閉中斷。
- I/O特權級(I/O privilege level,.IOPI),在保護模式下,用於控制對I/O地址空間的訪問。
規範與約定
[...]
(彙編語法規定)表示一個記憶體單元
一個記憶體單元的描述:
- 記憶體單元的地址
- 段地址
- 偏移地址
- 記憶體單元的長度(類型)
(...)
(為了學習方便規定)表示一個記憶體單元或寄存器中的內容
idata
表示常量,某個字元
訪問記憶體
為了訪問記憶體,我們可以使用這四個寄存器:BX,SI,DI,BP
我們可以使用如下方式訪問對應地址:
除了BP寄存器,其他寄存器預設均使用DS寄存器,BP使用SS寄存器
BP不能和BX一起作為偏移地址,SI不能和DI一起作為偏移地址
段寄存器中的值成為 段地址 ,通用寄存器中的值稱為 偏移地址
類型
為了告訴編譯器數據類型,需要使用以下首碼:
byte ptr
位元組
word ptr
字
MOV 指令
mov 指令將第二個操作數(源)複製到第一個操作數上(目標)
- 源操作數可以是立即數,通用寄存器或記憶體地址
- 目標操作數可以是通用寄存器或記憶體地址
- 兩個操作數必須是同一數據類型
MOV 指令支持以下指令形式:
- MOV REG,memory
- MOV memory,REG
- MOV REG,REG
- MOV memory,immediate
- MOV REG,immediate
REG:AX,BX,CX,DX,AH,AL,BH,BL,CH,CL,DH,DL,DI,SI,BP,SP
memory:[BX],[BX+SI+7],variable
immediate: 5, -24, 3Fh, 10001101b
對於段寄存器只有以下指令可以使用:
- MOV SREG (
CS) ,memory - MOV memory,SREG
- MOV,REG,SREG
- MOV SREG,REG
SREG: DS, ES, SS, and only as second operand: CS.
; 假設記憶體10000H原始值: 1122H
; 8086是小端模式,高位元組放在高地址,低位元組放在低地址
; 1000:0000 22
; 1000:0001 11
; 準備修改10000H位置的值
mov ax, 1000H
mov ds, ax
; 1000:0000 66
; 1000:0001 11
; 修改後10000H: 1166H
mov [0], 66h
; 1000:0000 66
; 1000:0001 11
; 修改後10000H: 1166H
mov byte ptr [0], 66h
; 1000:0000 66
; 1000:0001 00
; 修改後10000H: 0066H
mov word ptr [0], 66h
定址方式
當數據存放在記憶體中的時候,我們可以用多種方式來給定這個記憶體單元的偏移地址,這種定位記憶體單元的方法一般稱為定址方式。
數據有關的定址方式
隱含定址
隱含定址就是指令中不指明操作數,但隱含在操作碼中。如乘法指令(MUL src)
立即數定址(immediate addressing)
操作數直接包含在指令中,緊跟在操作碼之後的定址方式稱為立即定址方式,把該操作數稱為立即數。
- 可以是8位數或16位數
- 常用來給寄存器賦值,不執行匯流排周期,速度快
- 只能用於源操作數
例:
MOV AL,2CH
MOV AX,2C40H
寄存器定址
操作數包含在CPU內的某個寄存器中,指令直接給出寄存器名。
-
對16位的操作數,寄存器可以是:AX,BX,CX,DX和SI,DI,SP,BP
對8位的操作數,寄存器可以是:AL,BL,CL,DL和AH,BH,CH,DH
-
源操作數和目的操作數都可用
-
不執行匯流排周期,執行速度快
例:
INC CX
MOV AX,BX
存儲器定址
除以上三種定址方式外,以下各種定址方式的操作數都在存儲器中,其操作數稱為存儲器操作數。
由於80X86對記憶體採用分段管理,因此由以下定址方式得到的只是有效地址(簡寫為EA-effective address,在IBM PC中就是操作數地址的偏移量部分)。
有效地址可以由以下四種成分組成:
-
位移量(displacement)是存放在指令中的一個8位、16位或32位的數,它是一個地址。
-
基址(base)是存放在基址寄存器中的內容。通常用來指向數據段中數組或字元串的首地址。
-
變址(index)是存放在變址寄存器中的內容。通常用來訪問數組中的某個元素或字元串中的某個字元。
EA = 基址 + 變址 + 位移量
直接定址
操作數的有效地址直接包含在指令中的定址方式。
有效地址存放在代碼段的指令操作碼之後,但操作數本身在存儲器中,所以必須先求出操作數的物理地址。這種定址方式常用於存取簡單變數。
- 如果沒有指定段超越首碼預設操作數在數據段
- 編譯後的程式與debug中表現不同,會將[idata]直接轉換為idata,因此需要加上段首碼
例:
MOV AL, [1400H]
由於在彙編語言中用符號表示地址,所以指令“MOV AL,VAR”中的源操作數定址方式是直接定址,有時也寫做“MOV AL,[VAR]”
寄存器間接定址
操作數的有效地址在基址寄存器BX、BP或變址寄存器SI、DI中,而操作數在存儲器中的定址方式
-
能用作間址寄存器的寄存器:BX, BP, SI, DI
-
BP為間址寄存器時,操作數在堆棧段中,其餘為數據段
例:
MOV AX, [DI]
寄存器相對定址
也稱為直接變址定址方式。操作數的有效地址是一個基址(BX、BP)或變址(SI、DI)寄存器的內容和指令中給定的一個位移量(disp)之和。有效地址由2部分組成。
-
EA = (基址/變址寄存器) + 0/8/16位位移量
-
段地址對應BX/SI/DI寄存器預設是DS,對應BP寄存器預設是SS,可用段超越首碼改變。
例:
MOV AX, [DI+0100H]
基址變址定址
操作數的有效地址是一個基址寄存器(BX、BP)和一個變址寄存器(SI、DI)的內容之和。預設使用段寄存器的情況由基址寄存器決定。
-
EA=BX/BP+SI/DI
-
段基址對應BX基址寄存器預設是DS,對應BP基址寄存器預設是SS,可用段超越首碼改變。
例:
MOV AX, [BX] [SI] ← → MOV AX, DS: [BX+SI]
相對基址變址定址
操作數的有效地址是一個基址和一個變址寄存器的內容和指令中給定的一個位移量之和。有效地址由三部分組成。預設使用段寄存器的情況由基址寄存器決定。
-
EA=BX/BP+SI/DI+8/16位位移量
-
段地址對應BX基址寄存器預設是DS,對應BP基址寄存器預設是SS,可用段超越首碼改變。
例:
MOV AX, 06H[BX+SI] ← → MOV AX, DS:[BX+SI+06H]
與轉移地址有關的定址方式
這種定址方式用來確定轉移指令及CALL指令的專項地址
非考點,略
變數
變數是一種記憶體地址
8086的彙編器支持兩種類型的變數:BYTE 和 WORD
聲明一個變數的方式如下
name DB value ;DB 表示位元組 Define Byte
name DW value ;DW 表示單字 Define Word
name DD value ;DD 表示雙字 Define Double(Word)
; name 可以是任何字元和/或數字的組合,但是它必須以一個字元開始
; 可以聲明一個未命名的變數(變數會擁有一個地址,但是沒有名字)
;value 可以是任何數字或者是 '?' 表示未初始化
數組
數組可以被視為一系列變數,下麵是一些數組聲明的例子:
a DB 48h, 65h, 6Ch, 6Ch, 6Fh, 00h
b DB 'Hello', 0
你可以通過方括弧來訪問數組中的任何元素
MOV AL,a[3]
你還可以使用任何記憶體索引寄存器 BX,SI,DI,BP 來訪問其中的元素
MOV SI,3
MOV AL,a[SI]
DUP
如果需要聲明一個一個大數組,可以使用DUP操作符
number DUP (value(s))
number —— 需要聲明的複製(任何常數)
value —— 將要複製的值
如果你想要聲明一個比255更大或比-128更小的值,你可以使用DW取代DB。註意:DW 不能被用來聲明字元串
獲得變數的地址(LEA,OFFSET)
你可以通過兩種方式獲得變數的地址:LEA(Load Effective Address)指令和它的替代品 OFFSET 操作符
LEA 同時還能讓你獲得索引變數的地址。
LEA和OFFSET最後都會被編譯為同一種機器語言:
MOV BX,num
num是一個16進位的偏移量
註意:只有以下寄存器可以被用在方括弧內(作為記憶體指針):BX,SI,DI,BP
LEA
-
格式:
LEA REG,SRC
-
操作:(REG) <- SRC
目的操作數不能使用段寄存器,源操作數可使用任一存儲器定址方式
ORG 100h
MOV AL, VAR1 ; 將VAR1的值送入AL
LEA BX, VAR1 ; 獲取VAR1的地址,並存入BX
MOV BYTE PTR [BX], 44h ; 修改VAR1的值為44h
MOV AL, VAR1 ; VAR 送入 AL
RET
VAR1 DB 22h
END
LDS,LES,LFS,LGS,LSS
LDS(load DS with pointer) 指針送寄存器和DS
LES(load ES with pointer) 指針送寄存器和ES
LFS(load FS with pointer) 指針送寄存器和FS
LGS(load GS with pointer) 指針送寄存器和GS
LSS(Load SS with Pointer) 指針送寄存器和SS
-
這一組指令完成把地址送到指定的寄存器中
-
格式:同LEA
-
操作:(以LDS為例):
(REG) <- (SRC)
(SREG) <- (SRC + 2)
或 (SREG)<- (SRC + 4)
源操作數只能使用存儲器定址方式
當指令指定的是16位寄存器時,把該存儲單元中存放的16位偏移地址裝入該寄存器中,然後把(SRC+2)中的16位數裝入指令指定的段寄存器中,32為改為(SRC+4)
目的寄存器不允許使用段寄存器,LFS、LGS、LSS只能用於386以後的機型中
不影響標誌位
OFFSET
ORG 100h
MOV AL, VAR1
MOV BX, OFFSET VAR1
MOV BYTE PTR [BX], 44h
MOV AL, VAR1
RET
VAR1 DB 22h
END
如果想要知道某條語句的地址,可以通過標號的方式獲取
S:MOV AX,BX
MOV AX,OFFSET S
P:MOV AX,OFFSET P
利用這種方法可以實現指令在程式運行中的複製:
assume cs:code
code segment
s:mov ax,bx
mov si,offset s
mov di,offset s0
mov ax,cs:[si]
mov cs:[di],ax
s0:nop ;nop 為占位符,占一個位元組
nop
code ends
ends
常量
- 常量和變數一樣,但是他們只在編譯程式時存在,為了定義常量,我們需要用到EQU指令
EQU
-
格式:
name EQU <expression>
-
功能:聲明常量
內中斷
中斷可以被看作是一系列功能。這些功能使編程變得更加簡單,而不需要編寫代碼來列印字元,你可以簡單地調用中斷,它將為您=你完成一切。還有一些與磁碟驅動器和其他硬體一起工作的中斷功能。我們將這些功能稱為軟中斷。
中斷也可以被不同的硬體觸發,這些被稱為硬中斷。目前我們只關心軟中斷。
要進行軟中斷,有一個INT指令,它有非常簡單的語法:
INT value
value 的值可以是0 ~ 255(或 0 ~ 0FFH)
- 一般我們使用十六進位數
要使用中斷的子功能,需要在調用中斷前設置寄存器
- 通常使用AH寄存器,但有時候會使用其他寄存器
常見的中斷值對應功能:
INT 21
-
AX對應值為:
-
4C:帶返回碼結束,AL = 返回碼
-
07:鍵盤輸入(無回顯)
-
01:鍵盤輸入並回顯 , AL = 輸入字元
-
00:程式終止
-
02:顯示輸出,DL = 輸出字元
-
運算
INC
- 格式:
INC opr
- 操作:opr = opr + 1
DEC
- 格式:
DEC opr
- 操作:opr = opr - 1
ADD
- 格式:
ADD opr1,opr2
- opr1:memory,register
- opr2:memory,register,immediate
- 操作:opr1 = opr1 + opr2
ADC
- 格式:
ADC opr1,opr2
- 操作:opr1 = opr1 + opr2 + CF
SUB
- 格式:
SUB opr1,opr2
- 操作:opr1 = opr1 - opr2
SBB
- 格式:
SUB opr1,opr2
- 操作:opr1 = opr1 - opr2 - CF
DIV
- 格式:
DIV opr
- opr:memory,register
- 被除數:(預設)放在AX或DX和AX中
- 8位除數
- 被除數放在AX,商放入AL,餘數放入AH
- 16位除數
- 被除數高位放在DX,低位放在AX,商放入AX,餘數放入DX
- 8位除數
MUL
- 格式:
MUL opr
- opr:memory,register
- 被乘數:(預設)放在AL或AX中
- 8位乘數
- 被乘數放在AL,結果放入AX
- 16位乘數
- 被乘數放在AX,結果高位放在DX,低位放在AX
- 8位乘數
棧
PUSH
- 格式:
PUSH src
- src 可以是:
- 寄存器:AX,BX,CX,DX,DI,SI,BP,SP
- 段寄存器:DS,ES,SS,CS
- 記憶體單元
- 立即數(僅80186以後的CPU可以)
- src 可以是:
- 功能:將一個16位數放入棧中
- 原理:SP = SP - 2, 將src的值寫入此時SP指向的記憶體單元
- SS:SP此時指向新棧頂
POP
- 格式:
POP des
- des 可以是
- 寄存器:AX,BX,CX,DX,DI,SI,BP,SP
- 段寄存器:DS,ES,SS(除了CS)
- 記憶體單元
- des 可以是
- 原理:將此時SP指向的記憶體單元中的值寫入des,SP = SP + 2
- SS:SP 此時指向新棧頂
流控制
JMP
- 基礎語法:
JMP label
- label 指程式中存在的表示,一般在行首以”label:“的形式出現
- label標記了對應行/後續一條指令
- label 指程式中存在的表示,一般在行首以”label:“的形式出現
短轉移
- 格式:
JMP short label
- 功能:(IP) = (IP) + val(8 bits)
- 原理
- 8位位移 = 標號處地址 - jmp 指令後第一個位元組的地址
- short 指明此處位移為8位位移
- 8位位移的範圍為 -128 ~ 127,用補碼表示
- 由編譯程式在編譯時算出
近轉移
- 格式:
JMP near ptr label
- 功能:(IP) = (IP) + val(16 bits)
- 原理
- 16位位移 = 標號處地址 - jmp 指令後第一個位元組的地址
- near ptr 指明此處位移為16位位移,進行的是段內近轉移
- 16位位移的範圍為 -32769 ~ 32767,用補碼表示
- 由編譯程式在編譯時算出
遠轉移
- 格式:
JMP far ptr label
- 功能:CS:IP = (label)
- 原理
- 直接跳轉到目的地址
- 段間原轉移
轉移地址在寄存器中的JMP指令
- 格式:
jmp reg
- 功能: IP = (reg)
轉移地址在記憶體中的JMP指令
段內轉移
-
格式:
JMP word ptr adr
-
功能:從記憶體單元地址處開始存放著一個字,是轉移的**目的偏移地址****
段間轉移
- 格式:
JMP dword ptr adr
- 功能:從記憶體單元地址處開始存著兩個字,高地址處的字是轉移的目的段地址,低地址處是轉移的目的偏移地址
JCXZ
-
格式:
JCXZ label
-
功能:
- 如果(cx) = 0,則轉移到標號處執行
- (IP) = (IP) + 8位位移
- 8位位移 = 標號處地址 - jcxz指令後第一個位元組的地址
- (IP) = (IP) + 8位位移
- 否則什麼也不做(程式向下執行)
- 如果(cx) = 0,則轉移到標號處執行
-
是有條件轉移指令
- 所有有條件轉移指令都是短轉移
- 對IP的修改範圍都為-128~127
- 在對應的機器碼中包含轉移的位移,而不是目的地址
LOOP
- 格式:
LOOP label
- 指令操作:
- (cx) = (cx) - 1
- (cx) != 0時,轉移到標號處執行,否則向下執行
- 是相對位移
- 反指令為:
DEC CX
+JCXZ
LOOPE
-
指令操作:
- (cx) = (cx) - 1
- (cx) != 0 且 zf = 1 (Equal) 時,轉移到標號處執行,否則向下執行
-
反指令為:
LOOPNE
LOOPZ
- 指令操作:
- (cx) = (cx) - 1
- (cx) != 0 且 zf = 0 時,轉移到標號處執行,否則向下執行
- 反指令為:
LOOPNZ
其他有條件短轉移
單個標誌位檢測
指令 | 作用 | 條件 | 反指令 |
---|---|---|---|
JZ,JE | Jump if Zero(Euqal)(=) | ZF = 1 | JNZ,JNE |
JC,JB,JNAE | Jump if Carry(Below,Not Above Equal)(<) | CF = 1 | JNC,JNB,JNE |
JS | Jump if Sign (Negative) | SF = 1 | JNS |
JO | Jump if Overflow | OF = 1 | JNO |
JPE,JP | Jump if Parity Even | PF = 1 | JPO,JNP |
有符號數的條件檢測:
指令 | 作用 | 條件 | 反指令 |
---|---|---|---|
JE,JZ | Jump if Euqal(=) Jump if Zero |
ZF = 1 | JNZ,JNE |
JG,JNLE | Jump if Greater(>) Jump if Not Less or Equal(not <=) |
ZF = 0 and SF = OF | JNG,JLE |
JL,JNGE | Jump if Less(<) Jump if Not Greater or Equal(not >=) |
SF != OF | JNL,JGE |
無符號數的條件檢測
指令 | 作用 | 條件 | 反指令 |
---|---|---|---|
JE,JZ | Jump if Euqal(=) Jump if Zero |
ZF = 1 | JNZ,JNE |
JA,JNBE | Jump if Above(>) Jump if Not Below or Equal(not <=) |
CF = 0 and ZF = 0 | JNA,JBE |
JB,JNAE,JC | Jump if Below(<) Jump if Not Above or Equal(not >=) Jump if Carry |
CF = 1 | JNB,JAE,JNC |
CMP
通常我們使用CMP來進行比較
格式:CMP oprand1,oprand2
它將 openrand1 和 oprand2 相減,但是不保存結果,只根據結果來改變符號位
CALL 與 RET
CALL
- 格式:
CALL label
- 操作:
- 將當前IP或CS和IP壓入棧中
- 轉移到標號處執行指令
- 16位位移 = 標號處地址 - CALL指令後第一個位元組的地址
- 16位位移範圍為-32768~32767
CALL far ptr
-
格式:
CALL far ptr label
-
操作:
- (sp) = (sp) - 2
- ((ss) x 16 + (sp)) = (CS)
- (sp) = (sp) - 2
- ((ss) x 16 + (sp)) = (IP)
-
(CS) = 標號所在的段地址
(IP) = 標號所在的偏移地址
-
相當於
push CS push IP jmp far ptr label
轉移地址在寄存器中的CALL指令
-
格式:
CALL reg
-
操作:
- (sp) = (sp) - 2
- ((ss) x 16 + (sp)) = (IP)
-
(IP) = (reg)
-
相當於
push IP jmp reg
轉移地址在記憶體中的CALL指令
段內轉移
-
格式:
CALL word ptr adr
-
相當於
push IP jmp word ptr adr
段間轉移
-
格式:
CALL dword ptr adr
-
相當於
push CS push IP jmp dword ptr adr
RET
- 格式:
RET
- 功能:用棧中的數據,修改IP的內容,從而實現近轉移
- 相當於
pop IP
RETF
-
格式:
RETF
-
功能:用棧中的數據,修改CS和IP的內容,從而實現遠轉移
-
相當於
pop IP pop CS