匯編語言程序以段為單位進(jìn)行書寫,一般把數(shù)據(jù)定義在數(shù)據(jù)段里,程序?qū)懺诖a段中。下面給出段的定義語法:
段名 SEGMENT
...(段的內(nèi)容)...
段名 ENDS
注意事項:
匯編語言不區(qū)分字母的大小寫;
匯編語言中一行只能有一條語句;
段的名字用字母或下劃線開頭,需要做到含義清晰且不能與保留字重名;
匯編語言中用英文分號后的內(nèi)容表示程序注釋;
不能在一個段的內(nèi)部定義另一個段,也就是各個段之間相互獨立。
數(shù)據(jù)的定義是指對給出的數(shù)據(jù)分配存儲單元,并將它們以標(biāo)準(zhǔn)的格式存放到數(shù)據(jù)段中。數(shù)據(jù)定義的語句元素包括DB DW DD DQ DT等。
給出下面的匯編程序段
DATA SEGMENT
X DB -1,255,'A',3+2,?
DB "ABC",0FFH,11001010B
Y DB 3 DUP(?)
DATA ENDS
下面對上面的代碼段進(jìn)行解釋:
變量的定義:X和Y稱為變量名,表示程序員定義了兩個變量X和Y。與高級語言不同,匯編語言中的變量實際上是后面第一個數(shù)據(jù)的地址,變量名代表了后面的若干個數(shù)據(jù);
字節(jié)數(shù)據(jù)的定義:DB表示定義的數(shù)據(jù)類型都是字節(jié)類型。DB可以用于定義整數(shù)(包括正數(shù)和負(fù)數(shù),可以使用十進(jìn)制、十六進(jìn)制或二進(jìn)制)以及字符;
求值表達(dá)式:定義數(shù)據(jù)時可以出現(xiàn)簡單的求值表達(dá)式的結(jié)果。如上方的DB 3+2相當(dāng)于 DB 5;
未知值的定義:用問號表示一個暫時還不確定的值,一般先用0進(jìn)行這個單元的填充;
多個字符的定義:可以出現(xiàn)用雙引號括起來的多個字符,這些字符將分開并按照順序進(jìn)行存儲;
重復(fù)定義相同數(shù)據(jù):DUP表示重復(fù)定義多個相同的數(shù)據(jù)。語法如下;
隔行定義:如果數(shù)據(jù)太多一行寫不下,則可以另起一行繼續(xù)定義。不需要重新寫變量名,但是需要重新寫DB偽指令。
字?jǐn)?shù)據(jù)的位數(shù)為16位,只需要將上面字節(jié)定義的語法中的DB修改為DW即可。
雙字?jǐn)?shù)據(jù)為32字節(jié),只需要將上面字節(jié)定義的語法中的DB修改為DD即可。需要注意的是,數(shù)據(jù)的高位存放在地址較大的單元里,數(shù)據(jù)的低位存放在地址較小的單元里。
只需要將DB偽指令修改為DQ和DT即可。
指令語句是指與一條機器指令相對應(yīng)的代碼語句,其一般格式如下:
[標(biāo)號:] 操作碼 [操作數(shù)] [;注釋]
語法解釋:
標(biāo)號是指程序員為這一條指令語句所起的名字。大多數(shù)指令語句都不需要標(biāo)號,只有一些特殊的指令語句需要用到;
操作碼指定本條指令的操作類型,所有的操作碼都是保留字;
操作數(shù)可以是0-3個,有多個操作數(shù)時彼此之間用逗號分隔。右邊的操作數(shù)為源操作數(shù),最左邊的操作數(shù)為目的操作數(shù)。
操作數(shù)可以分為寄存器操作數(shù)、立即數(shù)操作數(shù)和存儲器操作數(shù)三類。關(guān)于寄存器操作數(shù),需要注意的是寄存器IP和FLAGS不能作為操作數(shù)出現(xiàn)在指令中;關(guān)于立即數(shù)操作數(shù),需要注意的是立即數(shù)操作數(shù)不能用作目的操作數(shù)。下面著重介紹存儲器操作數(shù),先介紹兩點基礎(chǔ)知識:
存儲器操作數(shù)表示對一個存儲器單元進(jìn)行訪問,需要給出這個存儲單元的段基址和偏移地址兩部分才能進(jìn)行;
大多數(shù)情況下,指令將自動使用DS寄存器中的內(nèi)容作為操作數(shù)的段基址,因此,編寫匯編語言源程序時首先要做的事情就是把數(shù)據(jù)段的段基址放入DS寄存器。;
既然我們已經(jīng)設(shè)置好了段基址,那么只需要有偏移地址即可找到內(nèi)存中正確的存儲單元。給出偏移地址的方法有直接和間接兩種方法。直接法是指直接在指令中寫出存儲單元的偏移地址,間接法則是把存儲單元的偏移地址事先裝入一個寄存器中,需要時通過這個寄存器中的值來找到這個存儲單元。
(1)直接法語法:
MOV 目的寄存器, 變量名[+字節(jié)偏移量]
此語句的作用是以DS寄存器中的內(nèi)容作為段基址,以數(shù)據(jù)段中指定變量名的偏移量(與字節(jié)偏移量)的和作為偏移地址,將指定存儲單元中的值放入目的寄存器中。
(2)間接法語法:
MOV 間接尋址寄存器, OFFSET 變量名
(下面是需要使用偏移地址時的語句)
MOV 目的寄存器, 間接尋址寄存器
語法解釋:
OFFSET是保留字,表示取出后面變量的偏移地址;
間接尋址寄存器只能是BX BP SI DI中的一個。如果沒有另外說明,那么使用BX、SI和DI時自動以DS中的內(nèi)容作為段基址,使用BP時自動使用SS的值作為段基址。
程序段的一般格式如下:
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START: MOV AX, DATA
MOV DS, AX
...(其他指令部分)...
MOV AX, 4C00H
INT 21H
CODE ENDS
END START
語法解讀:
程序開始的兩條指令都是用于裝載數(shù)據(jù)段寄存器DS的。進(jìn)入程序后,代碼段寄存器CS中的值已經(jīng)由操作系統(tǒng)自動設(shè)置為代碼段的段基址,數(shù)據(jù)段的段基址則需要程序員手動裝入DS中;
ASSUME偽指令用于指定每一個數(shù)據(jù)段所對應(yīng)的段基址寄存器。如上面的代碼中CODE段的段基址寄存器為CS,DATA段的段基址寄存器為DS;
INT 21H表示調(diào)用由操作系統(tǒng)提供的21H號服務(wù)程序。服務(wù)的種類由AH中的功能號決定,本例中4CH表示返回操作系統(tǒng)的操作;AL中的代碼稱為返回代碼,用返回代碼00H表示正常返回;
END偽指令標(biāo)志整個程序的結(jié)束。END語句下面書寫的任何代碼都不會被匯編。END后的標(biāo)號表示程序的入口地址,也就是匯編程序開始執(zhí)行的地方。
基本傳送指令是使用最頻繁的指令,需要熟練掌握。格式如下:
MOV 目的操作數(shù), 源操作數(shù)
語法解釋:
源操作數(shù)和目的操作數(shù)的類型必須相同。如果不相同只有使用強制類型轉(zhuǎn)換后才能進(jìn)行傳送。強制類型轉(zhuǎn)換語法可以見下方;
源操作數(shù)和目的操作數(shù)不能同時是存儲器操作數(shù),也不能同時是段寄存器;
目的操作數(shù)不能是立即數(shù);
代碼段基址寄存器CS不能作目的操作數(shù);
使用立即數(shù)作為源操作數(shù)時,立即數(shù)會按照目的操作數(shù)的類型進(jìn)行擴展。
強制類型轉(zhuǎn)換語法(要謹(jǐn)慎使用):
數(shù)據(jù)類型 PTR[變量名]
堆棧也是用戶使用的存儲器的一部分,用于存放臨時性的數(shù)據(jù)和一些其他信息。堆棧段的定義語法如下:
堆棧名 SEGMENT STACK
(堆棧內(nèi)容)
堆棧名 ENDS
語法解釋:
堆棧定義和一般段的定義的唯一區(qū)別在于使用了STACK;
對于堆棧段,系統(tǒng)會在裝入程序時自動把SSEG的段基址放入SS寄存器中,堆棧中的字節(jié)數(shù)自動置入SP寄存器中;
堆棧段中的內(nèi)容從較大的地址開始分配和使用;
對于8086CPU,進(jìn)出堆棧的只能是2字節(jié)的數(shù)據(jù)。
常用的堆棧相關(guān)指令包括PUSH POP PUSHF和POPF,語法如下:
PUSH 源操作數(shù) ;將指定操作數(shù)入棧保護(hù)
POP 目的操作數(shù) ;將棧頂操作數(shù)恢復(fù)到指定位置
PUSHF ;標(biāo)志寄存器內(nèi)容入棧保護(hù)
POPF ;標(biāo)志寄存器出棧恢復(fù)
符號定義相當(dāng)于C語言中的#define編譯預(yù)處理,用于進(jìn)行符號的等價替換,符號定義的語法如下所示:
符號名 EQU 表達(dá)式
語法解釋:
在進(jìn)行匯編時,對EQU定義的符號名用對應(yīng)的表達(dá)式進(jìn)行等價替換;
對用EQU定義的符號名不允許重復(fù)定義。
另一種進(jìn)行符號定義的方式是使用“=”符號,具體語法如下:
符號名 = 常數(shù)表達(dá)式
語法解釋:
使用等號定義符號時只能使用常量表達(dá)式。
可以使用SEG來取地址表達(dá)式所在段的段基址,具體使用方法為:
SEG 地址表達(dá)式
對于兩個操作數(shù)相加應(yīng)該使用ADD指令,指令語法如下:
ADD 目的操作數(shù), 源操作數(shù)
語法解釋:
該指令將目的操作數(shù)與源操作數(shù)相加,結(jié)果存放在目的操作數(shù)原先的存放位置;
ADD指令執(zhí)行后會刷新CPU的狀態(tài)標(biāo)志位。
除此之外,還有一條INC指令實現(xiàn)操作數(shù)的自增,語法如下:
INC 操作數(shù)
語法解釋:
增量執(zhí)行執(zhí)行后不影響CPU的狀態(tài)標(biāo)志位;
增量指令常常用于修改計數(shù)器以及存儲器指針的值。
減法指令和加法指令的使用是對稱的。加法中的ADD對應(yīng)減法中的SUB;加法中的INC對應(yīng)減法中的DEC。
乘法指令為MUL,除法指令為DIV,使用方法和加減法類似。由于乘除法使用較少,因此不過多介紹。
循環(huán)指令的語法如下:
LOOP 標(biāo)號
語法解釋:
循環(huán)的次數(shù)由寄存器CX中的值決定。每一次循環(huán)后CX寄存器中的值會自減1,當(dāng)CX=0時循環(huán)終止,因此CX也被稱為計數(shù)器;
裝載寄存器CX的過程應(yīng)該在循環(huán)開始之前完成;
每一次循環(huán)成功則回到標(biāo)號處的語句。
邏輯運算有AND OR XOR和NOT四種,使用語法如下:
邏輯運算操作碼 目的操作數(shù) 源操作數(shù)
使用情況:
AND指令主要用于對操作數(shù)的各位有選擇地清零;
OR指令主要用于對操作數(shù)各位有選擇地置一;
XOR指令主要用于對操作數(shù)各位有選擇地取反;
NOT指令主要用于對操作數(shù)整體取反。
所有的DOS系統(tǒng)功能調(diào)用都是通過軟中斷指令I(lǐng)NT 21H來實現(xiàn)的。INT 21H是一個具有90多個子功能的中斷服務(wù)程序。INT 21H對每一個子功能都進(jìn)行了編號,這個編程成為功能號。
DOS系統(tǒng)功能調(diào)用方法:
MOV 功能號 ;把功能號放入寄存器AH中
......
(在其他寄存器中放入該功能要求的入口參數(shù))
......
INT 21H ;調(diào)用DOS系統(tǒng)功能
常用功能:
功能號1,輸入字符以ASCII碼的形式存放在累加器AL中同時顯示出來。
MOV AH 01
INT 21H
功能號2,屏幕顯示存放在DL寄存器中的字符。
MOV AH 02
MOV DL 待顯示字符
INT 21H
功能號9,用于在顯示器上顯示一個存放在寄存器DX中的字符串,被顯示的字符串必須以’$'作為結(jié)束符。
MOV AH 09
MOV DX 待顯示字符串首地址
INT 21H
一個程序執(zhí)行完成后使得程序正常退出并返回DOS的功能,功能號為4CH。
MOV AH 4CH
INT 21H
子程序名 PROC
...
RET ;表示子程序返回
子程序名 ENDP ;表示子程序段定義結(jié)束
CALL 子程序名
MOV DX 端口地址
......
(其他寄存器初始化)
......
OUT DX 需要傳輸?shù)蕉丝诘臄?shù)據(jù)所在的寄存器
使用NOP表示執(zhí)行一條空指令,不進(jìn)行任何操作。當(dāng)指令之間需要有延時時,可以插入NOP指令。
NOP
CMP指令格式如下:
CMP 目的操作數(shù),源操作數(shù)
語法解釋:
CMP用于比較兩個同類型的操作數(shù)的大小;
指令執(zhí)行的結(jié)果不會修改兩個操作數(shù),而是修改標(biāo)志位;
CMP指令常常與下列指令結(jié)合使用。
JGE 前>=后 Jump if greater or equal
JG 前>后 Jump if greater
JLE 前<=后 Jump if less or equal
JL 前<后 Jump if less
JNE 前不等于后 Jump if not equal
JE 前等于后 Jump if equal
—— EOF —— 你好,我是飛宇,本碩均于某中流985 CS就讀,先后于百度搜索、字節(jié)跳動電商以及攜程等部門擔(dān)任Linux C/C++后端研發(fā)工程師。
最近跟朋友一起開發(fā)了一個新的網(wǎng)站:編程資源網(wǎng),已經(jīng)收錄了不少資源(附贈下載地址),如果屏幕前的靚仔/女想要學(xué)習(xí)編程找不到合適資源的話,不妨來我們的網(wǎng)站看看,歡迎掃碼下方二維碼白嫖~
同時,我也是知乎博主@韓飛宇,日常分享C/C++、計算機學(xué)習(xí)經(jīng)驗、工作體會,歡迎點擊此處查看我以前的學(xué)習(xí)筆記&經(jīng)驗&分享的資源。
我組建了一些社群一起交流,群里有大牛也有小白,如果你有意可以一起進(jìn)群交流。
歡迎你添加我的微信,我拉你進(jìn)技術(shù)交流群。此外,我也會經(jīng)常在微信上分享一些計算機學(xué)習(xí)經(jīng)驗以及工作體驗,還有一些內(nèi)推機會。
加個微信,打開另一扇窗