結構
說明:
是一堆數據的定義的集合
基本格式:
結構名稱 STRUC
字段的定義
結構名稱 ENDS
舉例:
STUDENT STRUC
ID DW ?
SCORE DB 1
NAME DB 'STUDENTNAME'
STUDENT ENDS
定義變量:
變量名 結構類型 < 參數表 >
舉例:
S1 STDUENT <1,50,'zhao'>
S2 STDUENT <1,60,'zhang'>
S3 STDUENT <1,70,'wang'>
結構使用:
1. MOV AX, P1.ID
2. MOV BX, OFFSET P1
MOV AL, [BX].SCORE
總結:
使用起來還是和C/C++ 的結構比較類似的,實際上 P1.ID 和 [BX].SCORE 的兩種引用方式本質上是匯編器幫我們轉換了地址。
記錄
說明:
結構是將將一堆定義結合起來,方便管理,那么記錄就是講一個字或者一個字節拆分成各種按照位的定義
實際上記錄就是一個字或者字節的按位定義,所以長度最長不超過16位,右對齊。
基本格式:
記錄名稱 RECORD 字段1:位寬=初始值,字段2:位寬=初始值,….
舉例:
ABCD RECORD AA:5=12, BB:3=6, CC:4=3
內存結構:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 aa aa aa aa aa bb bb bb cc cc cc cc
定義變量:
變量名 結構類型 < 參數表 >
舉例:
S2 ABCD <1,2,3>
S1 ABCD <1,2,3>
S3 ABCD <3,2,1>
記錄使用:
WIDTH
返回一個記錄整體的位寬或者一個字段的位寬
MOV AX, WIDTH ABCD
MOV AX, WIDTH AA
MASK
返回對應字段的掩碼
MOV BX, MASK AA; BX = 0001111100000000B
總結:
和結構的功能有點類似,相當於在字節尺度尺度上的結構定義,相當於定義 標志位, 而MASK 就是提取標志位的掩碼。
宏定義
說明:
宏定義的本質和C/C++ 一樣就是字符替換,用定義的內容替換掉宏標識符
基本格式:
宏名稱 MACRO 參數1,參數2,………
local 標號1, 標號2 ……
標號1: xxxxx
xxxxx
xxxxx
ENDM
舉例:
M1 MACRO OPR, X, Y
LOCAL P1, P2
P1: OPR AX, BX
MOV AX, X
MOV BX, Y
TEST AX, BX
JNZ P1
JMP P2
P2: MOV AX, BX
ENDM
宏的使用:
M1 MOV, 5, 1
這條指令會被展開如下結果大致上就是字符替換
??0001: MOV AX, BX
MOV AX, 5
MOV BX, 1
TEST AX, BX
JNZ ??0001
JMP ??0002
??0002: MOV AX, BX
其中值得注意的是標號被替換成了 ??0001 ??0002 這是因為 宏如果在同一段代碼里多次展開,標號也會跟着被多次展開,那么就會出現一段代碼里同一個標號被多次定義,就會報錯,所以如果在宏定義里面有標號定義,那么在 開頭要使用 LOCAL 指令聲明本地標號,這樣匯編器會自動累加數字來代替標號
另外,使用的時候參數多傳少傳都可以,多傳了就舍棄,少傳了就默認用空代替,之后介紹的命令 IFB 可以判斷參數是否為空
參數傳遞的說明:
& 連接參數用的,應該與C中的用法差不多,通常用於字符拼接以及字符串中
定義:
JUMP MACRO CON,LAB
J&CON LAB ;; 這里就是將 字符 J 和 CON 的傳入的內容拼接起來
ENDM
使用:
JUMP NZ, EXIT
展開為
JNZ EXIT
同理如果是定義在'' 字符串中頁需要用& 表明是參數
定義:
MSG MACRO A,B
A DB 'MR.&B'
ENDM
使用
MSG A1,HELLO
展開為
A1 DB 'MR.HELLO'
<> 字符串原樣傳遞,如果字符串中報個各種字符,比如空格 特殊字符等,就用 <> 包起來,
匯編就會把他們統統當成一個完整字符串而不會去解析含義了
比如 < 包含各種內 容的字符,串--//123!@#$%^ > 中間有逗號,如果不用<> 匯編器會以為是兩個參數
! 轉義符號在上面的, 相當於c在字符串中的 \ , 這里比如 有一段字符串 1>2 ,如果用<> 包起來 就變成 <1>2>, 那就不對了,
匯編器會以為到1后邊的> 就結束了,所以要用 <1!>2>, 用!來個后面的 > 轉義.
% 在參數傳遞的時候是可以傳入表達式的, 用%() 包起來,就是告訴匯編器闖入的是表達式的值而不是標的是本身。
比如
定義:
MSG MACRO A,B
A DB 'MR.&B'
ENDM
使用
MSG A1, 1+2
展開為
A1 DB 'MR.1+2'
使用
MSG A1, %(1+2)
展開為
A1 DB 'MR.3'
其他說明:
PURGE 消除宏定義
比如前面定義了 宏 MSG, 那么在使用 PURGE MSG 之后的代碼里,MSG這個宏就不能使用了,但是之前還是能使用的。
EXITM 終止宏的展開
這個偽指令用在宏定義里面,當宏展開的時候遇到這個命令就停止展開了,相當於階段宏的內容。
總結:
宏的功能有點像子過程調用,但是由於它是在匯編階段就展開的,沒有像CALL 一樣的壓棧轉跳等的開銷,所以實際上他比CALL高效,實際上就有點像C++ 中的 INLINE 函數。
宏中可以使用宏,宏定義中頁可以嵌套定義宏,但是嵌套定義的宏,需要使用一次宏才會生效,比如
DEF MACRO A
A MACRO
push ax
ENDM
ENDM
如果不使用DEF宏定義,那么DEF宏定義不會被展開,那么根本就沒有 A的宏定義,如果順序是這樣的
DEF DEF2
被展開為
DEF2 MACRO
PUSH AX
ENDM
這個使用宏定義中的宏定義才被真正定義
之后才可以使用DEF2的宏定義
重復匯編
說明:
用途就是相當於寫了個循環
如下場景
db 0
db 0
.
20 個這樣的內容,目的是定義20個byte變量,或者說就是定義 BYTE LIST[20]
.
db 0
db 0
那就可以用 重復匯編 宏指令了
基本格式:
RPET
格式
REPT NUM
XXXXXX
ENDM
說明
功能就是將里面的內容直接復制粘貼多少遍
比如
rept 5
db 0
endm
展開為
db 0
db 0
db 0
db 0
db 0
可以用來定義數據 比如 BYTE LIST[20], 直接就是
rept 20
db 0
endm
IRP
格式
IRP 待替換參數<參數表1,參數表2,參數表3,參數表4,參數表5,參數表6>
xxxxxxx
endm
說明
本質還是一樣的,但是功能豐富了一點,在復制的時候,會逐一使用參數表內容替換待替換參數
比如
IRP P1<1,2,3,4,5,6>
DB P1
ENDM
展開為
DB 1
DB 2
DB 3
DB 4
DB 5
DB 6
IRPC
格式
IRPC 待替換參數,字符串
xxxxxxx
endm
說明
其實和IRP 是一樣的,就是用參數表逐一替換,不同的是給出這里給出的參數是字符串,這個偽指令會用字符串的字符來逐一代替
比如
IRP P1 abcdef
DB P1
ENDM
展開為
DB 'a'
DB 'b'
DB 'c'
DB 'd'
DB 'e'
DB 'f'
總結:
這三個偽指令只要是在定義數據的時候使用的
條件匯編
說明:
和C/C++ 中的
#Ifxxx
#else
#endfi
是一樣的東西
基本格式:
IFXXX
ELSE
ENDIF
IF/IFE
判斷標的是的值,用法和LINUX SHELL中的用法蠻相似的
IF (表達式)
表達式 != 0 的時候內容有效
ELSE
表達式 == 0 的時候內容有效
ENDIF
表達式的計算使用 https://www.cnblogs.com/alwaysking/p/7623781.html 中介紹的內容
IFDEF/IFNDEF
和C/C++ 中的#ifdef 與#ifndef 意義完全相同
IFB
用在宏定義中的,用於判斷某個參數 是否為空的
比如
MSG MACRO A,B
ifb <B>
A DB 'MR.&B'
else
A DB 'MR.UNKNOW'
endif
ENDM
INCLUDE
說明
沒錯與C/C++ 中的含義一致,就是在INCLIDE 的位置直接將INCLUDE的文件的拼接(復制粘貼)進來
用法
INCLUDE A.ASM
說明
include后面可以跟路徑,和C/C++ 一樣,匯編器會首先在當前目錄找,之后會在編譯參數指定的尋找路徑查找文件