各指令:
mov數據傳送指令指令:兩個操作數的數據類型要相同,兩個操作數不能同時爲段寄存器,代碼段寄存器CS不能爲目的操作數,但可作爲源操作數。立即數不能直接傳給段寄存器,立即數不能作爲目的操作數,指令指針IP,不能作爲MOV指令的操作數。兩個操作數不能同時爲存儲單元,就是一條指令不能兩次訪存。
符號擴展是用源操作數的符號位來填充目的操作數的高位數據位,指令movsx。零擴展是用0來填充目的操作數的高位數據位,指令movzx。
交換指令xchg交換寄存器和內存單元中的值,該寄存器不能是段寄存器。
指令lea是把一個內存變量的有效地址送給指定的寄存器。該指令通常用來對指針或變址寄存器BX、DI或SI等置初值。
入棧指令push,出棧指令pop。PUSHF/PUSHFD把16位/32位標誌寄存器進棧;POPF/POPFD把16位/32位標誌寄存器出棧。
clc:置進位標誌位cf爲0.
stc:置進位標誌位cf爲1.
進位取反指令cmc:取反cf位。
cld :置方向標誌位df爲0.
std:置方向位指令df爲1.
清中斷允許位指令cli置IF爲0,使得不允許可屏蔽的外部中斷來中斷其後程序段的執行。置中斷允許位指令sti置IF爲1,恢復可屏蔽的外部中斷的中斷響應功能。
加法指令ADD,帶進位的加法指令ADC,把源操作數和進位標誌位CF的值(0/1)一起加到目的操作數中。加一指令INC。與之對應的減法指令SUB SBB DEC,求補指令DEG。無符號乘法指令MUL,有符號乘法指令IMUL。無符號除法指令DIV , 有符號除法指令IDIV。邏輯與AND,邏輯或OR,邏輯異或XOR,邏輯非NOT。算術左移SAL,算法右移SAR,算術移位是低位補0,高位補符號位。邏輯左移SHL,邏輯右移SHR,邏輯移位是低位和高位都補0。雙精度左移SHLD,SHLD/SHRD Reg/Mem, Reg, n,在執行SHLD指令時,第一操作數向左移n位,其“空出”的低位由第二操作數的高n位來填補。循環左移ROL和循環右移ROR,它們移出的位不僅要進入CF,而且還要填補空出的位。帶進位的循環左移RCL和帶進位的循環右移RCR,它們都用原CF的值填補空出的位,移出的位再進入CF。位掃描指令BSF和BSR,位掃描指令是在第二個操作數中找第一個“1”的位置。如果找到,則該“1”的位置保存在第一操作數中,並置標誌位ZF爲1,否則,置標誌位ZF爲0,BSF是從低位向高位掃,BSR相反。檢測位指令test,把兩個操作數進行邏輯“與”操作,並根據運算結果設置相應的標誌位,但並不保存該運算結果,所以,不會改變指令中的操作數。比較指令CMP,用第二個數減去第一個數,根據結果設置各標誌位。循環指令loop,循環次數存放在CX中。指令jcxz,當CX=0時,則程序轉移標號處執行。無條件指令jmp tag。
條件跳轉指令:
無符號數條件轉移指令:
指令的助憶符 |
檢測的轉移條件 | 功能描述 |
JE/JZ |
ZF=1 | Jump Equal or Jump Zero |
JNE/JNZ |
ZF=0 | Jump Not Equal or Jump Not Zero |
JA/JNBE |
CF=0 and ZF=0 | Jump Above or Jump Not Below or Equal |
JAE/JNB |
CF=0 | Jump Above or Equal or Jump Not Below |
JB/JNAE |
CF=1 | Jump Below or Jump Not Above or Equal |
JBE/JNA |
CF=1 or AF=1 | Jump Below or Equal or Jump Not Above |
指令的助憶符 |
檢測的轉移條件 | 功能描述 |
JE/JZ |
ZF=1 | Jump Equal or Jump Zero |
JNE/JNZ |
ZF=0 | Jump Not Equal or Jump Not Zero |
JG/JNLE |
ZF=0 and SF=OF | Jump Greater or Jump Not Less or Equal |
JGE/JNL |
SF=OF | Jump Greater or Equal or Jump Not Less |
JL/JNGE |
SF≠OF | Jump Less or Jump Not Greater or Equal |
JLE/JNG |
ZF=1 or SF≠OF | Jump Less or Equal or Jump Not Greater |
指令的助憶符 |
檢測的轉移條件 | 功能描述 |
JC |
CF=1 | Jump Carry |
JNC |
CF=0 | Jump Not Carry |
JO |
OF=1 | Jump Overflow |
JNO |
OF=0 | Jump Not Overflow |
JP/JPE |
PF=1 | Jump Parity or Jump Parity Even |
JNP/JPO |
PF=0 | Jump Not Parity or Jump Parity Odd |
JS |
SF=1 | Jump Sign (negative) |
JNS |
SF=0 | Jump No Sign (positive) |
字符串操作指令是對一片連續存儲單元進行處理,這片存儲單元是由隱含指針DS:SI或ES:DI來指定的。字符串操作指令可對內存單元按字節、字或雙字進行處理,並能根據操作對象的字節數使變址寄存器SI(和DI)增減1、2或4。當DF=0時,變址寄存器SI(和DI)增加1、2或4;當DF=1時,變址寄存器SI(和DI)減少1、2或4。取字符串數據指令LODS,從由指針DS:SI所指向的內存單元開始,取一個字節、字或雙字進入AL、AX或EAX中,並根據標誌位DF對寄存器SI作相應增減。該指令的執行不影響任何標誌位。置字符串數據指令STOS,該指令是把寄存器AL、AX或EAX中的值存於以指針ES:DI所指向內存單元爲起始的一片存儲單元裏,並根據標誌位DF對寄存器DI作相應增減。該指令不影響任何標誌位。字符串傳送指令MOVS,該指令是把指針DS:SI所指向的字節、字或雙字傳送給指針ES:DI所指向內存單元,並根據標誌位DF對寄存器DI和SI作相應增減。該指令的執行不影響任何標誌位。輸入字符串指令ints,輸出字符串指令outs。字符串比較指令cmps,該指令是把指針DS:SI和ES:DI所指向字節、字或雙字的值相減,並用所得到的差來設置有關的標誌位。重複前綴指令REP根據CX值確定重複執行後面的指令多少次。條件重複前綴指令,根據CX和zf值確定是否重複和重複幾次,REPE和REPZ根據CX≠0
且 ZF=1則重複,REPNE和REPNZ根據CX≠0 且 ZF=0重複。
空指令操作NOP,等待指令WAIT,暫停指令HLT:在等待中斷信號時,該指令使CPU處於暫停工作狀態,CS:IP指向下一條待執行的指令。當產生了中斷信號,CPU把CS和IP壓棧,並轉入中斷處理程序。在中斷處理程序執行完後,中斷返回指令IRET彈出IP和CS,並喚醒CPU執行下條指令。封鎖數據指令LOCK。
彙編程序可定義多個段,數據段、棧端、多個代碼段,每段有自己的段名:name segment........name ends。通過assume僞指令每個段都要與一個段寄存器建立一種對應關係:ASSUME 段寄存器名:段名[,段寄存器名:段名, ……]。要定義堆棧段,來用壓棧和出棧對方法和數據進行操作。僞指令END寫在最後。
採用CMP和有條件跳轉指令或無條件跳轉指令配合達到if/else判斷形成分支結構程序的目的。竟然還有類C的僞指令:.IF .ELSEIF .ELSE .ENDIF可以協助進程分支程序的設計。僞指令.WHILE .REPEAT協助設計循環程序結構。還有.BREAK .CONTUNUE來進程中斷循環。
DATA1 | SEGMENT | |||
data | DW 90, 95, 54, 65, 36, 78, 66, 0, 99, 50, -1 | |||
Average | DW 0 | |||
DATA1 | ENDS | |||
CODE1 | SEGMENT | |||
ASSUME CS:CODE1, DS:DATA1 | ||||
START: | MOV | AX, DATA1 | ||
MOV | DS, AX | |||
XOR | AX, AX | |||
XOR | DX, DX | ;用(DX,AX)來保存數組元素之和 | ||
XOR | CX, CX | ;用CX來保存數組元素個數 | ||
LEA | SI, data | ;用指針SI來訪問整個數組 | ||
again: | MOV | BX, word ptr [SI] | ||
CMP | BX, 0 | |||
JL | over | |||
ADD | AX, BX | |||
ADC | DX, 0 | ;把當前數組元素之值加到(DX,AX)中 | ||
INC | CX | ;數組元素個數加1 | ||
ADD | SI, 2 | |||
JMP | again | |||
over: | JCXZ | exit | ;防止零作除數,即數組是空數組 | |
DIV | CX | |||
MOV | Average, AX | |||
exit: | MOV | AX, 4C00H | ||
INT | 21H | |||
CODE1 | ENDS | |||
END | START |
段組僞指令GROUP是用於把源程序模塊中若干個段結合成一個組,並對該段組定義一個段組名。段組僞指令的格式如下:段組名 GROUP 段名[, 段名,……]。
子程序調用指令CALL 子程序名/deg/mem。若是近調用,CALL指令將產生一個近調用,它把該指令之後地址的偏移量(用一個字來表示的)壓棧,把被調用子程序入口地址的偏移量送給指令指針寄存器IP即可實現執行程序的轉移。若是遠調用,調用指令不僅要把該指令之後地址的偏移量壓進棧,而且也要把段寄存器CS的值壓進棧。在此之後,再把被調用子程序入口地址的偏移量和段值分別送給IP和CS,這樣完成了子程序的遠調用操作。子程序返回指令RET/RETF/RETN,在近類型的子程序中,返回指令RET是近返回,其功能是把棧頂之值彈出到指令指針寄存器IP中,SP會被加2;若是遠返回,則先出棧至IP,再出棧至CS,同時SP加4。
而子程序是需要傳遞參數的,一般是寄存器傳參、內存單元存放參數和棧保存參數。寄存器傳參適用於參數少的子程序因爲寄存器本身就少。內存地址存放需要指定位置存放和取得參數。當用堆棧傳遞入口參數時,要在調用子程序前把有關參數依次壓棧,子程序從堆棧中取到入口參數;當用堆棧傳遞出口參數時,要在子程序返回前,把有關參數依次壓棧(這裏還需要做點額外操作,要保證返回地址一定在棧頂),調用程序就可以從堆棧中取到出口參數。在子程序中,保存和恢復寄存器內容的主要方法是:在子程序的開始把它所用到的寄存器壓進棧,在返回前,再把它們彈出棧。這樣編寫的好處是該子程序可以被任何其它程序來調用。在調用指令前,不需要保存寄存器,在調用指令後,也無需恢復寄存器。
子程序僞指令invoke類似於call。僞指令LOCAL來說明一個或者多個局部變量:LOCAL 變量名[數量][:數據類型],.......。僞指令PUBLIC tag1, tag2.......說明這些標識符可以爲其他模塊引用的公共標識符。僞指令EXTERN tag1:type, tag2:type......說明這些標識符已經在其他模塊中定義了。類似於C語言。
CPU區分不同的I/O設備使用I/O端口,形成端口地址空間。主要的端口地址:
端口地址 | 端口名稱 | 端口地址 | 端口名稱 |
020H~023H |
中斷屏蔽寄存器 |
378H~37FH |
並行口LPT2 |
040H~043H |
時針/計數器 |
3B0H~3BBH |
單色顯示器端口 |
060H |
鍵盤輸入端口 |
3BCH~3BFH |
並行口LPT1 |
061H |
揚聲器(0, 1位) |
3C0H~3CFH |
VGA/EGA |
200H~20FH |
遊戲控制口 |
3D0H~3DFH |
CGA |
278H~27FH |
並行口LPT3 |
3F0H~3F7H |
磁盤控制器 |
2F8H~2FFH |
串行口COM2 |
3F8H~3FFH |
串行口COM1 |
中斷分爲外部中斷和內部中斷,分爲可屏蔽中斷和不可屏蔽中斷,分爲硬件中斷和軟件中斷,由中斷控制器interupter handler控制。中斷類型以中斷類型碼指示,利用中斷向量表來指示中斷向量地址即中斷處理程序開始地址。主要中斷號:
中斷號 | 含義 | 中斷號 | 含義 |
0 | 除法出錯 | 8 | 定時器 |
1 | 單步 | 9 | 鍵盤 |
2 | 非屏蔽中斷 | A | 未用 |
3 | 斷點 | B | COM2 |
4 | 溢出 | C | COM1 |
5 | 打印屏幕 | D | 硬盤(並行口) |
6 | 未用 | E | 軟盤 |
7 | 未用 | F | 打印機 |
彙編中也有宏的概念,利用宏名來代替一段程序代碼。宏定義:
宏名 MACRO [參數]
........宏主體
宏名 ENDM
而宏的引用形式爲:宏名 [參數]。參數可以是常量、寄存器、表達式、內存地址。宏內可以引用其他宏,可以定義宏。“PURGE 宏名”表示解除宏定義。宏可以進行宏擴展。
要在C語言中嵌入彙編語言,可以asm mov ax,data,可以嵌入一組asm {........}。
難點:使用棧來存儲參數,會使得數據和地址都存在棧裏面。當用棧傳遞入口參數時要在子程序前把有關參數依次壓棧,子程序從堆棧中取得參數;;當用棧傳遞出口參數時要在子程序返回之前把有關參數依次壓棧而且要保證返回地址一定在棧頂。如果是段內調用,call指令會把IP值壓棧,子程序要用BP來訪問棧,所以子程序要先保存BP的值在棧中,再把當前SP即棧頂偏移量傳給BP,用BP來取得參數:
子程序寄存器保存後的棧
SUBPRO | PROC NEAR | |||
PUSH | BP | ;保護寄存器BP | ||
MOV | BP, SP | ;用寄存器BP來訪問堆棧,讀取參數 | ||
… | ;保護其它寄存器的指令 | |||
MOV | Paran, [BP+4] | ;保護其它寄存器的指令 | ||
… | ||||
MOV | Para1, [BP+4+2*(n-1)] | |||
… | ||||
SUBPRO | ENDP |
彙編語言代碼段:
DATA1 | SEGMENT | |||
data | DW 90, 95, 54, 65, 36, 78, 66, 0, 99, 50, -1 | |||
Average | DW 0 | |||
DATA1 | ENDS | |||
CODE1 | SEGMENT | |||
ASSUME CS:CODE1, DS:DATA1 | ||||
START: | MOV | AX, DATA1 | ||
MOV | DS, AX | |||
XOR | AX, AX | |||
XOR | DX, DX | ;用(DX,AX)來保存數組元素之和 | ||
XOR | CX, CX | ;用CX來保存數組元素個數 | ||
LEA | SI, data | ;用指針SI來訪問整個數組 | ||
again: | MOV | BX, word ptr [SI] | ||
CMP | BX, 0 | |||
JL | over | |||
ADD | AX, BX | |||
ADC | DX, 0 | ;把當前數組元素之值加到(DX,AX)中 | ||
INC | CX | ;數組元素個數加1 | ||
ADD | SI, 2 | |||
JMP | again | |||
over: | JCXZ | exit | ;防止零作除數,即數組是空數組 | |
DIV | CX | |||
MOV | Average, AX | |||
exit: | MOV | AX, 4C00H | ||
INT | 21H | |||
CODE1 | ENDS | |||
END | START |
DATA1 | SEGMENT | |||
data | DW 90, 95, 54, 65, 36, 78, 66, 0, 99, 50, -1 | |||
Average | DW 0 | |||
DATA1 | ENDS | |||
CODE1 | SEGMENT | |||
ASSUME CS:CODE1, DS:DATA1 | ||||
START: | MOV | AX, DATA1 | ||
MOV | DS, AX | |||
XOR | AX, AX | |||
XOR | DX, DX | ;用(DX,AX)來保存數組元素之和 | ||
XOR | CX, CX | ;用CX來保存數組元素個數 | ||
LEA | SI, data | ;用指針SI來訪問整個數組 | ||
again: | MOV | BX, word ptr [SI] | ||
CMP | BX, 0 | |||
JL | over | |||
ADD | AX, BX | |||
ADC | DX, 0 | ;把當前數組元素之值加到(DX,AX)中 | ||
INC | CX | ;數組元素個數加1 | ||
ADD | SI, 2 | |||
JMP | again | |||
over: | JCXZ | exit | ;防止零作除數,即數組是空數組 | |
DIV | CX | |||
MOV | Average, AX | |||
exit: | MOV | AX, 4C00H | ||
INT | 21H | |||
CODE1 | ENDS | |||
END | START |
DATA1 | SEGMENT | |||
MSG1 | DB 13, 10, "Iteration: " | |||
NUM1 | DB '1', "$" | |||
MSG2 | DB 13, 10, "Alphabet: $" | |||
NUM2 | DB 'A', " $" | |||
MSG3 | DB 13, 10, "Type digits, then press ENTER: $" | |||
DATA1 | ENDS | |||
CODE1 | SEGMENT | |||
ASSUME CS:CODE1, DS:DATA1 | ||||
START: | MOV | AX, DATA1 | ||
MOV | DS, AX | |||
MOV | CX,9 | |||
MOV | AH, 09H | |||
MOV | DX, OFFSET MSG1 | |||
.REPEAT | ||||
INT 21H INC NUM1 |
;顯示Iteration: 1,2,~,9 | |||
.UNTILCXZ | ||||
MOV | DX,OFFSET MSG2 | |||
INT | 21H | ;顯示字符串"Alphabet:" | ||
MOV | AH, 09H | |||
MOV | DX, OFFSET NUM2 | |||
.REPEAT | ||||
INT 21H INC NUM2 |
;顯示當前字母 ;當前字母向後移 |
|||
.UNTIL NUM2 > 'Z' | ;顯示整個大寫字母表 | |||
MOV | AH, 09H | |||
MOV | DX, OFFSET MSG3 | |||
INT | 21H | |||
.WHILE 1 | ;循環條件爲永真的循環 | |||
MOV AH, 07H INT 21H |
;不帶回顯地從鍵盤讀一個字符 | |||
.BREAK .IF AL == 13 | ;如果輸入“回車”鍵,則終止循環 | |||
.CONTINUE .IF(AL<'0') || (AL>'9') | ;如果字符不是數字字符,則繼續循環 | |||
MOV DL, AL MOV AH, 02H INT 21H |
;顯示所輸入的數字字母 | |||
.ENDW | ||||
MOV | AX, 4C00H | |||
INT | 21H | |||
CODE1 | ENDS | |||
END | START |
參考資料:
http://www.feiesoft.com/asm/07-3-3.html
DATA1 | SEGMENT | |||
data | DW 90, 95, 54, 65, 36, 78, 66, 0, 99, 50, -1 | |||
Average | DW 0 | |||
DATA1 | ENDS | |||
CODE1 | SEGMENT | |||
ASSUME CS:CODE1, DS:DATA1 | ||||
START: | MOV | AX, DATA1 | ||
MOV | DS, AX | |||
XOR | AX, AX | |||
XOR | DX, DX | ;用(DX,AX)來保存數組元素之和 | ||
XOR | CX, CX | ;用CX來保存數組元素個數 | ||
LEA | SI, data | ;用指針SI來訪問整個數組 | ||
again: | MOV | BX, word ptr [SI] | ||
CMP | BX, 0 | |||
JL | over | |||
ADD | AX, BX | |||
ADC | DX, 0 | ;把當前數組元素之值加到(DX,AX)中 | ||
INC | CX | ;數組元素個數加1 | ||
ADD | SI, 2 | |||
JMP | again | |||
over: | JCXZ | exit | ;防止零作除數,即數組是空數組 | |
DIV | CX | |||
MOV | Average, AX | |||
exit: | MOV | AX, 4C00H | ||
INT | 21H | |||
CODE1 | ENDS | |||
END | START |