8086汇编语言精华笔记总结~
目錄
- 第一章 匯編語言的基礎知識
- 1、計算機系統概述
- 硬件(Handware)
- 軟件(Software)
- 2、匯編語言介紹
- 3、數據表示
- 1. BCD碼
- 2. ASCII碼
- 3. 真值和機器數
- 4. 補碼
- 4、8086微處理器
- 1、通用寄存器
- 2、標志寄存器FLAGS
- 3、指令指針IP
- 4、段寄存器
- 段超越前綴指令
- 計算機中信息的單位
- 數據的地址對齊
- 存儲器(men)的分段管理
- 5、8086尋址方式
- 1、指令的組成
- 2、8086的機器代碼格式
- 3、立即數尋址方式
- 4、存儲器尋址方式
- 1. 直接尋址方式
- 2. 寄存器間接尋址方式
- 3. 寄存器相對尋址方式
- 4. 基址變址尋址方式
- 5. 相對基址變址尋址方式
- 5、尋址方式的多種表示方式
- 6、各種操作數的表達
- 第二章 8086指令系統
- 1、數據傳送類指令
- 1. 傳送指令MOV
- 2. 交換指令XCHG
- 3. 換碼指令XLAT
- 4. 堆棧操作指令PUSH、POP
- 5. 標志傳送指令
- 6. 標志位操作指令
- 7、地址傳送指令
- 有效地址傳送指令 LEA
- 指針傳送指令 LDS 和 LES
- 2、算術運算類指令
- 1、加法指令ADD、ADC、INC
- 2、減法指令SUB、SBB、DEC
- 3、求補指令 NEG
- 4、比較指令CMP
- 5、乘法指令MUL、IMUL
- 6、除法指令DIV、IDIV
- 7、符號擴展指令CBW、CWD
- 8、十進制調整指令
- 壓縮BCD碼調整
- 非壓縮BCD碼調整
- 3、位操作指令
- 1、邏輯或指令 AND
- 2、邏輯與指令 OR
- 3、邏輯異或指令XOR
- 4、邏輯非指令 NOT
- 5、測試指令 TEST
- 6、移位指令(shift)
- 7、循環移位指令(rotate)
- 4、控制轉移類指令
- 1、無條件轉移指令 JMP
- 2、條件轉移指令 JCC
- 3、循環指令(loop)
- 4、子程序指令
- 5、中斷指令
- 5、處理機控制類指令
- 1、空操作指令 NOP
- 2、段超越前綴指令
- 3、封鎖前綴指令 LOCK
- 4、暫停指令 HLT
- 5、交權指令 ESC
- 6、等待指令
- 第三章 匯編語言程序格式
- 1、匯編語言程序的開發
- 1、匯編語言程序設計的語句格式
- 2、匯編語言的程序格式
- 3、匯編語言的開發過程
- 4、DOS系統功能調用
- 功能調用的步驟
- 輸入輸出類調用
- 1、字符輸出:
- 2、字符串輸出:
- 3、字符輸入:
- 4、字符串輸入:
- 5、按鍵判斷:
- 2、參量、變量和符號
- 1、參數
- 1. 常數
- 2. 數值表達式
- 3. 地址型參數
- 2、變量定義偽指令
- 1. 變量名
- 2. 位指令助記符
- 3. 初值表
- 3、變量和標號的屬性
- 3、程序段的定義和屬性
- exe程序
- com程序
- 1、簡化段定義偽指令合集
- .MODEL存儲模型位指令
- 簡化段定義偽指令
- .STARTUP 程序開始偽指令
- EXIT [返回參數] 程序終止偽指令
- END [標號] 匯編結束偽指令
- 2、com程序的編寫
- 3、完整段定義偽指令
- 完整段定義位指令
- 指定段寄存器偽指令
- 段組偽指令
- 段順序偽指令
- 4、簡化段定義格式的段屬性
- 第四章 基本匯編語言程序設計
- 1、順序程序設計
- 2、分支程序設計
- 1、單分支程序設計
- 2、雙分支程序設計
- 3、多分支程序設計
- 3、循環程序設計
- 1、冒泡法
- 2、串操作類指令
- 4、 子程序設計
- 1、過程定義位指令
- 2、子程序的參數傳遞
- 3、子程序的嵌套
- 4、子程序的遞歸
- 5、子程序的重入
- 第五章 高級匯編語言程序設計
- 1、高級語言特性
- 1、條件控制偽指令
- 2、循環控制偽指令
- 3、過程聲明和過程調用偽指令
- 2、宏結構程序設計
- 1、宏匯編
- a. 宏
- b. 宏指令
- c. 宏展開
- 宏的參數
- 宏操作符
- 與宏有關的偽指令
- 宏匯編與子程序的比較
- 2、重復匯編
- 1. 按參數值重復
- 2. 按參數個數重復
- 3. 按參數字符個數重復
- 3、條件匯編
- 宏結構的作用
- 3、模塊化程序設計
- 1. 源程序文件的包含
- 2. 目標代碼文件的連接
- 3. 子程序庫的調入
- 4、輸入輸出程序設計
- 1、 輸入輸出指令
- a. 輸入指令IN
- b. 輸出指令OUT
- 2、程序直接控制輸入輸出
- 3、程序查詢輸入輸出
- 4、中斷服務程序
- 內部中斷服務程序
- 駐留中斷服務程序
- 外部可屏蔽中斷服務程序
第一章 匯編語言的基礎知識
1、計算機系統概述
硬件(Handware)
- 中央處理器CPU
- 運算器,控制器,寄存器
- 存儲區
- 主存儲器:RAM、ROM
- 輔助存儲器:硬盤,光盤,U盤
- 外部設備
- 輸入設備和輸出設備
軟件(Software)
- 系統軟件(eg:操作系統)
- 應用軟件
其中我們程序員最關心的有三個
- 寄存器(Register)
- CPU內部的高速存儲單元
- 為CPU提供
數據和地址信息
- 存儲器地址(Address)
- 由大量存儲單元組成,用
編號區分每個存儲單元 - 存儲器的
地址=存儲器中存儲單元的編號 - 每個存儲單元存放
一個字節的數據(1Byte=8bit) - 地址采用
十六進制表達- Inter8086有1MB的存儲器容量(1MB=210KB=220B)
- 存儲器地址表示為:00000H~FFFFFH
- 由大量存儲單元組成,用
- 端口(Port)
- 是
I/O地址的別稱 - I/O接口電路由
接口寄存器組成,用編號區分各寄存器 - I/O
地址=接口電路中寄存器的編號 - 端口采用
十六進制表達- Intel 8086支持64K個8位端口
- I/O地址可以表示為:0000H~FFFFH
- 是
2、匯編語言介紹
以
助記符形式表示計算機指令,匯編格式指令以及使用它們編寫程序的規則就形成匯編語言
- **匯編語言程序:**用匯編語言書寫的程序
- **匯編程序:**將匯編語言程序
匯編成機器代碼目標模塊的程序 匯編語言程序和匯編程序是兩個不同的概念
3、數據表示
1. BCD碼
壓縮BCD碼:一個字節表達兩位BCD碼非壓縮BCD碼:一個字節表達一位BCD碼(低4位表達數值,高4位常設置為0)
2. ASCII碼
標準ASCII碼用7位二進制編碼,有128個
不可顯示的控制字符:
- 前32個和最后一個編碼
回車CR:0DH換行LF:0AH響鈴BEL:07H
可顯示和打印的字符:20H開始的95個編碼
-
數碼
0~9:30H~39H -
大寫字母
A~Z:41H~5AH -
小寫字母
a~z:61H~7AH -
空格:20H -
擴展ASCII碼:最高D7位為1,表達
制表符
3. 真值和機器數
**真值:**現實中真實的數值
**機器數:**計算機中用0和1數碼組合表達的數
**定點數:**固定小數點的位置表達數值的機器數
- 定點整數:將小數點固定在機器數的最右側表達的整數
- 定點小數:將小數點固定在機器數的最左側表達的小數
浮點數:小數點浮動表達的實數
無符號數:只表達0和正整數的定點整數
有符號數:表達負整數、0和正整數的定點整數
- 符號位需要占用一個位
- 常用機器數的最高位,0表示正數、1表示負數
4. 補碼
有符號數在計算機中默認采用了補碼- **最高位表示符號:**正數用0,負數用1
- **正數補碼:**直接表示數值大小(同無符號數)
- **負數補碼:**將對應正數補碼取反加1
4、8086微處理器
微處理器是微機的硬件核心,主要包含指令執行的運算和控制部件,還有多種寄存器
8086內部結構有兩個功能模塊,完成一條指令的取指和執行功能
- 總線接口單元
BIU:負責讀取指令和操作數 - 執行單元
EU**:**負責指令譯碼和執行
8086CPU所有寄存器都是16位的,都可以存放兩個字節,可存儲的數據的最大值為2^16-1
1、通用寄存器
16位通用寄存器:AX BX CX DX SI DI BP SP8 位通用寄存器:AH BH CH DH AL BL CL DL
數據寄存器: 用來存放計算的結果和操作數,也可存放地址
| AX | 累加器,使用頻度最高,用于算術、邏輯運算以及與外設傳送信息等; |
|---|---|
| BX | 基址寄存器,常用做存放存儲器地址**;** |
| CX | 計數器,作為循環和串操作等指令中的隱含計數器; |
| DX | 數據寄存器,常用來存放雙字長數據的高16位,或存放外設端口地址。 |
**變址寄存器:**用于存儲器尋址時提供地址(在串操作指令中有特殊用法)
| SI | 是源變址寄存器 |
|---|---|
| DI | 是目的變址寄存器 |
**指針寄存器:**用于尋址內存堆棧內的數據(與SS堆棧段寄存器聯合確定堆棧段中存儲單元地址)
| SP | 為堆棧指針寄存器,指示棧頂的偏移地址,不能再用于其他目的,具有專用目的 |
|---|---|
| BP | 為基址指針寄存器,表示數據在堆棧段中的基地址 |
2、標志寄存器FLAGS
用于反映指令
執行結果或者控制指令執行形式
-
狀態標志:記錄程序執行結果的狀態信息CF(進位標志):運算結果
最高位有進位(加法)或借位(減法),CF=1,針對無符號數AF(輔助進位標志):運算時
D3位(低半字節)有進位或者借位,AF=1ZF(零位標志):運算
結果為0,則ZF=1SF(符號標志):運算結果
最高位為1,SF=1PF(奇偶標志):運算結果中
低八位中1的個數為0/偶數時,PF=1OF(溢出標志):運算結果
超出范圍(例如8位表達的范圍是+127~-128)則產生溢出,ZF=1,針對有符號數 -
控制標志:可根據需要設置,控制指令執行方式DF:DF置0,則串操作控制處理方向,從帶有最低地址的第一個元素逐個處理,否則,從高向低
IF:IF=1,CPU允許中斷,IF=0,則CPU關閉中斷
TF:TF=1,機器進入單步工作方式,每條機器指令執行后,顯示結果及寄存器狀態,若TF=0,則機器處在連續工作方式。此標志為調試機器或調試程序發現故障而設置。
3、指令指針IP
- 指示代碼段中指令的
偏移地址,通過CS:IP指向下一條指令的物理地址 - 是一個
專用寄存器
4、段寄存器
8086有四個
段寄存器,每個段寄存器確定了一個邏輯段的起始地址
| CS(Code Segment) | 指明代碼段的起始地址(CS:IP指向下一條要執行的指令) |
|---|---|
| SS(Stack Segment) | 指明堆棧段的b起始地址(SS:SP操作堆棧頂的數據) |
| DS(Data Segment**)** | 指明數據段的起始地址(DS:EA存取數據段中的數據) |
| ES(Extra Segment) | 指明附加段(附加數據段)的起始地址(ES:EA存取附加段中的數據) |
段超越前綴指令
- 默認的數據訪問在
DS段 - 默認的情況允許改變,需要使用
段超越前綴指令
| CS: | ;代碼段超越,使用代碼段的數據 |
|---|---|
| SS: | ;堆棧段超越,使用堆棧段的數據 |
| DS: | ;數據段超越**,**使用數據段的數據 |
| ES: | ;附加段超越,使用附加段的數據 |
計算機中信息的單位
| 二進制位Bit | 存儲一位二進制數:0或1 |
|---|---|
| 字節Byte | 8個二進制位,D7~D0 |
| 字Word | 16位,2個字節,D15~D0 |
| 雙字Dword | 32位,4個字節,D31~D0 |
- 最低有效位LSB:數據的最低位,D0位
- 最高有效位MSB**:**數據的最高位,對應字節、字、雙字分別指D7、D15、D31位
數據的地址對齊
- 字單元在偶地址(xxx0B)、雙字單元在模4地址(xx00B)
存儲器(men)的分段管理
-
8086CPU有
20根地址線- 最大尋址空間為2^20=1MB
- 物理尋址范圍從00000H~FFFFFH
-
8086CPU將
1MB的空間分成許多邏輯段,各個段之間可以重疊- 每個段的最大限制為
2^16=64KB - 段地址低四位為0000B
- 每個段的最大限制為
-
這樣,每個存儲單元除了唯一的一個物理地址外,還有多個邏輯地址
-
邏輯地址= 段基地址:段內偏移地址- 邏輯地址是16位的,因此范屬圍是2的16次方,即
64K
- 邏輯地址是16位的,因此范屬圍是2的16次方,即
-
物理地址= 段地址 * 16 (二進制數據左移四位,十六進制左移一位) + 偏移地址- 物理地址是20位的,因此范圍是2的20次方,即
1M
- 物理地址是20位的,因此范圍是2的20次方,即
5、8086尋址方式
1、指令的組成
指令由
操作碼和操作數兩部分組成;
指令的助記符格式:
操作碼 操作數1,操作數2 ;注釋
- 有些指令不需要操作數,通常的指令都有一個或兩個操作數,個別指令有3個甚至4個操作數
2、8086的機器代碼格式
示例一:
示例二:
示例三:
3、立即數尋址方式
-
直接存放在機器代碼中,緊跟在操作碼之后的操作數為立即數(imm)
- 8位數值
i8(00F~FFH) - 16位數值
i16(0000H~FFFFH)
- 8位數值
-
立即數常用來給寄存器賦值
MOV AL,05H ;AL←05H MOV AX,0102H ;AX←0102H
4、存儲器尋址方式
-
操作數存放在cpu的內部寄存器reg中8位寄存器 r8AH、AL、BH、BL、CH、CL、DH、DL 16位寄存器 r16AX、BX、CX、DX、SI、DI、BP、SP 4個段寄存器 segCS、DS、SS、ES -
指令中給出操作數的
主存地址信息
多種存儲器尋址方式:
1. 直接尋址方式
有效地址直接在指令中給出- 默認
段地址在DS寄存器,可用段超越前綴改變
MOV AX,[2000H] ;AX←DS:[2000H] 指令代碼:A1 00 20
MOV AX,ES:[2000H] ;AX←ES:[2000H] 指令代碼:26 A1 00 20
2. 寄存器間接尋址方式
有效地址放在BX(基址寄存器)或變址寄存器(SI,DI)中- 默認
段地址在DS寄存器,可用段超越前綴改變
MOV AX,[SI] ;AX←DS:[SI]
3. 寄存器相對尋址方式
有效地址是寄存器內容(BX/BP/SI/DI)和有符號8位或16位位移量之和
有效地址=BX/BP/SI/DI+8/16位位移量
段地址對應BX/SI/DI寄存器默認在DS,對應BP寄存器默認在SS;可用段超越前綴改變
MOV AX,[DI+06H] ;AX←DS:[DI+06H]
MOV AX,[BP+06H] ;AX←SS:[BP+06H]
4. 基址變址尋址方式
有效地址是基址寄存器(BX)/指針寄存器(BP)和變址寄存器(SI/DI)之和
有效地址=BX/BP+SI/DI
段地址對應BX基址寄存器默認是DS,對應BP指針寄存器默認是SS;可用段超越前綴改變
MOV AX,[BX+SI] ;AX←DS:[BX+SI]
MOV AX,[BP+DI] ;AX←SS:[BP+DI]
MOV AX,DS:[BP+DI] ;AX←DS:[BP+DI]
5. 相對基址變址尋址方式
有效地址是基址寄存器(BX)/指針寄存器(BP)和變址寄存器(SI/DI)和一個有符號8位或16位位移量之和
有效地址=BX/BP+SI/DI+8/16位位移量
段地址對應BX基址寄存器默認是DS,對應BP指針寄存器默認是SS;可用段超越前綴改變
MOV AX,[BX+SI+06H] ;AX←DS:[BX+SI+06H]
5、尋址方式的多種表示方式
-
位移量可用符號表示:
MOV AX,[SI+COUNT] ;COUNT是事先定義的變量或常量(就是數值) MOV AX,[BX+SI+WNUM] ;WNUM是變量或常量 -
同一尋址方式可以寫成不同的形式:
MOV AX,[BX][SI] ;MOV AX,[BX+SI] MOV AX,COUNT[SI] ;MOV AX,[SI+COUNT] MOV AX,WNUM[BX][SI] ;等同于 MOV AX,WNUM[BX+SI];等同于 MOV AX,[BX+SI+WNUM]
6、各種操作數的表達
-
寄存器操作數的表達
r8(任意一個8位通用寄存器) AH AL BH BL CH CL DH DL r16(任意一個16位通用寄存器) AX BX CX DX SI DI BP SP reg 代表r8或r16 seg 段寄存器CS DS ES SS -
存儲器操作數的表達
m8 一個8位存儲器操作數單元(所有主存尋址方式) m16 一個16位存儲器操作數單元(所有主存尋址方式) mem 代表m8或m16 -
立即數的表達
i8 一個8位立即數 i16 一個16位立即數 imm 代表i8或i16 dest 目的操作數 src 源操作數
第二章 8086指令系統
1、數據傳送類指令
1. 傳送指令MOV
把一個字節或字的操作數從源地址傳送至目的地址
;reg:通用寄存器
;mem:存儲器
;imm:立即數
;seg:段寄存器
MOV reg/mem,imm
MOV reg/mem/seg,reg
MOV reg/seg,mem
MOV reg/mem,seg
注意:
-
兩個操作數類型一致(對于存儲器單元和立即數同時作為操作數的情況,需要顯示聲明;
byte ptr為字節類型,word ptr為字類型)mov byte ptr [si],0ah ;byte ptr 說明是字節操作 mov word ptr [si+2],0bh ;word ptr 說明是字操作 -
兩個操作數不能都是存儲器(要實現這種操作,通過寄存器實現)
mov ax,buffer1 ;ax←buffer1(將buffer1內容送ax) mov buffer2,ax ;buffer2←ax -
段寄存器的操作有一些限制
-
不允許立即數傳給段寄存器
MOV DS,100H ;非法指令:立即數不能傳送段寄存器 -
不允許改變CS(代碼段)的值
MOV CS,[SI] ;不允許使用的指令 -
不允許段寄存器之間的直接數據傳送
MOV DS,ES ;非法指令:不允許段寄存器間傳送
-
2. 交換指令XCHG
將兩個地方的數據進行交換
- 寄存器與寄存器之間對換數據
- 寄存器與存儲器之間對換數據
- 不能在存儲器與存儲器之間對換數據
XCHG reg,reg/mem ;reg<->reg/mem
3. 換碼指令XLAT
將BX指定的緩沖區中、AL指定的位移處的一個字節數據取出賦給AL
XLAT ;al←ds:[bx+al]
示例:
mov bx,100h
mov al,03h
Xlat
;換碼指令沒有顯式的操作數,但使用了BX和AL;
;因為換碼指令使用了隱含尋址方式——采用默認操作數
4. 堆棧操作指令PUSH、POP
PUSH:
PUSH r16/m16/seg ;SP<SP-2 SS:[SP]←r16/m16/seg
POP:
POP r16/m16/seg ;r16/m16/seg←SS:[SP] SP←SP+2
-
堆棧的操作單位是
字,2個字節 -
進展和出棧時,都是低地址字節送低字節,高地址字節送高字節(
小端對齊) -
堆棧操作遵循
先進后出原則,但可用存儲器尋址方式隨機存取數據 -
常見作用:
-
臨時存放數據
-
傳遞參數
-
保存和恢復寄存器
push ax ;進入子程序后 push bx push ds ... pop ds ;返回主程序前 pop bx pop ax
-
5. 標志傳送指令
用來傳送標志寄存器FLAGS的內容
低八位傳送:LAHF 和 SAHF16位傳送:PUSHF 和 POPF
LAHF
AH <- FLAGS的低字節
- SF/ZF/AF/PF/CF狀態標志位分別進入
AH的第7/6/4/2/0位,而AH的5/3/1位任意
SAHF
FLAGS的低字節 <- AH
- 用
AH的第7/6/4/2/0位響應設置SF/ZF/AF/PF/CF標志位
PUSHF
- 保存所有標志到堆棧
POPF
- 將堆棧內容取出到標志寄存器
6. 標志位操作指令
-
標志位操作指令直接對
CF、DF、IF標志進行復 位或置位,常用于特定的情況 -
用于任意設置進位標志
CLC ;復位進位標志:CF←0 STC ;置位進位標志:CF←1 CMC ;求反進位標志:CF←~CF -
串操作指令中,需要使用
CLD ;復位方向標志:DF←0 STD ;置位方向標志:DF←1 -
在編寫中斷服務程序時,需要控制可屏蔽中斷的允許和禁止
CLI ;復位中斷標志:IF←0 STI ;置位中斷標志:IF←1
7、地址傳送指令
將存儲器單元的
邏輯地址送至指定的寄存器
有效地址傳送指令 LEA
- 將存儲器操作數的有效地址傳送到指定的16位寄存器中
LEA r16,mem ;r16←mem的有效地址EA
- 示例:
mov bx,0400h
mov si,3ch
lea bx,[bx+si+0f62h] ;BX=0400h+003ch+0f62h=139EH
- 獲得主存單元的
有效地址;不是物理地址,也不是該單元的內容 - 可以實現計算功能
指針傳送指令 LDS 和 LES
- LDS指令將主存中mem指定的字送至
r16,并將mem的下一字送至DS寄存器
LDS r16,mem ;r16←mem DS←mem+2
- LES指令將主存中mem指定的字送至
r16,并將mem的下一字送至ES寄存器
LES r16,mem ;r16←mem ES←mem+2
- 示例:
mov word ptr [3060h],0100h
mov word ptr [3062h],1450h
les di,[3060h] ;es=1450h,di=0100h
lds si,[3060h] ;ds=1450h,si=0100h
mem指定主存的連續4個字節作為邏輯地址(32位的地址指針),送入DS:r16或ES:r16
2、算術運算類指令
1、加法指令ADD、ADC、INC
- ADD:將源與目的操作數相加,結果送到目的操作數
ADD reg,imm/reg/mem ; reg ← reg+imm/reg/mem
ADD mem,imm/reg ; mem ← mem+imm/reg
- ADC:將源與目的操作數相加,再加上進位
CF標志,結果送到目的操作數
ADC reg,imm/reg/mem ; reg ← reg+imm/reg/mem+CF
ADC mem,imm/reg ; mem ← mem+imm/reg+CF
- INC:對操作數
加1(不影響CF,按定義設置其他狀態標志)
INC reg/mem ; reg/mem ← reg/mem+1
2、減法指令SUB、SBB、DEC
- SUB:將目的操作數減去源操作數,結果送到目的操作數(按照定義相應設置狀態標志)
SUB reg,imm/reg/mem ; reg ← reg-imm/reg/mem
SUB mem,imm/reg ; mem ← mem-imm/reg
- SBB:將目的操作數減去源操作數,再減去
借位CF(進位),結果送到目的操作數(按照定義相應設置狀態標志)
SBB reg,imm/reg/mem ; reg ← reg-imm/reg/mem-CF
SBB mem,imm/reg ; mem ← mem-imm/reg-CF
- DEC:對操作數
減1(不影響CF,按定義設置其他狀態標志)
DEC reg/mem ; reg/mem ← reg/mem-1
3、求補指令 NEG
用零減去操作數,然后結果返回操作數求補運算也可以表達成:`將操作數按位取反后加1`
NEG reg/mem ; reg/mem ← 0-reg/mem
4、比較指令CMP
將目的操作數減去源操作數,按照定義相應設置狀態標志
執行的功能與SUB指令相同,但結果不回送目的操作數
CMP reg,imm/reg/mem ; reg-imm/reg/mem
CMP mem,imm/reg ; mem-imm/reg
5、乘法指令MUL、IMUL
- MUL:
無符號乘法
MUL r8/m8 ;AX ← AL*r8/m8
MUL r16/m16 ;DX.AX ← AX*r16/m16
- IMUL:
有符號乘法
IMUL r8/m8 ;AX ← AL*r8/m8
IMUL r16/m16 ;DX.AX ← AX*r16/m16
-
乘法指令對標志的影響
MUL指令 若乘積的高一半(AH或DX)為0,則OF=CF=0;否則OF=CF=1 IMUL指令 若乘積的高一半是低一半的符號擴展,則OF=CF=0;否則均為1 -
乘法指令對其他狀態標志沒有定義
6、除法指令DIV、IDIV
- DIV:無符號除法
MUL r8/m8 ;AL←AX÷r8/m8的商 AH←AX÷r8/m8的余數
MUL r16/m16 ;AX←DX.AX÷r16/m16的商 DX←DX.AX÷r16/m16的余數
- IDIV:有符號除法
IMUL r8/m8 ;AL←AX÷r8/m8的商 AH←AX÷r8/m8的余數
IMUL r16/m16 ;AX←DX.AX÷r16/m16的商 DX←DX.AX÷r16/m16的余數
- 除法指令對標志沒有定義
- 除法指令會產生結果溢出
- 除法錯中斷: 當被除數遠大于除數時,所得的商就有可能超出它所能表達的范圍。如果存放商的寄存器AL/AX不能表達,便產生溢出,8086CPU中就產生編號為0的內部中斷
- 對DIV指令,除數為0,或者在字節除時商超過8位,或者在字除時商超過16位
- 對IDIV指令,除數為0,或者在字節除時商不在-128~127范圍內,或者在字除時商不在-32768~32767范圍內
7、符號擴展指令CBW、CWD
- 用一個操作數的符號位(即最高位)形成另一個操作數,后一個操作數的各位是全0(正數)或全1(負數)
- 符號擴展不改變數據大小
- 對于數據64H(表示數據100),其最高位D7為0,符號擴展后高8位都是0,成0064H(仍表示數據100)
- 對于數據FF00H(表示有符號數-256),其最高位D15為1,符號擴展后高16位都是1,成為FFFFFF00H(仍表示有符號數-256)
8、十進制調整指令
壓縮BCD碼調整
-
加減調整
- 使用DAA或DAS指令前,應先執行以AL為目的操作數的加法或減法指令
- DAA和DAS指令對OF標志無定義,按結果影響其他標志
- 例如CF反映壓縮BCD碼相加或減的進位或借位狀態
mov al,68h ;al=68h,壓縮BCD碼表示真值68
mov bl,28h ;bl=28h,壓縮BCD碼表示真值28
add al,bl ;二進制加法:al=68h+28h=90h
daa ;十進制調整:al=96h 實現壓縮BCD碼加法:68+28=96
mov al,68h ;al=68h,壓縮BCD碼表示真值68
mov bl,28h ;bl=28h,壓縮BCD碼表示真值28
sub al,bl ;二進制減法:al=68h-28h=40h
das ;十進制調整:al=40h 實現壓縮BCD碼減法:68-28=40
非壓縮BCD碼調整
-
加減調整
- 使用AAA或AAS指令前,應先執行以AL為目的操作數的加法或減法指令
- AAA和AAS指令在調整中產生了進位或借位,則AH要加上進位或減去借位,同時CF=AF=1,否則CF=AF=0;
- 對其他標志無定義
mov ax,0608h ;ax=0608h,非壓縮BCD碼表示真值68
mov bl,09h ;bl=09h,非壓縮BCD碼表示真值9
add al,bl ;二進制加法:al=08h+09h=11h
Aaa ;十進制調整:ax=0707h 實現非壓縮BCD碼加法:68+9=77
mov ax,0608h ;ax=0608h,非壓縮BCD碼表示真值68
mov bl,09h ;bl=09h,非壓縮BCD碼表示真值9
sub al,bl ;二進制減法:al=08h-09h=ffh
aas ;十進制調整:ax=0509h 實現非壓縮BCD碼減法:68-9=59
- 乘除調整
-
AAM指令跟在字節乘MUL之后,將乘積調整為非壓縮BCD碼
-
AAD指令跟在字節除DIV之前,先將非壓縮BCD碼的被除數調整為二進制數
-
AAM和AAD指令根據結果設置SF、ZF和PF,但對OF、CF和AF無定義
mov ax,0608h ;ax=0608h,非壓縮BCD碼表示真值68 mov bl,09h ;bl=09h,非壓縮BCD碼表示真值9 mul bl ;二進制乘法:al=08h×09h=0048h aam ;十進制調整:ax=0702h 實現非壓縮BCD碼乘法:8×9=72mov ax,0608h ;ax=0608h,非壓縮BCD碼表示真值68 mov bl,09h ;bl=09h,非壓縮BCD碼表示真值9 aam ;二進制擴展:ax=68=0044h div bl ;除法運算:商al=07h,余數ah=05h;實現非壓縮BCD碼除法:68÷9=7(余5)
3、位操作指令
以二進制位為基本單位進行數據操作
1、邏輯或指令 AND
| AND reg,imm/reg/mem | ;reg←reg∧imm/reg/mem |
|---|---|
| AND mem,imm/reg | ;mem←mem∧imm/reg |
- AND指令設置CF = OF = 0,根據結果設置SF、ZF和PF狀態,而對AF未定義
2、邏輯與指令 OR
| OR reg,imm/reg/mem | ;reg←reg∨imm/reg/mem |
|---|---|
| OR mem,imm/reg | ;mem←mem∨imm/reg |
- OR指令設置CF = OF = 0,根據結果設置SF、ZF和PF狀態,而對AF未定義
3、邏輯異或指令XOR
- 異或不同為1,相同為0
| XOR reg,imm/reg/mem | ;reg←reg⊕imm/reg/mem |
|---|---|
| XOR mem,imm/reg | ;mem←mem⊕imm/reg |
- XOR指令設置CF = OF = 0,根據結果設置SF、ZF和PF狀態,而對AF未定義
4、邏輯非指令 NOT
| NOT reg/mem | ;reg/mem←~reg/mem |
|---|---|
- NOT指令是一個單操作數指令,不影響標志位
5、測試指令 TEST
- 對兩個操作數執行邏輯與運算,結果不送到目的操作數
| TEST reg,imm/reg/mem | ;reg∧imm/reg/mem |
|---|---|
| TEST mem,imm/reg | ;mem∧imm/reg |
- XOR指令設置CF = OF = 0,根據結果設置SF、ZF和PF狀態,而對AF未定義
6、移位指令(shift)
- 將操作數移動一位或多位,分成邏輯移位和算術移位,分別具有左移或右移操作
| SHL reg/mem,1/CL | ;邏輯左移,最高位進入CF,最低位補0 |
|---|---|
| SHR reg/mem,1/CL | ;邏輯右移,最低位進入CF,最高位補0 |
- 邏輯左移一位相當于無符號數乘以2,邏輯右移一位相當于無符號數除以2
| SAL reg/mem,1/CL | ;算術左移,最高位進入CF,最低位補0 |
|---|---|
| SAR reg/mem,1/CL | ;算術右移,最低位進入CF,最高位不變 |
- 移位指令的第一個操作數是指定的被移位的操作數,可以是寄存器或存儲單元
- 后一個操作數表示移位位數,該操作數為1,表示移動一位;當移位位數大于1時,則用CL寄存器值表示,該操作數表達為CL
- 按照移入的位設置進位標志CF,根據移位后的結果影響SF、ZF、PF,而對AF未定義
- 對于OF,如果進行一位移動,則按照操作數的最高符號位是否改變,相應設置溢出標志OF:如果移位前的操作數最高位與移位后操作數的最高位不同(有變化),則OF = 1;否則OF = 0。當移位次數大于1時,OF不確定
7、循環移位指令(rotate)
- 將操作數從一端移出的位返回到另一端形成循環,分成不帶進位和帶進位,分別具有左移或右移操作
| ROL reg/mem,1/CL | ;不帶進位循環左移 |
|---|---|
| ROR reg/mem,1/CL | ;不帶進位循環右移 |
| RCL reg/mem,1/CL | ;帶進位循環左移 |
| RCR reg/mem,1/CL | ;帶進b位循環右移 |
- 按照指令功能設置進位標志CF,不影響SF、ZF、PF、AF
- 對于OF,如果進行一位移動,則按照操作數的最高符號位是否改變,相應設置溢出標志OF:如果移位前的操作數最高位與移位后操作數的最高位不同(有變化),則OF = 1;否則OF = 0。當移位次數大于1時,OF不確定
4、控制轉移類指令
- 用于實現分支、循環、過程等程序結構
- 通過改變IP(和CS)值,實現程序執行順序的改變
1、無條件轉移指令 JMP
JMP label ;程序轉向label標號指定的地址
- 執行JMP,使程序轉到指定的目標地址處,從目標地址處開始執行指令
- 操作數label是要轉移到的目標地址(目的地址、轉移地址)
- 目標地址的尋址方式
- 相對尋址方式:以當前IP為基地址,加上位移量構成目標地址
- 直接尋址方式:轉移地址像立即數一樣,直接在指令的機器代碼中
- 間接尋址方式:轉移地址在寄存器或主存單元中
- 轉移方式
- 段內轉移——近轉移(near)
- 在當前代碼段64KB范圍內轉移
- 不需要更改CS地址,只要改變IP偏移地址
- 段內轉移——短轉移(short)
- 轉移范圍可以用一個字節表達,在段內-128~+127的范圍轉移
- 段間轉移——遠轉移(far)
- 從當前代碼段跳轉到另一個代碼段,可在1MB之內
- 更改CS和IIP
- 目標地址必須用一個32位數表達,叫做32位遠指針(邏輯地址)
- 段內轉移——近轉移(near)
JMP指令分為四種類型
-
段內轉移,相對尋址
- 位移量是緊接著JMP指令后的那條指令的偏移地址,到目標指令的偏移地址的地址位移
- 當向地址增大方向轉移時,位移量為正;向地址減小方向轉移時,位移量為負
JMP label ;IP←IP+位移量 -
段內轉移,間接尋址
- 將一個16位寄存器或主存字單元內容送入IP寄存器,作為新的指令指針,但不修改CS寄存器的內容
JMP r16/m16 ;IP←r16/m16 -
段間轉移,直接尋址
- 將標號所在段的段地址作為新的CS值,標號在該段內的偏移地址作為新的IP值;這樣,程序跳轉到新的代碼段執行
JMP far ptr label ;IP←label的偏移地址 CS←label的段地址 -
段間轉移,間接尋址
- 用一個雙字存儲單元表示要跳轉的目標地址。這個目標地址存放在主存中連續的兩個字單元中的,低位字送IP寄存器,高位字送CS寄存器
JMP far ptr mem ;IP←[mem],CS←[mem+2]
2、條件轉移指令 JCC
JCC label ;條件滿足,發生轉移:IP←IP+8位位移量 條件不滿足,順序執行
操作數label采用 相對尋址、短轉移 方式
- 表示Jcc指令后的那條指令的偏移地址,到目標指令的偏移地址的地址位移
- 距當前IP地址-128~+127個單元的范圍之內
JCC指令不影響標志,但要利用標志,分為3種情況:
- 判斷單個標志位狀態
- 比較無符號數大小
- 比較有符號數大小
轉移條件cc:單個標志狀態
| JZ/JE | ZF=1 | Jump if Zero/Equal |
|---|---|---|
| JNZ/JNE | ZF=0 | Jump if Not Zero/Not Equal |
| JS | SF=1 | Jump if Sign |
| JNS | SF=0 | Jump if Not Sign |
| JP/JPE | PF=1 | Jump if Parity/Parity Even |
| JNP/JPO | PF=0 | Jump if Not Parity/Parity Odd |
| JO | OF=1 | Jump if Overflow |
| JNO | OF=0 | Jump if Not Overflow |
| JC | CF=1 | Jump if Carry |
| JNC | CF=0 | Jump if Not Carry |
轉移條件cc:兩數大小關系
| 無符號數: | ------------------------- | -------------------------------------------- |
|---|---|---|
| JB/JNAE | CF=1 | Jump if Below/Not Above or Equal |
| JNB/JAE | CF=0 | Jump if Not Below/Above or Equal |
| JBE/JNA | CF=1或ZF=1 | Jump if Below/Not Above |
| JNBE/JA | CF=0且ZF=0 | Jump if Not Below or Equal/Above |
| 有符號數: | ------------------------- | -------------------------------------------- |
| JL/JNGE | SF≠OF | Jump if Less/Not Greater or Equal |
| JNL/JGE | SF=OF | Jump if Not Less/Greater or Equal |
| JLE/JNG | ZF≠OF或ZF=1 | Jump if Less or Equal/Not Greater |
| JNLE/JG | SF=OF且ZF=0 | Jump if Not Less or Equal/Greater |
3、循環指令(loop)
- 操作數label采用 相對尋址、短轉移 方式
- 默認利用CX計數器
| JCXZ label | ;CX=0,轉移到標號label |
|---|---|
| LOOP label | ;CX←CX-1,CX≠0,循環到標號label |
| LOOPZ label | ;CX←CX-1,CX≠0且ZF=1,循環到標號label |
| LOOPNZ label | ;CX←CX-1,CX≠0且ZF=0,循環到標號label |
4、子程序指令
- 子程序是完成特定功能的一段程序
- CALL指令調用子程序,RET指令返回主程序
子程序調用指令:
-
CALL指令有四種類型:
CALL label ;段內調用、相對尋址 CALL r16/m16 ;段內調用、間接尋址 CALL far ptr label ;段間調用、直接尋址 CALL far ptr mem ;段間調用、間接尋址 -
CALL指令需要保存返回地址
-
段內調用——入棧偏移地址IP
-
SP←SP-2,SS:[SP]←IP -
段間調用——入棧偏移地址IP和段地址CS
-
SP←SP-2,SS:[SP]←IP SP←SP-2,SS:[SP]←CS
子程序返回指令:
- 根據段內和段間、有無參數,分成4種類型
| RET | ;無參數段內返回 |
|---|---|
| RET i16 | ;有參數段內返回 |
| RET | ;無參數段間返回 |
| RET i16 | ;有參數段間返回 |
-
需要彈出CALL指令壓入堆棧的返回地址
-
段內返回——出棧偏移地址IP
IP←SS:[SP], SP←SP+2
- 段間返回——出棧偏移地址IP和段地址CS
IP←SS:[SP],SP←SP+2CS←SS:[SP],SP←SP+2
- 返回指令RET的參數
RET i16 ;有參數返回
-
RET指令可以帶有一個立即數i16,
則堆棧指針SP將增加,即 SP←SP+i16
-
這個特點使得程序可以方便地廢除若干執行CALL指令以前入棧的參數
5、中斷指令
中斷(Interrupt )是又一種改變程序執行順序的方法,具有多種類型
8086外部中斷:來自CPU之外的原因引起的中斷,可分為:
- 可屏蔽中斷:可由CPU的中斷允許標志IF控制
- 非屏蔽中斷:不受CPU的中斷允許標志IF控制
8086內部中斷:CPU內部執行程序引起的中斷,可分成:
- 除法錯中斷:執行除法指令,結果溢出產生的 0號 中斷
- 指令中斷:執行中斷調試指令 INT i8 產生的 i8號 中斷
- 斷點中斷:用于斷點調試(INT 3)的 3號 中斷
- 溢出中斷:執行溢出中斷指令,OF=1產生的 4號 中斷
- 單步中斷:TF=1在每條指令執行后產生的 1號 中斷
中斷指令INT
| INT i8 | ;中斷調用指令:產生i8號中斷 |
|---|---|
| IRET | ;中斷返回指令:實現中斷返回 |
| INTO | ;溢出中斷指令;若溢出標志OF=1,產生4號中斷;否則順序執行 |
5、處理機控制類指令
1、空操作指令 NOP
-
不執行任何操作,但占用一個字節存儲單元,空耗一個指令執行周期
-
NOP常用于程序調試
- 在需要預留指令空間時用NOP填充
- 代碼空間多余時也可以用NOP填充
- 還可以用NOP實現軟件延時
-
事實上,NOP和 XCHG AX,AX 的指令代碼一樣,都是 90H
2、段超越前綴指令
- 在允許段超越的存儲器操作數之前,使用段超越前綴指令,將采用指定的段寄存器尋址操作數
| CS: | ;使用代碼段的數據 |
|---|---|
| SS: | ;使用堆棧段的數據 |
| DS: | ;使用數據段的數據 |
| ES: | ;使用附加段的數據 |
3、封鎖前綴指令 LOCK
LOCK ;封鎖總線
- 這是一個指令前綴,可以放在任何指令前
- 這個前綴使得在這個指令執行時間內,8086 處理器的封鎖輸出引腳有效,即把總線封鎖,使別的控制器不能控制總線;直到該指令執行完后,總線封鎖解除
4、暫停指令 HLT
HLT ;進入暫停狀態
- 暫停指令使CPU進入暫停狀態,這時CPU不進行任何操作。當CPU發生復位或來自外部的中斷時,CPU脫離暫停狀態
- HLT指令可用于程序中等待中斷。當程序中必須等待中斷時,可用HLT,而不必用軟件死循環。然后,中斷使CPU脫離暫停狀態,返回執行HLT的下一條指令
5、交權指令 ESC
ESC 6位立即數,reg/mem ;把浮點指令交給浮點處理器執行
- 浮點協處理器8087指令是與8086的整數指令組合在一起的,當8086發現是一條浮點指令時,就利用ESC指令將浮點指令交給8087執行
6、等待指令
WAIT ;進入等待狀態
- 8086利用WAIT指令和測試引腳實現與8087同步運行
- 浮點指令經由8086處理發往8087,并與8086本身的整數指令在同一個指令序列;而8087執行浮點指令較慢,所以8086必須與8087保持同步
第三章 匯編語言程序格式
1、匯編語言程序的開發
編輯—匯編–連接–調試
1、匯編語言程序設計的語句格式
- 執行性語句:由
硬指令構成的語句,通常對應一條機器指令,出現在程序的代碼段中
標號: 硬指令助記符 操作數,操作數 ; 注釋
- 說明性語句:由
偽指令構成的語句它通常指示匯編程序如何匯編源程序
名字 偽指令助記符 參數,參數.. ;注釋
-
標號、名字與標識符:
-
標號:反映硬指令(邏輯地址)的標識符,后加冒號分隔 -
名字:反映位指令(邏輯地址)和屬性的標識符,后跟空格或制表符分隔,沒有冒號 -
標識符:一般最多由31個字母、數字及規定的特殊符號(如、$、?、@)組成,不能以數字開頭。默認情況下,匯編程序不區別標識符中的字母大小寫- 一個程序中,每個標識符的定義是唯一的,還不能是匯編語言采用的保留字
-
-
保留字:匯編程序已經利用的標識符
硬指令助記符 例如:MOV、ADD 偽指令助記符 例如:DB、EQU 操作符 例如:OFFSET、PTR 寄存器名 例如:AX、CS 預定義符號 例如:@data -
助記符
-
操作數與參數:
- 處理器指令的操作數可以是立即數、寄存器和存儲單元
- 偽指令的參數可以是常數、變量名、表達式等,可以有多個,參數之間用逗號分隔
-
注釋
-
分隔符:
- 語句的4個組成部分要用分隔符分開
- 標號后用冒號,注釋前用分號
- 操作數之間和參數之間使用逗號分隔
- 其他部分通常采用空格或制表符
- 多個空格和制表符的作用與一個相同
- MASM支持續行符"\"
2、匯編語言的程序格式
- 完整的匯編程序由段組成,可以包含若干個代碼段、數據段、附加段、堆棧段,段與段之間的順序可以隨意排列
- 獨立運行的程序必須包含一個代碼段,并指示程序執行的起始點,一個程序只有一個起始點
- 可執行語句必須在一個代碼段中,說明性語句可位于任何一個段中
匯編源程序有兩種格式:
-
簡化段定義格式(MASM5.0開始支持)
;MASM 6.X支持 ;example.asm ;文件名.model small ;程序存儲模型.stack ;定義堆棧段.data ;定義數據段... ;在數據段定義數據.code ;定義代碼段.startup ;程序起始點,建立DS、SS... ;在代碼段填入指令序列.exit 0 ;程序結束點,返回DOS... ;子程序代碼end ;匯編結束;MASM 5.X支持 ;example.asm ;文件名.model samll ;程序存儲模型.stack ;定義堆棧段.data ;定義數據段... ;在數據段定義數據.code ;定義代碼段 start: move ax,@data move ds,ax ;這兩句指令等價于.startup... ;代碼段,填入指令序列move ax,4c00h int 21h ;這兩句指令等價于.exit 0... ;子程序代碼end start ;匯編結束 -
完整段定義格式(MASM5.0以前就具有)
;MASM 5.X支持 ;example.asm ;文件名 stack segment stack ;定義堆棧段dw 512 dup(?) ;堆棧段有512字(1024字節)空間 stack ends ;堆棧段結束 data segment ;定義數據段... ;在數據段定義數據 data ends ;數據段結束 code segment 'code' ;定義代碼段assume cs:code,ds:data,ss:stack start: move ax,data ;建立DS段地址move ds,ax... ;在代碼段填入指令序列move ax,4c00hint 21h ;利用功能調用返回DOS... ;子程序代碼 code ends ;代碼段結束end start ;匯編結束,同時指明程序起始點
3、匯編語言的開發過程
-
準備工作
- 安裝開發軟件包
- 進入操作系統(模擬DOS環境)
- 進入MSAM開發目錄
-
源程序的
編輯- 以ASM為擴展名
-
源程序的
匯編-
匯編是將程序翻譯成由機器代碼組成的目標模塊文件的過程
-
MASM 6.X提供的匯編程序是ML.EXE
-
如果源程序中沒有語法錯誤,MASM將自動生成一個目標模塊文件(.obj);否則MASM將給出相應的錯誤信息
ML /c lt301.asm -
-
目標模塊的
鏈接- 鏈接程序能把一個或多個目標文件和庫文件合成一個可執行文件(.EXE、.COM文件)
- 如果沒有錯誤,則會生成一個可執行文件(.EXE),否則將提示相應的錯誤信息
LINK lt301.obj
ML匯編程序可以自動調用LINK連接程序,實現匯編和連接的依次進行
- 該命令除了產生模塊化文件.obj和可執行文件.exe之外,還會產生列表文件.lst
- 列表文件是一種文本文件,含有源程序和目標代碼
-
可執行程序的調試
- 經過匯編,連接生成的可執行程序在操作系統下只要輸入文件名就可以運行
lt301.exe- 操作系統裝載該文件進入主存,并開始運行
4、DOS系統功能調用
21H中斷是DOS給用戶用于調用系統功能的中斷,它有近百個功能,只要包括設備管理,目錄管理和文件管理這三個方面的功能ROM-BIOS也以中斷服務程序的形式,向程序員提供系統的基本輸入輸出程序
功能調用的步驟
- 在
AH寄存器設置系統功能的調用號 - 在指定寄存器中設置入口參數
- 執行
INT 21H(或ROM-BIOS的中斷向量號)實現中斷服務程序的功能調用 - 根據出口參數分析功能調用執行情況
輸入輸出類調用
1、字符輸出:
-
功能號:
AH=02H -
入口參數:
DL=字符的ASCII碼 -
功能:在顯示器當前光標位置顯示給定的字符,光標右移一個字符位置。
按Ctrl-Berak或Ctrl-C退出
2、字符串輸出:
- 功能號:
AH=09H - 入口參數:
DS:DX=欲顯示字符串在主存中的首地址,字符串應以$(24H)結束 - 功能:在顯示器輸出指定的字符串【可以輸出回車(0DH)和換行(0AH)字符產生回車和換行的作用】
3、字符輸入:
-
功能號:
AH=01H -
入口參數:
AL=字符的ASCII碼- 功能:獲得按鍵的ASCII代碼值
【調用此功能時,若無鍵按下,則會一致等待,直到按鍵后才讀取該鍵值】
4、字符串輸入:
-
功能號:
AH=0AH -
入口參數:
DS:DX=緩沖區首地址 -
執行該功能調用時,用戶按鍵,最后用回車確認
【該調用可以執行全部標準鍵盤編輯命令;用戶按回車鍵結束輸入,如按Ctrl+Break或Ctrl+c則終止】
緩沖區的定義
示例:
5、按鍵判斷:
- 功能號:
AH=0BH - 出口參數:
AL=0,當前沒有按鍵;AL=FFH,當前已經按鍵 - 功能:僅判斷當前是否有按下的鍵,設置AL后退出
2、參量、變量和符號
1、參數
- 參數是指令的操作對象,參數之間用
逗號分隔 - 參數可以沒有,可以有1、2或多個
- 參數有數值型,主要形式是常數和數值表達式
1. 常數
表達一個固定的數值
-
十進制常數:由0 ~ 9數字組成,以字母D或d結尾,缺省情況下,后綴D或d可以省略100 255D -
十六進制常數:由0~9、A~F組成,以字母H或h結尾以字母A~F開頭的十六進制數,前面要用0表達,以避免與其他符號混淆64H 0FFh 0B800H -
二進制常數: 由0或1兩個數字組成,以字母B或b結尾01101100B -
八進制常數:用單引號或雙引號括起來的單個字符或多個字符,其數值是每個字符對應的ASCII碼的值'd' = 64H 'AB'= 4142H 'Hello, Everybody !' -
符號常數:利用一個標識符表達的一個數值
MASM提供等價機制,用于常量定義;等價EQU偽指令符號名 EQU 數值表達式符號名 EQU <字符串>;等號=偽指令符號名 = 數值表達式
示例:
DosWriteChar equ 2
CarriageReturn = 13
CallDOS equ <int 21h>mov ah,2 ;mov ah,DosWriteChar
mov dl,13 ;mov dl,CarriageReturn
int 21h ;CallDOS
2. 數值表達式
指由運算符連接的各種常數所構成的表達式
算數運算符:+ - * / MOD
mov ax,3*4+5 ;等價于 mov ax,17
;除加、減外,其他運算符的參數必須是整數
邏輯運算符:AND OR XOR NOT
or al,03h AND 45h ;等價于 or al,01h
-
移位運算符:SHL SHR實現
邏輯左移、右移;移入低位高位都是0
mov al,0101b SHL (2*2) ;等價于 mov al,01010000b
關系運算符:- EQ(等于) NE(不等于) GT(大于) LT(小于) GE(大于等于) LE(小于等于)
- 用于比較和測試符號數值
- MASM用
0FFFFH(補碼-1)表示條件為真 - MASM用
0000H表示條件為假
mov bx,((PORT LT 5)AND 20)OR((PORT GE 5)AND 30)
;當PORT<5時,匯編結果為mov bx,20
;否則,匯編結果為mov bx,30
-
高低分離符:- HIGH LOW HIGHWORD LOWWORD
;HIGH、LOW從一個字數值或符號常量中得到高、低字節 mov ah,HIGH 8765h ;等價于mov ah,87h;HIGHWORD、LOWWORD取一個符號常量(不能是其他常數)的高字或低字部分 dd_value equ 0ffff1234h ;定義一個符號常量 mov ax,LOWWORD dd_value ;等價于mov ax,1234h
3. 地址型參數
- 主要形式:標號和名字(變量名、段名、過程名等)
- 硬指令的操作數有存儲單元;存儲單元就應該用地址型參數(存儲器操作數)表達
2、變量定義偽指令
作用:為變量申請固定長度的存儲空間,并可同時將相應的存儲單元初始化
格式:變量名 位指令助記符 初值表
1. 變量名
- 變量名為用戶自定義標識符,表示初值表首元素的邏輯地址;用這個符號表示地址,常稱為符號地址
- 可以沒有變量名。此時匯編程序會直接為初值表分配空間,無符號地址
- 設置變量名是為了方便存取它指示的存儲單元
2. 位指令助記符
-
DB——定義字節偽指令- 用于分配一個或多個字節單元,并可以將它們初始化為指定值
- 初值表中每個數據一定是字節量(Byte),存放一個8位數據
- 可以是0~255的無符號數
- 或是-128~+127帶符號數
- 也可以是字符串常數
.data ;數據段 X db 'a',-5 db 2 dup(100),? Y db 'ABC' mov al,X ;此處X表示它的第1個數據,故AL←'a' dec X+1 ;對X為始的第2個數據減1,故成為-6 mov Y,al ;現在Y這個字符串成為 'aBC'
-
DW——定義字偽指令- 用于分配一個或多個字單元,并可以將它們初始化為指定值
- 初值表中每個數據一定是字量(Word),一個字單元可用于存放任何16位數據
- 一個段地址
- 一個偏移地址
- 兩個字符
- 0~65535之間的無符號數
- -32768~+32767之間的帶符號數
.data ;數據段 count dw 8000h,?,'AB' maxint equ 64h number dw maxint array dw maxint dup(0)
-
DD——定義雙字偽指令- 用于分配一個或多個雙字單元,并可以將它們初始化為指定值
- 初值表中每個數據是一個32位的雙字量
- 可以是有符號或無符號的32位整數
- 也可以用來表達16位段地址(高位字)和16位的偏移地址(低位字)的遠指針
vardd DD 0,?,12345678h farpoint DD 00400078h
DF——定義3字偽指令- 用于為一個或多個6字節變量分配空間及初始化
- 6字節常用在32位CPU中表示一個48位遠指針(16位段選擇器:32位偏移地址)
- 用于為一個或多個6字節變量分配空間及初始化
DQ——定義4字偽指令- 用于為一個或多個8字節變量分配空間及初始化
- 8字節變量可以表達一個64位整數
- 用于為一個或多個8字節變量分配空間及初始化
DT——定義10字節偽指令- 用于為一個或多個10字節變量分配空間及初始化
- 10字節變量可以表達擴展精度浮點數
- 用于為一個或多個10字節變量分配空間及初始化
-
定位偽指令:控制數據的偏移地址、-
ORG參數:ORG偽指令是將當前偏移地址指針指向參數表達的偏移地址:ORG 100h ;從100h處安排數據或程序 ORG $+10 ;使偏移地址加10,即跳過10個字節空間MASM中,符號“$”表示當前偏移地址值EVEN ;從偶地址開始 ALIGN n ;從n的整數倍地址開始
-
3. 初值表
-
初值表是用逗號分隔的參數
-
主要由數值常數、表達式或?、DUP組成
-
?——表示初值不確定,即未賦初值
-
DUP——表示重復初值
-
DUP的格式為:
重復次數 DUP(重復參數)
-
3、變量和標號的屬性
-
地址屬性
- 標號和名字對應存儲單元的邏輯地址
- 邏輯地址包括:段地址和偏移地址
-
類型屬性
- 標號、子程序名可以是NEAR、FAR,分別表示段內和段間
- 變量名的類型可以是BYTE(字節)、WORD(字)、DWROD(雙字)
-
地址操作符:取得名字或標號的段地址和偏移地址兩個屬性
[ ] 將括起的表達式作為存儲器地址 $ 當前偏移地址 : 采用指定的段地址寄存器 OFFSET 名字/標號 返回名字或標號的偏移地址 SEG 名字/標號 返回名字或標號的段地址 -
類型操作符:對名字或標號的類型屬性進行有關設置
-
類型名 PTR 名字/標號
- PTR操作符使名字或標號具有指定的類型
- 使用PTR操作符,可以臨時改變名字或標號的類型
- 類型名可以是:BYTE/WORD/DWORD/FWORD/QWORD/TBYTE或者是NEAR/FAR,還可以是由STRUCT、RECORD、UNION以及TYPEDEF定義的類型
mov al,byte ptr w_var ;w_var是一個字節變量 jmp far ptr n_label ;n_label是一個標號 -
THIS 類型名
- 利用THIS說明的操作數具有匯編時的當前邏輯地址,但具有指定的類型
b_var equ THIS byte ;按字節訪問變量b_var,但與w_var的地址相同 w_var dw 10 dup(0) ;按字訪問變量w_var f_jump equ THIS far ;用f_jump為段間轉移(f_jump label far) n_jump: mov ax,w_var ;用n_jump為段內近轉移,但兩者指向同一條指令- LABEL偽指令的功能等同于“EQU THIS”
-
SHORT 標號
-
TYPE 名字/標號
- 返回表明名字或標號類型的一個字量數值
- 對字節、字和雙字變量依次返回1、2和4;
- 對短、近和遠轉移依次返回ff01h、ff02h和ff05h
mov ax,TYPE w_var ;匯編結果為 mov ax,2 mov ax,TYPE n_jump ;匯編結果為 mov ax,0ff02h(near標號)- 操作符SIZEOF返回整個變量占用的字節數
- LENGTHOF返回整個變量的數據項數(即元素數) SIZEOF = LENGTHOF × TYPE
-
SIZEOF 變量名
-
LENGTHOF 變量名
-
3、程序段的定義和屬性
exe程序
- 可執行程序
- 可以有獨立的代碼、數據和堆棧段,還可以有多個代碼段或多個數據段,程序長度可以超過64KB,執行起始處可以任意指定
- 當DOS裝入或執行一個程序時,DOS確定當時主存最低的可用地址作為該程序的裝入起始點。此點以下的區域稱為程序段。在程序段內偏移0處,DOS為該程序建立一個程序段前綴控制塊PSP(Program Segment Prefix),它占256(=100h)個字節;而在偏移100h處才裝入程序本身
com程序
- COM程序是一種將代碼、數據和堆棧段合一的結構緊湊的程序,所有代碼、數據都在一個邏輯段內,不超過64KB
- 程序開發中,需要滿足一定的要求并采用相應參數才能夠生成COM結構的程序
- COM文件存儲在磁盤上是主存的完全影象,不包含重新定位的加載信息,與EXE文件相比其加載速度更快,占用的磁盤空間也少
- 盡管DOS也為COM程序建立程序段前綴PSP,但由于兩種文件結構不同,所以加載到主存后各段設置并不完全一樣
1、簡化段定義偽指令合集
.MODEL存儲模型位指令
-
使用簡化段定義,必須有存儲模型位指令
-
.model語句位于所有段定義語句之前
-
存儲模型決定一個程序的規模,確定進行子程序調用、指令轉移和數據訪問的缺省屬性
-
MASM有7種不同的存儲模型:
① TINY ② SMALL
③ COMPACT ④ MEDIUM
⑤ LARGE ⑥ HUGE
⑦ FLAT
簡化段定義偽指令
-
.STACK [大小] ;堆棧段開始
.DATA ;數據段開始
.CODE [段名] ;代碼段開始
-
簡化段定義偽指令指明一個邏輯段的開始,同時自動結束前面的一個段,采用簡化段定義偽指令前,需有.model語句
-
使用簡化段定義,各段名稱和其他用戶所需的信息可以使用MASM預定義符號
例如:@data表示由.data等定義的數據段的段名
.STARTUP 程序開始偽指令
- 按照CPU類型、存儲模型、操作系統和堆棧類型,產生程序開始執行的代碼;同時還指定程序開始執行的起始點
- 在DOS下,還將設置DS值,調整SS和SP值
EXIT [返回參數] 程序終止偽指令
- 產生終止程序執行返回操作系統的指令代碼
- 它的可選參數是一個返回的數碼,通常用0表示沒有錯誤
- 例如.exit 0對應的代碼是:
mov ax,4c00h
int 21h
- DOS功能調用的4ch子功能(返回DOS):
- 入口參數:AH=4ch,AL=返回數碼
END [標號] 匯編結束偽指令
- 指示匯編程序MASM到此結束匯編過程
- 源程序的最后必須有一條END語句
- 可選的標號用于指定程序開始執行點,連接程序將據此設置CS : IP值
- 采用了.startup偽指令就不需要再用“end 標號”指明開始執行點,但還要有end偽指令
2、com程序的編寫
-
利用MASM 6.x的簡化段定義格式,可以非常容易地創建一個COM程序
-
遵循的規則:
-
- 采用TINY模型
- 源程序只設置代碼段,無數據、堆棧等段
- 程序必須從偏移地址100h處開始執行
- 數據只能安排在代碼段中,注意不能與可執行代碼相沖突,通常在程序最后
3、完整段定義偽指令
完整段定義位指令
段名 segment 定位 組合 段字 '類別'... ;語句序列
段名 ends
-
段定位(align)屬性:指定邏輯段在主存儲器中的邊界
BYTE 段開始為下一個可用的字節地址(xxxx xxxxb) WORD 段開始為下一個可用的偶數地址(xxxx xxx0b) DWORD 段開始為下一個可用的4倍數地址(xxxxxx00b) PARA 段開始為下一個可用的節地址(xxxx 0000b) PAGE 段開始為下一個可用的頁地址(0000 0000b) - 簡化段定義偽指令的代碼段和數據段默認采用WORD定位,堆棧段默認采用PARA定位
- 完整段定義偽指令的默認定位屬性是PARA,其低4位已經是0,所以默認情況下數據段的偏移地址從0開始
-
段組合(combine)屬性:指定多個邏輯段之間的關系
PRIVATE 本段與其他段沒有邏輯關系,不與其他段合并,每段都有自己的段地址。這是完整段定義偽指令默認的段組合方式 PUBLIC 連接程序把本段與所有同名同類型的其他段相鄰地連接在一起,然后為所有這些段指定一個共同的段地址,也就是合成一個物理段。這是簡化段定義偽指令默認的段組合 STACK 本段是堆棧的一部分,連接程序將所有STACK段按照與PUBLIC段的同樣方式進行合并。這是堆棧段必須具有的段組合 -
段字(use)屬性
-
為支持32位段而設置的屬性
-
對于16位×86cpu來說,默認是16位段,即USE16
而對于匯編32位x86 CPU指令時,它默認采用32位段,即USE32;但可以使用USE16指定標準的16位段
-
編寫運行于實地址方式(8086工作方式)的匯編語言程序,必須采用16位段
-
-
段類別(class)屬性
- 當連接程序組織段時,將所有的同類別段相鄰分配
- 段類別可以是任意名稱,但必須位于單引號中
- 大多數MASbM程序使用 ‘code’、'data’和’stack’來分別指名代碼段、數據段和堆棧段,以保持所有代碼和數據的連續
指定段寄存器偽指令
- 通知MASM用指定的段寄存器來尋址對應的邏輯段,即建立段寄存器與段的缺省關系
- 在明確了程序中各段與段寄存器之間的關系后,匯編程序會根據數據所在的邏輯段,在需要時自動插入段超越前綴。這是ASSUME偽指令的主要功能
- ASSUME偽指令并不為段寄存器設定初值,連接程序LINK將正確設置CS : IP和SS : SP,由于數據段通常都需要,所以在樣板源程序中,首先為DS賦值;如果使用附加段,還要賦值ES
段組偽指令
-
把多個同類段合并為一個64KB物理段,并用一個組名統一存取它
-
定義段組后,段組內各段就統一為一個段地址,各段定義的變量和標號的偏移地址就相對于段組基地址計算
-
offset操作符取變量和標號相對于段組的偏移地址,如果沒有段組則取得相對于段的偏移地址
offset后可以跟段組中的某個段名,表示該段最后一個字節后面字節相對于段組的偏移地址
段順序偽指令
-
.SEG ;按照源程序的各段順序
.DOSSEG ;按照微軟使用的標準DOS規定
.ALPHA ;按照段名的字母順序
- 段順序偽指令確定各邏輯段在主存的前后位置
- 完整段定義格式中,默認按照源程序各段的書寫順序安排(即.seg)
- 采用.model偽指令的簡化段定義格式,則是規定的標準DOS程序順序( 即.dosseg ):
代碼段 → 數據段 → 堆棧段
主存地址低端 ——> 高端
4、簡化段定義格式的段屬性
-
采用簡化段定義格式的源程序,同樣具有段定位、組合、類別以及段組等屬性(表3.4),具有默認的屬性
-
.MODEL偽指令除了設置程序采用的存儲模型外,還具有如下語句的作用:
dgroup GROUP _data,_bss,stack
assume cs:_TEXT,ds:dgroup,ss:dgroup
第四章 基本匯編語言程序設計
1、順序程序設計
順序程序完全按指令書寫的前后順序執行每一條指令,是最基本、最常見的程序結構
2、分支程序設計
- 分支程序根據條件是真或假決定執行與否
- 判斷的條件是各種指令,如CMP、TEST等執行后形成的狀態標志
- 轉移指令Jcc和JMP可以實現分支控制;還可以采用MASM 6.x提供的條件控制偽指令實現
1、單分支程序設計
- 條件成立跳轉,否則順序執行分支語句體;注意選擇正確的條件轉移指令和轉移目標地址
2、雙分支程序設計
-
條件成立跳轉執行第2個分支語句體,否則順序執行第1個分支語句體。
注意第1個分支體后一定要有一個JMP指令跳到第2個分支體后
3、多分支程序設計
- 多個條件對應各自的分支語句體,哪個條件成立就轉入相應分支體執行。多分支可以化解為雙分支或單分支結構的組合
3、循環程序設計
- 循環結構一般是根據某一條件判斷為真或假來確定是否重復執行循環體
- 循環指令和轉移指令可以實現循環控制;還可以采用MASM 6.x提供的循環控制偽指令實現
1、冒泡法
- “冒泡法”是一種排序算法,不是最優的算法,但它易于理解和實現
- 冒泡法從第一個元素開始,依次對相鄰的兩個元素進行比較,使前一個元素不大于后一個元素;將所有元素比較完之后,最大的元素排到了最后;然后,除掉最后一個元素之外的元素依上述方法再進行比較,得到次大的元素排在后面;如此重復,直至完成就實現元素從小到大的排序
- 這需要一個雙重循環程序結構
move cx,count ;cx數組元素個數dec cx ;外循環個數,元素個數減1
outlp: move dx,cx ;dx為內循環個數move bx,offset array
inlp: move al,[bx] ;取前一個元素cmp al,[bx+1] ;與后一個元素比較jna next ;前一個不大于后一個元素,則不進行交換xchg al,[bx+1] ;否則,進行交換move [bx],al
next: inc bx ;下一對元素dec dxjnz inlp ;內循環尾loop outlp ;外循環尾
2、串操作類指令
-
串傳送 MOVES
- 把字節或字從主存的源地址傳送到目的地址
MOVSB ;字節串傳送:ES:[DI]←DS:[SI] ;SI←SI±1,DI←DI±1 MOVSW ;字串傳送:ES:[DI]←DS:[SI] ;SI←SI±2,DI←DI±2 -
串存儲 STOS
- 把AL或AX數據傳送到目的地址
STOSB ;字節串存儲:ES:[DI]←AL ;DI←DI±1 STOSW ;字串存儲:ES:[DI]←AX ;DI←DI±2 -
串讀取 LODS
- 把指定主存單元的數據傳送給AL或AX
LODSB ;字節串讀取:AL←DS:[SI] ;SI←SI±1 LODSW ;字串讀取:AX←DS:[SI] ;SI←SI±2 -
串比較 CMPS
- 將主存中的源操作數減去目的操作數,以便設置標志,進而比較兩操作數之間的關系
CMPSB ;字節串比較:DS:[SI]-ES:[DI] ;SI←SI±1,DI←DI±1 CMPSW ;字串比較:DS:[SI]-ES:[DI] ;SI←SI±2,DI←DI±2 -
串掃描 SCAS
- 將AL/AX減去目的操作數,以便設置標志,進而比較AL/AX與操作數之間的關系
SCASB ;字節串掃描:AL-ES:[DI] ;DI←DI±1 SCASW ;字串掃描:AX-ES:[DI] ;DI←DI±2 -
REP 重復前綴
- 每執行一次串指令,CX減1,直到CX=0,重復執行結束
- REP前綴可以理解為:當數據串沒有結束(CX≠0),則繼續傳送
-
REPZ 重復前綴
- 每執行一次串指令,CX減1,并判斷ZF是否為0,只要CX=0或ZF=0,重復執行結束
- REPZ/REPE前綴可以理解為:當數據串沒有結束(CX≠0),并且串相等(ZF=1),則繼續比較
-
REPNZ 重復前綴
- 每執行一次串指令,CX減1,并判斷ZF是否為1,只要CX=0或ZF=1,重復執行結束
- REPNZ/REPNE前綴可以理解為:當數據串沒有結束(CX≠0),并且串不相等(ZF=0),則繼續比較
4、 子程序設計
- 把功能相對獨立的程序段單獨編寫和調試,作為一個相對獨立的模塊供程序使用,就形成子程序
- 子程序可以實現源程序的模塊化,可簡化源程序結構,可以提高編程效率
1、過程定義位指令
過程名 proc [near|far]...
過程名 endp
-
過程名(子程序名)為符合語法的標識符
NEAR屬性(段內近調用) 的過程只能被相同代碼段的其他程序調用 FAR屬性(段間遠調用) 的過程可以被相同或不同代碼段的程序調用 -
對簡化段定義格式,在微型、小型和緊湊存儲模型下,過程的缺省屬性為near;
-
在中型、大型和巨型存儲模型下,過程的缺省屬性為far
-
對完整段定義格式,過程的缺省屬性為near
-
用戶可以在過程定義時用near或far改變缺省屬性
-
通用格式:
具有多個出口的子程序:
2、子程序的參數傳遞
入口參數(輸入參數):主程序提供給子程序
出口參數(輸出參數):子程序返回給主程序
參數的形式: ① 數據本身(傳值)
**② 數據的地址(傳址)**
傳遞的方法: ① 寄存器 ② 變量 ③ 堆棧
例題:
-
用寄存器傳遞參數
把參數存于約定的寄存器中,可以傳值,也可以傳址。
子程序對帶有出口參數的寄存器不能保護和恢復(主程序視具體情況進行保護)
子程序對帶有入口參數的寄存器可以保護,也可以不保護;但最好一致
-
入口參數:CX=元素個數,DS:BX=數組的段地址:偏移地址
出口參數:AL=校驗和
;例4.16主程序 .startup ;設置入口參數(含有DS<-數組的段地址) mov bx,offset array ;BX<-數組的偏移地址 mov CX,count ;cx<-數組的元素個數 call checksuma ;調用求和過程mov result,al ;處理出口參數.exit 0 ;例4.16子程序 checksuma procxor al,al ;累加器清0 suma: add al,[bx] ;求和inc bx ;指向下一字節loop sumaret checksuma endpend
-
2.用變量傳遞參數
主程序和子程序直接采用同一個變量名共享同一個變量,實現參數的傳遞
不通模塊間共享時,需要聲明
-
入口參數:count=元素個數,array=數組名(段地址:偏移地址)
出口參數:result=校驗和
;例4.16;主程序call checksumb;子程序 checksumb proc push ax push bx push cx xor al,al ;累加器清0 mov bx offset array ;bx<-數組的偏移地址mov cx,count ;cx<-數組的元素個數 sumb: add al,[bx] ;求和inc bxloop sumbmov result,al ;保存校驗和pop cxpop bxpop axret checksumb endp
-
用堆棧傳遞參數
主程序將子程序的入口參數壓入堆棧,子程序從堆棧中取出參數
子程序將出口參數壓入堆棧,主程序彈出堆棧取得它們
-
入口參數:順序壓入偏移地址和元素個數
出口參數:AL=校驗和
;例4.16主程序.startup mov ax,offset array ;偏移地址push ax mov ax,count ;元素個數push ax call checksumc add sp,4 mov result,al .exit 0 ;例4.16子程序 checksumc proc push bp mov bp,sp ;利用BP間接尋址存取參數push bx push cx mov bx,[bp+6] ;SS:[BP+6]指向偏移地址mov cx,[bp+4] ;SS:[BP+4]指向元素個數xor al,al sumc: add al,[bx] inc bx loop sumc pop cx pop bx pop bp ret checksumc endp -
3、子程序的嵌套
子程序內包含有子程序的b調用就是子程序嵌套,沒有什么特殊要求
4、子程序的遞歸
- 當子程序直接或間接地嵌套調用自身時稱為遞歸調用,含有遞歸調用的子程序稱為遞歸子程序
- 遞歸子程序必須采用寄存器或堆棧傳遞參數,遞歸深度受堆棧空間的限制
5、子程序的重入
- 子程序的重入是指子程序被中斷后又被中斷服務程序所調用,能夠重入的子程序稱為可重入子程序。在子程序中,注意利用寄存器和堆棧傳遞參數和存放臨時數據,而不要使用固定的存儲單元(變量),就能夠實現重入。
- 子程序的重入不同于子程序的遞歸。重入是被動地進入,而遞歸是主動地進入;重入的調用間往往沒有關系,而遞歸的調用間卻是密切相關的。遞歸子程序也是可重入子程序
第五章 高級匯編語言程序設計
1、高級語言特性
MASM 6.0 引入高級語言的程序設計特性
-
條件控制偽指令
.IF .ELSE .ENDIF
-
循環控制偽指令
.WHILE .ENDW .REPEAT .UNTIL
-
過程聲明和過程調用偽指令
.PROTO .INVOKE
1、條件控制偽指令
.IF .ELSE .ENDIF
類似高級語言中IF、THEN、ELSE、ENDIF的相應功能
在匯編時要展開,自動生成相應的比較和條件轉移指令序列,實現程序分支
常見的操作符
| 操作符 | 功能 | 操作符 | 功能 | 操作符 | 功能 |
|---|---|---|---|---|---|
| == | 等于 | && | 邏輯與 | CARRY? | CF=1? |
| != | 不等于 | || | 邏輯或 | OVERFLOW? | OF=1? |
| > | 大于 | ! | 邏輯非 | PARITY? | PF=1? |
| >= | 大于等于 | & | 位測試 | SIGN? | SF=1? |
| < | 小于 | () | 改變優先級 | ZERO? | ZF=1? |
| <= | 小于等于 |
;單分支結構
.IF AX < 0neg ax
.ENDIF
mov result,ax;雙分支結構
.IF ax==5mov bx,axmov ax,0
.ELSEdec ax
.ENDIF
2、循環控制偽指令
;求1~100之和
xor ax, ax
mov cx,100
.while cx!=0add ax,cxdec cx
.endw
mov sum,ax
;求1~100之和
xor ax, ax
mov cx,100
.repeatadd ax,cxdec cx
.until cx==0
mov sum,ax
3、過程聲明和過程調用偽指令
過程定義位指令PROC
要調用帶參數過程定義的過程,不應該用CALL指令,因為比較煩瑣
應該采用過程調用
INVOKE指令使用
INVOKE偽指令的前提是需要用PROTO偽指令對過程進行聲明
-
過程聲明偽指令:用于事先聲明過程的結構
PROTO 調用距離 語言類型, 參數:類型 -
過程調用偽指令:
INVOKE 過程名,參數,...
示例:
2、宏結構程序設計
宏(Macro)是匯編語言的一個特點,它是與子程序類似又獨具特色的另一種簡化源程序的方法
宏匯編、重復匯編、條件匯編——統稱為
宏結構
1、宏匯編
a. 宏
具有宏名的一段匯編語句序列(宏定義時書寫)
b. 宏指令
匯編語句的縮寫(宏調用時書寫)
c. 宏展開
宏指令用這段宏代替的過程(宏匯編時實現)
宏的參數
宏的參數功能強大,頗具特色
配合宏,還有宏操作符和有關偽指令
宏操作符
與宏有關的偽指令
宏匯編與子程序的比較
**<img src="https://zsr204.oss-cn-beijing.aliyuncs.com/imgs/20200709170741.png" alt="image-20200709170741619" style="zoom:50%;" />**
2、重復匯編
-
重復匯編指在匯編過程中,重復展開一段(基本)相同的語句 -
重復匯編沒有名字,不能被調用
-
重復匯編常用在宏定義體中,也可以在一般匯編語句中使用
-
重復匯編偽指令有三個:
REPEAT——按參數值重復FOR——按參數個數重復FORC——按參數的字符個數重復 -
最后,用ENDM結束
1. 按參數值重復
REPEAT 重復次數重復體
ENDM
2. 按參數個數重復
FOR 形參,〈實參表〉重復體
ENDM
3. 按參數字符個數重復
FORC 形參, 字符串重復體
ENDM
3、條件匯編
條件匯編偽指令在匯編過程中,根據條件決定匯編的語句
pdata macro numIF num lt 100 ;;如果num < 100,則匯編如下語句db num dup (?)ELSE ;;否則,匯編如下語句db 100 dup (?)ENDIFendm
;-----------------------------------------------------------------------------------------------
pdata 12 ;宏調用①
db 12 dup(?) ;宏匯編結果①
pdata 102 ;宏調用②
db 100 dup(?) ;宏匯編結果②
宏結構的作用
宏匯編、重復匯編和條件匯編為源程序的編寫提供了很多方便,靈活運用它們可以編寫出非常良好的源程序來- 匯編系統中有些以圓點起始的偽指令(如.startup、.exit等)實際上是一種宏結構
dstring MACRO string ;;定義字符串db '&string&',0dh,0ah,'$'ENDM
mainbegin MACRO dsseg ;;設置數據段地址mov ax,dssegmov ds,axENDM
dispmsg MACRO messagemov dx,offset messagemov ah,09hint 21hENDM
mainend MACRO retnum ;;返回DOS,可不帶參數ifb <retnum>mov ah,4ch ;;沒有參數elsemov ax,4c00h+(retnum AND 0ffh);; 有參數endifint 21hENDM;----------------------------------------------------------.model small.stack 256.datamsg1 equ this bytedstring <Hello,Everybody !!>msg2 equ this bytedstring <You see,I made it.>.codestart: mainbegin @data ;建立DS內容dispmsg msg1 ;顯示msg1字符串dispmsg msg2 ;顯示msg2字符串mainend ;返回DOSend start
3、模塊化程序設計
將
程序分段、采用子程序或者宏結構都是進行模塊化程序設計
1. 源程序文件的包含
2. 目標代碼文件的連接
-
把常用子程序寫成獨立的源程序文件,單獨匯編,形成子程序的
目標文件.OBJ -
主程序也經過獨立匯編之后形成
目標文件 -
連接程序將所有
目標文件連接起來,最終產生可執行文件
需要遵循的原則:
**① 聲明共用的變量、過程等**
**② 實現正確的段組合**
**③ 處理好參數傳遞問題**
3. 子程序庫的調入
把常用子程序寫成獨立的源文件,單獨匯編形成OBJ 文件后,存入
子程序庫主程序也單獨匯編形成OBJ文件
主程序連接時,調入子程序庫中的
子程序模塊,產生最終的可執行文件
例題:
;Lt512c.asm
... ;宏定義
.code
extern ALdisp:near,sorting:near,input:near ;聲明其他模塊中的子程序
.startup
...
.exit 0
end
;sub512c1.asm.model small.codepublic aldisp
Aldisp proc...
Aldisp endpend
;sub512c2.asm.model small.codepublic sorting
sorting proc...
sorting endpend
;sub512c3.asm.model small.codepublic input
input proc...
input endpend
例題:
4、輸入輸出程序設計
1、 輸入輸出指令
8086通過輸入輸出指令與外設進行數據交換,呈現給我們的外設是端口(I/O地址)
8086用于尋址外設端口的地址線為16條,端口最多為216=65536(64K)個,端口號為0000H~FFFFH
每個端口用于傳送一個字節的外設數據
輸入輸出的尋址方式有兩種:
1、直接尋址:只用于尋址00H~FFH前256個端口,操作數i8表示端口號
2、間接尋址:可用于尋址全部64K個端口,DX寄存器的值就是端口號
- 大于FFH的端口只能采用間接尋址方式
a. 輸入指令IN
將外設數據傳送給CPU內的AL/AX
| IN AL,i8 | ;字節輸入:AL←I/O端口(i8直接尋址) |
|---|---|
| IN AL,DX | ;字節輸入:AL←I/O端口(DX間接尋址) |
| IN AX,i8 | ;字輸入:AX←I/O端口(i8直接尋址) |
| IN AX,DX | ;字輸入:AX←I/O端口(DX間接尋址) |
b. 輸出指令OUT
將CPU內的AL/AX數據傳送給外設
| OUT i8,AL | ;字節輸出:I/O端口←AL(i8直接尋址) |
|---|---|
| OUT DX,AL | ;字節輸出:I/O端口←AL(DX間接尋址) |
| OUT i8,AX | ;字輸出:I/O端口←AX(i8直接尋址) |
| OUT DX,AX | ;字輸出:I/O端口←AX(DX間接尋址) |
2、程序直接控制輸入輸出
3、程序查詢輸入輸出
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-0sT9y2qx-1598619859404)(https://zsr204.oss-cn-beijing.aliyuncs.com/imgs/20200709194057.png)]
4、中斷服務程序
需要交換數據的外設,采用中斷請求向處理器提出要求
處理器執行事先設計好的中斷服務程序,在中斷服務程序當中實現數據交換
8086可以處理256種中斷,分為內部、外部兩種類型
外部可屏蔽中斷用于與外 設進行數據交換
內部中斷服務程序
駐留中斷服務程序
外部可屏蔽中斷服務程序
總結
以上是生活随笔為你收集整理的8086汇编语言精华笔记总结~的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你想了解的Cookie和Session就
- 下一篇: 2020了,还要学JSP嘛?入个门呗!毕