組合語言的假指令,可分為「一般的假指令」、「條件式組譯」及「高階指令」等三種,而一般,我們只需用到第一種,至於第二種,則式各人需要使用於巨集檔中,第三種,則不建議使用,因為要使用高階指令,那你不如用C語言去寫就好了,何必學組合語言呢,整個程式的整體架構是由程式設計師一人開發的,假如你加入了高階指令,那麼這個組合語言程式,不就沒有了他的本質(速度快,檔案小)。
以下會將這三種假指令取其常用的,分別一一為您介紹。
捷徑:條件式組譯、高階指令
一般的假指令
一般假指令的種類很多,例如:.model, .code, .data, .stack, end, ;, .186, .286, .386, .486, .586, equ, org, label, offset, segment, .data?, const, @, .fardata, .fardata?, seg, assume,dup等等。假指令本身,並不是程式碼,而是您在組譯時,組譯程式(MASM)會去看得懂這些假指令,而加以處理你所寫的程式碼,我將所有會用到的指令分別介紹如下:
1.指定微處理器模式 .8086、.186、.286、.386、.486
若指定.286,那麼程式在組譯時,就無法組譯386以上的組合語言指令碼,例如 EAX與 EBX 等32位元的暫存器,只有386以上CPU才有,所以若程式裡有 mov eax,eax 等指令時,組譯會發生組譯錯誤的訊息,唯有將微處理器模式改回 .386 或 .486 時才會組譯成功。所以小弟建議,一般都採用 .486 即可。功能就是將以上的程式碼組譯成 80486 的程式碼。
2.定義記憶體模式 .model [模式」
於本站「組合語言基礎」=>『組合語言原始檔基本架構』中,欲編寫組合語言程式一定要在原始檔中定義 記憶體模式,而其模式的種類與使用場合分別於下說明
記憶體模式 |
用途及記憶體使用範圍
|
tiny | 用於成立 .com 檔,程式段、資料段、額外段及堆疊段等四個區共用在同一個區段(64Kb)中,檔案最大僅能64Kb。 |
small | 程式段及資料段,各有64Kb的空間。為一般最常用的 .exe 檔的模式,建議使用。 |
medium | 程式段可超過64Kb,而資料段只有64Kb的空間。 |
compact | 資料段可超過64Kb,而程式段只有64Kb的空間。 |
large | 程式段與資料段,皆可大於 64 Kb。 |
huge | 同上,但更強的是,連同資料段中的任意某陣列,也可大於 64Kb 的範圍。 |
flat | ???? 用於 OS/2 系統。用途不詳...... |
.model tiny |
.model small |
定義程式區段的起始,如果我們定義兩個以上的程式段時,就必需為這些程式段命不同的名字;當我們只定義一個程式區段時,名稱可以省略不必命名,但在 tiny、small、compact 三種模式下,只能有一個程式段,所以就不必名稱了。
4.堆疊段起始 .stack [size]
定義堆疊段的起始,定義時可指定大小,其中以 byte 為單位,若省略而不指定大小時,會以 1024 bytes 取代之。
5.一般資料段起始 .data、.fardata [名稱]
近程資料段以 .data 起始,但其超出 64Kb 範圍的資料段稱為遠程資料段需以 .fardata 起始,而名稱,只有在定義兩個以上的遠程資料段時,才需命名。
6.無初始值之資料段與常數資料段 .data?、.fardata?、.const
我們如果只編寫單獨為組合語言程式時,這三個區段則無需定義,但若我們寫的程式要與高階語言作連結時,就必需將無初始值的資料移至 data? 或 fardata? 區段中,且需將用來定義字串、實數及常數的部份移至 .const 區段中。如下
|
當我們寫程式區段的程式碼時,必需在啟始執行的位置設一個標名,那麼該程式被組譯後,程式就會從這個標名開始執行,假設我們把它放在程式段的第一列。那麼於 END 之後也必需加上這個標名,才算是指定成功,程式才會以這個標名做起始,如下:
|
利用 mov 指令,即可將各區段段位值址取得,方法如下
|
|
使用時必需省略如上中的 end 後面的 begin0 及程式段的 begin0:,而且 .startup 也會自動執行 mov ax,@data 及 mov ds,ax,但如果是 .com 檔,它會自己加入 org 100h 指令,所以修改後架構,可參考「組合語言基礎」=>『組合語言原始檔基本架構』。
也就是說用於 .com 檔時,可做下列改變
|
|
|
|
組譯程式在碰到 .exit 時,會自動翻譯為執行下列程式碼
|
11.重覆定義資料 dup
可以重覆定一指定個數的記憶體變數內容,例如我們要定一個名稱為 poss0的記憶體變數,而內容是18個空白鍵,那麼我們的定義方式,可以有以下幾種為例:
方法一:
poss0 db 18 dup(20h) |
可利用定義功能,將程式中的某數值,以一個名稱取代,這種定義的用途的好處,就是修改程式容易,當我們寫一個程式,但如檔案內有個A數值為98,我們將它用等號定義,名稱定義為 numa,有一天我們要修改程式的A數值時,我們可以直接從定義的部份更改其A值即可將整個檔的A值都改了,這樣方便吧,如下:
numa equ 98或 numa = 98 |
|
條件式組譯
條件式組譯通常用在巨集檔裡面,因為同一個巨集中,為了避免佔用太大的記憶體,所以不是整個巨集裡的內容都需要用到,那麼那些沒有用到的部份就可不必組譯,可節省記憶體空間。1.假設指令集 if....(else)....endif
使用格式 [ ifxx 條件運算式 ],其中 ifxx 可為以下各模式,當條件成立時,才會將 ifxx 與 endif 之間的內容組譯。
if 假如不等於 0
ife 假如等於 0
ifdef 假如已定義過
ifndef 假如沒定義過
ifb 假如為空白
ifnb 假如不為空白
ifidn A,B 假如A等於B
ifidni A,B 假如A等於B(但區分大小寫)
ifdif A,B 假如A不等於B
ifdifi A,B 假如A不等於B(但區分大小寫)
使用範例如下
abcd macro pra1,pra2 ifb <para1> ; 假如引數1沒有輸入任何東西,則令 ax =1 mov ax,1 endif : exitm |
else、elsee、elsedef、elseb、elsenb、...... 功能同上,需用在 if 之後。
3.重覆組譯指令 repeat.....endm
使用的格式為,[repeat 次數],當組譯器在組譯時,就會重複組譯 repeat 與 endm 之間的內容,所以通常用於巨集指令之內。
4.條件重覆組譯 while.....endm
使用格式為 [while 條件運算式],當條件運算式成立時,重複組譯 while 與 endm之間的程式敘述。
5.重覆參數組譯 for.....endm
使用格式為 [ for 參數,<數值1,數值2,數值3.....> ],重複組譯的次數是取決於共輸入幾個數值,如果只輸入三個數值,代表藉於 for 與 endm 之間的程式碼重複組譯三次,每一次的參數值都不一樣,第一次時參數是放入數值1,第二次是放人數值2,第三次是放人數值3。
6.重覆文字參數組譯 forc
使用格式為 [ forc 參數,<字串> ],重複組譯的次數是取決字串的長度,如果只輸入 345 三個字,代表藉於 forc 與 endm 之間的程式碼重複組譯三次,每一次的參數值都不一樣,第一次時參數是放入數值3,第二次是放人數值4,第三次是放人數值5。
高階指令
高階指令,也可稱為流程控制指令,可以讓使用者在寫迴圈時更為簡便化,且由於它的語法與 C 語言相近,所以語法也就比較高階化,讓人容易一看就知道在寫什麼。而可用的高階指令有 .if、.while、.repeat、.break、.continue 等五種,使用的語法分別列出如下:
(1) .if 的使用方式
下面是簡單的 .if 控制流程,首先會檢查條件式 A 是否有成立,如果有成立則往下一行執行,執行完 .if 的部份再跳至 .endif 離開迴圈,如果不成立則跳到下一個條件式 B 去檢查是否成立,依此類推,直到每個條件式都不成立時,才會去執行 .else 裡面的東西,執行完一樣是跳至 .endif 離開迴圈。
.if 條件式 A : .elseif 條件式 B : .elseif 條件式 C ( 可以有無限多個 .elseif ) : .else : .endif |
(2) .while 之使用方式
條件式 A如果為真,則執行 .while .... .endw 之間的指令的部份,直至條件式 A為假,才停止執行。
.while 條件式A : (假如條件式A為真則執行此處指令) .endw |
(3) .repeat 之使用方式
有兩種使用方法,第一種是 .repeat 與 .until 配合,即當執行裡面的指令一次後,去判斷條件式 A是否為真,如果為假則繼續重覆此段的指令,如果為真則結束迴圈,如下
.repeat : (此段指令即欲執行之迴圈) .until 條件式A |
.repeat : (此段指令即欲執行之迴圈) .untilcxz 條件式A |
.break為結束迴圈,而 .continue 則為跳至迴圈的開頭,如下:
.while ..... : .break : .endw <=== 執行至 .break時,會直接結束迴圈,而從這開始執行 |
.while ..... <=== 執行至 .continue 時,會跳回這裡開始執行 : .continue : .endw |
.while ...... : .continue .if 條件式A <=== 條件式A成立時,跳至迴圈開頭 : .break .if 條件式B <== 條件式B成立時,結束迴圈 : .endw |
運算符號
|
意義
|
==
!=
>
<
>=
<=
&
!
&&
||
|
等於
不等於
大於
小於
大於等於
小於等於
AND
NOT
AND
OR
|
沒有留言:
張貼留言