4.1 匯編語言的格式
4.1.1 8086匯編語言程序的一個例子
- 8086匯編的一個語句行是由4個部分組成的,即:
標號 操作碼 操作數(shù) ;注釋(或名字)
4.1.2 8086匯編語言源程序的格式
- 源程序的一般格式位:
NAME1 SEGMENT
語句
語句
NAME1 ENDS
NAME2 SEGMENT
語句
語句
NAME2 ENDS
END<標號>
語句行的構成
4.2.1 標記(Token)
1.IBM宏匯編的字符集
(1)字母
- 包含大寫的英文字母
- 小寫的英文字母
(2)數(shù)字 - 阿拉伯數(shù)字
(3)特殊字符 -
IBM中宏匯編字符集中可打印字符
2.界符
-
IBM宏匯編字符集中可打印字符
3.常量
(1)數(shù)字(整數(shù))常量
①二進制常量
- 字母B結(jié)尾
②十進制常量 - 字母D結(jié)尾
③八進制常量 - 以字母Q結(jié)尾
④十六進制 - 以字母H結(jié)尾
(2)字符串常量
- 字符串常量是由包含在單引號內(nèi)的1或2個ASCII碼構成的
4.標識符
- 標識符是由程序員自由建立起來的、有特定意義的字符序列,如例子中的SUM、CYCLE酸些、PORT_VAL等
- 一個標識符是由最多31個字母、數(shù)字及規(guī)定的特殊字符(?@_$)等組成的,且不能用數(shù)字打頭(以免與十六進制數(shù)向混淆)
5.保留字
- 保留字看上去像標識符承匣,但是它們在語言中有特殊的意義,而且不能用它們作為標識符
IBM宏匯編中的保留字
6.注釋
- 為了使匯編語言的源程序更便于閱讀和理解锤悄,常在源程序中加上注釋
- 注釋是在分號(;)后面的任意的字符序列韧骗,知道行的結(jié)尾
- 在匯編時,匯編程序?qū)λ鼈儾⒉贿M行處理
- 可打印的文件中零聚,注釋和源程序一起打印
4.2.2 符號(Symbol)
1. 寄存器
2.變量
- 所有變量都有三種屬性:
(1)段值(SEGMENT)袍暴,即變量單元所在段的段地址(段的起始地址)的高16位,低4位始終為0
(2)偏移量(OFFSET)隶症,即變量單元地址與段的起始地址之間的偏移量(16位)
(3)類型(TYPE)政模,變量有三種類型:字節(jié)(Byte)、字(word)和雙字(Double Word)
3.標號(Label)
- 標號是某條指令所存放單元的符號地址蚂会,它是轉(zhuǎn)移(條件轉(zhuǎn)移或無條件轉(zhuǎn)移)指令或調(diào)用(CALL)指令的目標操作數(shù)
- 標號的類型與變量不同览徒,它的類型是NEAR或是FAR
4.數(shù)
- 匯編源程序中的常數(shù)也常以符號的形式出現(xiàn)
5.其他符號
4.2.3 表達式(Expressions)
1.操作數(shù)(Operands)
- 一個操作數(shù)或者一個寄存器名,或是一個常量(數(shù)字常量或字符串常量)颂龙,或是一個存儲器操作數(shù)
(1)常量操作數(shù)
- 具有數(shù)字值的操作數(shù)是常量或是表示常量的標識符(符號)
- 例中的常量操作數(shù)是100习蓬、PORT_VAL
- 常量操作數(shù)的值允許范圍是從-65535 ~ +65535
(2)存儲器操作數(shù)
- 存儲器操作數(shù),通常是標識符
- 具體地說措嵌,可以分為標號(Label)和變量(Variable)兩種
變量可以具有以下幾種尋址方式:
①直接尋址
②基址尋址
③變址(索引)尋址
④基址變址尋址
2.運算符(Operators)
(1)算術運算符(Arithmetic Operators)
- 一個是加(+)減躲叼、乘、除運算發(fā)
- 另一個算術運算符是MOD
因此對例子中地存儲其地址作如下運算:
SUM+2
CYCLE-5
NOT_DONE-GO
是有效地表達式企巢。而
SUM-CYCLE
(2)邏輯運算符
- 邏輯運算符是按位操作地AND枫慷、OR、XOR和NOT
(3)關系運算符 - 在IBM宏匯編中有以下關系運算符
①相等Equal(EQ)
②不等Not Equal(NE)
③小于Less Than(LT)
④大于Greater Than(GT)
⑤小于或等于Less Than or Equal(LE)
⑥大于或等于Greater Than or Equal(GE)
MOV BX ,PORT_VAL LT 5
若PORT_VAL地值小于5浪规,關系為真或听,則會變程序在匯編后產(chǎn)生地語句為:
MOV BX ,OFFFFH
若PORT_VAL的值不小于5,則關系為假笋婿,匯編后產(chǎn)生的語句為:
MOV BX,0
(4)分析運算符
- 把存儲器操作數(shù)分解為它的組成部分誉裆,如它的段值、段內(nèi)偏移量和類型
(5)合成運算符 - 由已存在的存儲器操作數(shù)生成一個段值和偏移量相同而類型不同的新的存儲器操作數(shù)
4.2.4 語句(Statements)
一個匯編語言的源程序是由一條條語句組成的缸濒,語句就是對需要計算機完成的動作的說明
源程序中的語句可分為兩類:指令語句和指示性語句
指令語句足丢,匯編程序把它們翻譯成機器代碼粱腻,這些代碼命令8086執(zhí)行某些操作。如MOV斩跌、ADD绍些、JMP等
對于指示性語句(偽指令),匯編程序并不把它們翻譯成機器代碼耀鸦,實際上也不可能翻譯成機器代碼柬批,只是用來指示、引導匯編程序在匯編時做一些操作袖订,如定義符號氮帐、分配存儲單元、初始化存儲器等著角,所以偽指令本身不占用存儲單元
例如:
MY_PLACE DB ?
指令語句的格式:
標號:助記符 參數(shù)揪漩,...,參數(shù) ;注釋
指示性語句的格式為:
名字 命令 參數(shù)吏口,...奄容,參數(shù) ;注釋
4.3 指示性語句
4.3.1 符號定義語句
1.等值語句EQU
NAME EQU EXPRESSION
- EQU語句給符號定義一個值,或定義為別的符號名产徊,甚至可定義為一條可執(zhí)行的指令等
-
一些例子如下:
2.等號(Equal Sign) =語句
- 能對符號進行再定義
EMP = 6
EMP = 7
EMP = EMP + 1
3.解除語句PURGE
PURGE 符號1昂勒,符號2,...舟铜,符號n
-
已經(jīng)用EQU命令定義的符號戈盈,若以后不再用了,就可以用PURGE語句接觸
例如:
4.3.2 數(shù)據(jù)定義語句
數(shù)據(jù)定義語句谆刨,為一個數(shù)據(jù)項分配存儲單元塘娶,用一個符號名與這個存儲單元相聯(lián)系,且為這個數(shù)據(jù)提供一個人選的初始值
與該項相聯(lián)系的符號名稱為變量
-
例子:
例如:THING DB 25
不僅使THING這個符號與一個字節(jié)的存儲單元相聯(lián)系痊夭,而且在匯編時會把25放入THING相聯(lián)系的存儲單元中
所以THING是一個字節(jié)變量刁岸,它的初始值為25BIGGER_THING DW 4142H
在匯編時就會把41H與42H分別放至與BIGGER_THING相聯(lián)系的兩個連續(xù)的字節(jié)單元中(一個字中),而且42H放在地址低的字節(jié)她我,41H放在地址高的字節(jié)
所以虹曙,若BIGGER_THING是一個字變量,則它的初始值為4142H-
語句:BIGGEST_THING DD 12345678H
它定義了一個雙字變量番舆,且給了初始值
一個存儲單元的類型如下:
(1)數(shù)據(jù)字節(jié)
SUM DB ? ;定義一個字節(jié)
(2)數(shù)據(jù)字(兩個連續(xù)的字節(jié))
BIGGER DW ?; 定義一個字
(3)數(shù)據(jù)雙字(四個連續(xù)的字節(jié))
BIGGER DD ? ;定義一個雙字
(4)Near指令單元
CYCLE : CMP SUM,100
(5)Far指令單元
-
若在一個程序中酝碳,對它的數(shù)據(jù)段有如下定義:
其中的每一個存儲單元都有一些屬性(或組成成分)
分析運算符SEG,返回的是一個存儲單元的段地址(即它所在段的起始地址)OFFSET運算符返回的是每一個存儲單元地址的段內(nèi)偏移量恨狈,即它與段地址之間的偏差疏哗。故:
SEG BUFFER1
SEG BUFFER2
SEG BUFFER3
都是相同的,它們返回的地址都是DATA_TABLES的地址
所以拴事,若要對數(shù)據(jù)段寄存器初始化沃斤,則可采用指令:
MOV AX,SEG BUFFER1
MOV DS,AX
而
OFFSET BUFFER1
OFFSET BUFFER2
OFFSET BUFFER3
是各不相同的圣蝎,若要向這些緩沖區(qū)填入新的數(shù)據(jù)刃宵,可以采用一些地址指針衡瓶,則可以用以下指令來初始化地址指針:
MOV BX ,OFFSET BUFFER1
MOV SI,OFFSET BUFFER2
MOV DI,OFFSET BUFFER3
以后,就可以用這些指針來間接尋址這些緩沖區(qū)
存儲器地址操作數(shù)的類型值
4.3.3 段定義語句
段定義的主要命令有①SEGMENT牲证,②ENDS哮针,③ASSUME,④ORG
SEGMENT和ENDS語句把匯編語言源程序分成段
這些段就相應于存儲器段坦袍,在這些存儲器段中十厢,存放相應段的目標碼
-
如何使用SEGMENT、ENDS和ASSUME命令捂齐,以定義代碼段蛮放、堆棧段、數(shù)據(jù)段和附加段
image.png
(1)不要搭接奠宜,段中的第一個可用字節(jié)是在16字節(jié)界限上
MY_SEG SEGMENT
.
.
.
MY_SEG ENDS
這是一種正常情況
(2)允許搭接包颁,但第一個可用字節(jié)必須在字的界限上
MY_SEG SEGMENT WORD
.
.
.
MY_SEG ENDS
(3)段開始在指定的16個字節(jié)界值上,但第一個可用字節(jié)在指定的偏移位置上
MY_SEG SEGMENT AT 1A2BH ; 段地址為1A2BH
ORG 0003H ;段內(nèi)從偏移量0003H開始
MY_SEG ENDS
偽指令ORG的一般格式為:
ORG <表達式>
此語句指定了段內(nèi)在它以后的程序或數(shù)據(jù)塊存放的起始地址压真,也即以語句中的表達式的值作為起始地址娩嚼,連續(xù)存放,除非遇到一個新的ORG語句
4.3.4 過程定義語句
過程定義語句的格式:
PROCEDURE_NAME PROC [NEAR]
或
PROCEDURE_NAME PROC FAR
RET
PROCEDURE _NAME ENDP
-
例子
4.3.5 結(jié)束語句
START:
END START
4.4 指令語句
4.4.1 指令助記符
1.NOP(No Operation)
- 使匯編產(chǎn)生一字節(jié)指令滴肿,使寄存器AX的內(nèi)容自行交換
2.保留空格(Place Holder)
- NIL是使匯編程序不產(chǎn)生任何指令的唯一的指令助記符
4.4.2 指令前綴
- IBM宏匯編中允許作為前綴的助記符:
LOCK
REP(Repeat)
REPE (當相等時重復)
REPNE (當不相等時重復)
REPZ (當標志ZF=1時重復)
PEPNZ (當標志ZF=0時重復)
具有前綴的指令語句例子
CYCLE: LOCK DEC COUNT
4.4.3 操作數(shù)尋址方式
1.立即
MOV AX,15 ;15是一個立即數(shù)
2.寄存器
MOV AX,15 ;15是一個寄存器操作數(shù)
3.直接
SUM DB ?
MOV SUM,15 ;SUM是一個直接存儲操作數(shù)
4.通過基址寄存器間接
MOV AX,[BX]
MOV AX,[BP]
5.通過變址寄存器間接
MOV AX,[SI]
MOV AX,[DI]
6.通過基址寄存器加變址寄存器間接
MOV AX,[BX][SI]
MOV AX,[BX][DI]
MOV AX,[BP][SI]
MOV AX,[BP][DI]
7.通過基址或變址寄存器加位移量間接
MANY_BYTES DB 100 DUP (?)
.
.
.
MOV AX,MANY_BYTES[BX]
MOV AX,MANY_BYTES[BP]
MOV AX,MANY_BYTES[SI]
MOV AX,MANY_BYTES[DI]
8.通過基址寄存器加變址寄存器加位移量間接存儲器
MANY_BYTES DB 100 DUP (?)
.
.
.
MOV AX,MANY_BYTES[BX][SI]
MOV AX,MANY_BYTES[BX][DI]
MOV AX,MANY_BYTES[BP][SI]
MOV AX,MANY_BYTES[BP][DI]
4.4.4 串操作指令
ALPHA DB ?
BETA DB ?
MOV SI,OFFSET ALPHA
MOV DI,OFFSET BETA
MOV BETA,ALPHA
- 一個完整的匯編語言源程序應該由可執(zhí)行命令組成的指令性語句和由對符號定義岳悟、分配存儲單元、分段等組成的指示性語句構成的泼差。而且贵少,一個完整的程序至少應該包含三種段:由源程序組成的代碼段。堆棧操作所需要的堆棧段和存放數(shù)據(jù)的數(shù)據(jù)段
該例子是把兩個分別由未組合的BCD碼(一個字節(jié)為一位BCD數(shù))的串相加堆缘;由于8086中允許兩個未組合的十進制數(shù)相加滔灶,只要經(jīng)過適當?shù)恼{(diào)整就可以得到正確的結(jié)果。所以套啤,在程序中把第一個串的一位BCD數(shù)取至AL中宽气,與第二個串的相應位相加,經(jīng)過AAA調(diào)整潜沦,再把結(jié)果存至存儲器中萄涯。程序中的前面部分是為了設置段,先設置數(shù)據(jù)段唆鸡,用DB偽指令定義兩個數(shù)據(jù)串涝影,用COUNT表示數(shù)據(jù)的長度。接著是定義堆棧段争占,為堆棧留下了100個單元的空間(實際上當然由需要來定)燃逻,然后是當以代碼段序目,從標號GO開始就是可執(zhí)行指令部分。
4.5 匯編語言程序設計及舉例
4.5.1 算術運算程序設計(直線運行程序)
- 例 兩個32位無符號數(shù)乘法程序
4.5.2 分支程序設計
4.5.3 循環(huán)程序設計
1.用計數(shù)器控制循環(huán)
例題:在一串給定個數(shù)的數(shù)中尋找最大值(或最小值)伯襟,放至指定的存儲單元猿涨。每個數(shù)用16位表示
2.多重循環(huán)
4.5.4 字符串處理程序
1.確定字符串的長度
例題:從頭搜索字符串的結(jié)束標志,統(tǒng)計搜索的字符個數(shù)
2.加偶校驗到ASCII字符
- 例題:若有一個ASCII字符串姆怪,它的起始地址放在單元STRING內(nèi)叛赚,要求從串中取出每一個字符,檢查其中包含的“1”的個數(shù)稽揭,若已為偶數(shù)俺附,則它的最高有效位置“0”;否則溪掀,最高有數(shù)位置“1”事镣,然后送回
4.5.5 碼轉(zhuǎn)換程序設計
1.十六進制到ASCII的轉(zhuǎn)換
例4-5 若有一個二進制數(shù)碼串,要把每一個字節(jié)中的二進制轉(zhuǎn)換位兩位十六進制數(shù)的ASCII揪胃,高4位的ASCII放在第hi高的單元璃哟。串中的第一個字節(jié)為串的長度(小于128)
2.從二進制到ASCII串的轉(zhuǎn)換
- 例4-6 把在內(nèi)存變量NUMBER中的16位二進制數(shù),每一位轉(zhuǎn)換為相應的ASCII只嚣,存入串變量STRING中
4.5.6 有關I/O的DOS功能調(diào)用
1.在CRT上連續(xù)輸出0 ~ 9
4.5.7 宏匯編與條件匯編
1.宏命令的用途
(1)在匯編語言的源程序中沮稚,若有的程序段要多次使用,為了使在源程序中不重復書寫這個程序段册舞,可以一條宏指令來代替蕴掏。由宏匯編程序在匯編時產(chǎn)生所需要的代碼
MOV CL,4
SAL AL,CL
若要多次使用,就可以用一條宏指令代替:
SHFT MACRO
MOV CL,4
SAL AL,CL
ENDM
(2)宏定義不但能使源程序書寫簡潔调鲸,而且由于宏指令具有接受參量的能力盛杰,所以功能就更靈活
SHFT MACRO X,Y
MOV CL,X
SAL Y,CL
ENDM
(3)形式參量不只可以出現(xiàn)在操作數(shù)部分,也可以出現(xiàn)在操作碼部分藐石。如:
SHFT MACRO X,Y,Z
MOV CL,X
S&Z Y,CL
ENDM
若有以下調(diào)用:
SHFT 4,AL,AL
SHIFT 6,BX,AR
SHIFT 8,SI,HR
在匯編時即供,分別產(chǎn)生以下指令的目標代碼
MOV CL,4
SAL AL,CL
MOV CL,6
SAR CL,6
SAR BX,CL
MOV CL,8
SHR SI,CL
2.IBM宏匯編中主要宏操作偽指令
(1)MACRO
宏定義名 MRRCO <形式參量表>
(2)PURGE
PURGE 宏定義名 [,......]
(3)LOCAL
- 例題在AL中有一位十六進制數(shù)碼要轉(zhuǎn)換為ASCII,則可以用以下宏定義:
CHANGE MACRO
CMP AL,10
JL ADD_0
ADD AL,'A'-'0'-10
ADD_0 ADD AL,'0'
ENDM
上面的CHANGE宏定義在下有多次調(diào)用的情況于微,應定義為:
CHANGE MACRO
LOCAL ADD_0
CMP AL,10
JL ADD_0
ADD AL,'A'-'0'-10
ADD_0 ADD AL,'0'
ENDM
(4)REPT
REPT <表達式>
ENDM
- 這個偽指令可以重復執(zhí)行在它的指令體部分所包含的語句逗嫡。重復執(zhí)行的次數(shù),由表達式的值所決定
例4-7 把數(shù)字0 ~ 9的ASCII填入表TABLE株依。CHAR = ‘0’
例題4-8 建立一個地址表驱证,其中每個字的內(nèi)容是下一個字的地址(用作地址指針),而最后一個字的內(nèi)容是第一個字的地址
(5)IRP
IRP 形式參量(參數(shù)表)
ENDM
(6)IRPC
IRPC 形式參量恋腕,字符串(或<字符串>)
ENDM
3.宏定義嵌套
4.宏指令與子程序的區(qū)別
(1)宏指令是為了簡化源程序的書寫抹锄,在匯編時,匯編程序處理宏指令,還把宏定義體插入到宏調(diào)用處伙单。所以获高,宏指令并沒有簡化目標程序。有多少次宏調(diào)用吻育,在目標程序中仍需要有同樣多次的目標代碼插入念秧。所以,宏指令不能節(jié)省目標程序所占的內(nèi)存單元
(2)若一個源程序中多次調(diào)用一個程序段扫沼,則可用子程序出爹,也可以用宏指令來簡化源程序庄吼。用子程序的辦法缎除,匯編后產(chǎn)生的目標代碼少,也即目標程序占用的內(nèi)存少总寻,節(jié)約了內(nèi)存空間器罐。但是,子程序在執(zhí)行時渐行,每調(diào)用一次都要先保護斷點轰坊,通常在程序中還要保護現(xiàn)場;在返回時先要恢復現(xiàn)場祟印,然后恢復斷點(返回)
這些操作都額外增加了時間肴沫,因而執(zhí)行時間長,速度慢指令恰好相反蕴忆,它的目標程序長颤芬,占用的內(nèi)存的那元多;但是執(zhí)行時不需要保護斷點套鹅,也不需要保護現(xiàn)場以及恢復站蝠、返回等這些額外的操作,因而執(zhí)行時間短卓鹿、速度快