汇编(MOV,SUB,PUSH,POP,...)

汇编开发(八):结构体与宏

2019-02-23  本文已影响0人  _凌浩雨

1. 结构体

结构是给予逻辑相关的变量组的模板或模式。 结构中的变量称为字段。 程序语句可以作为单个实体访问结构,也可以访问单个字段。 结构通常包含不同类型的字段。 联合还将多个标识符组合在一起,但标识符与内存中的相同区域重叠。

COORD STRUCT
    X WORD ? ; offset 00
    Y WORD ? ; offset 02
COORD ENDS
1). 定义结构体

定义结构体使用STRUCTENDS, 结构体内部,使用相同的语法定义变量。

name STRUCT
    field-declarations
name ENDS

示例:

Employee STRUCT
    IdNum BYTE "000000000"
    LastName BYTE 30 DUP(0)
    Years WORD 0
    SalaryHistory DWORD 0,0,0,0
Employee ENDS

内存占用布局:

structure’s memory layout.png Alignment of Structure Members.png
2). 定义结构体变量

可以声明结构变量,并可选择使用特定值进行初始化。

identifier structureType < initializer-list >

示例:

.data
point1 COORD <5,10>     ; X = 5, Y = 10
point2 COORD <20>       ; X = 20, Y = ?
point3 COORD <>         ; X = ?, Y = ?
worker Employee <>      ; (default initializers)

person1 Employee <"555223333">      ; 初始化IdNum
person2 Employee {"555223333"}      ; 与上一行作用相同
person3 Employee <,"dJones">        ; 初始化LastName
person4 Employee <,,,2 DUP(20000)>  ; 初始化SalaryHistory
NumPoints = 3
AllPoints COORD NumPoints DUP(<0,0>)
data
ALIGN DWORD
person Employee <>
3). 引用结构体变量

可以使用TYPE和SIZEOF运算符来引用结构变量和结构名称.

TYPE Employee   ; 60
SIZEOF Employee ; 60
SIZEOF worker   ; 60
TYPE Employee.SalaryHistory     ; 4
LENGTHOF Employee.SalaryHistory ; 4
SIZEOF Employee.SalaryHistory   ; 16
TYPE Employee.Years             ; 2
mov edx,OFFSET worker.LastName
mov esi,OFFSET worker
mov ax,(Employee PTR [esi]).Years
.data
    department Employee 5 DUP(<>)
.code
    mov esi,TYPE Employee       ; index = 1
    mov department[esi].Years, 4
; 循环数组
INCLUDE Irvine32.inc

NumPoints = 3
.data
    ALIGN WORD
    AllPoints COORD NumPoints DUP(<0, 0>)

.code
main PROC
    mov edi, 0              ; 数组索引
    mov ecx, NumPoints      ; 循环计数
    mov ax, 1               ; 开始X, Y的值

L1:
    mov (COORD PTR AllPoints[edi]).X, ax
    mov (COORD PTR AllPoints[edi]).Y, ax
    add edi, TYPE COORD
    inc ax
    LOOP L1
    exit
main ENDP
END
4). 示例: 显示系统时间
; 显示时间
INCLUDE Irvine32.inc

; 相关结构体在SmallWin.inc中

.data
    sysTime SYSTEMTIME <>
    XYPos COORD <10, 5>
    consoleHandle DWORD ?
    colonStr BYTE ":", 0
.code
main PROC
    ; 获取Win32控制台标准输出句柄
    INVOKE GetStdHandle, STD_OUTPUT_HANDLE
    mov consoleHandle, eax

    ; 设置光标位置和获取系统时间
    INVOKE SetConsoleCursorPosition, consoleHandle, XYPos
    INVOKE GetLocalTime, ADDR sysTime

    ; 显示系统时间(hh:mm:ss)
    movzx eax, sysTime.wHour
    call WriteDec
    mov edx,OFFSET colonStr
    call WriteString
    movzx eax, sysTime.wMinute
    call WriteDec
    call WriteString
    movzx eax, sysTime.wSecond
    call WriteDec

    call Crlf
    call WaitMsg
    exit
main ENDP
END
ShowTime 效果.png
5). 结构体包含结构体

结构体可以在内部字段中包含其他结构体。

Rectangle STRUCT
    UpperLeft COORD <>
    LowerRight COORD <>
Rectangle ENDS

定义及初始化:

rect1 Rectangle < >
rect2 Rectangle { }
rect3 Rectangle { {10,10}, {50,20} }
rect4 Rectangle < <10,10>, <50,20> >
6). 定义和使用共用体

虽然结构中的每个字段都具有相对于结构的第一个字节的偏移量,但联合中的所有字段都以相同的偏移量开始。 union的存储大小等于其最长字段的长度。

格式:

unionname UNION
    union-fields
unionname ENDS

如果在结构体定义共用体,则格式如下

structname STRUCT
    structure-fields
    UNION unionname
        union-fields
    ENDS
structname ENDS
Integer UNION
    D DWORD 1
    W WORD 5
    B BYTE 8
Integer ENDS

.data
    myInt Integer <>
; 结构体外部定义共用体
FileInfo STRUCT
    FileID Integer <>
    FileName BYTE 64 DUP(?)
FileInfo ENDS

; 结构体内部定义共用体
FileInfo STRUCT
    UNION FileID
        D DWORD ?
        W WORD ?
        B BYTE ?
    ENDS
    FileName BYTE 64 DUP(?)
FileInfo ENDS
val1 Integer <12345678h>
val2 Integer <100h>
val3 Integer <>

共用体中也可以包含结构体

INPUT_RECORD STRUCT
    EventType WORD ?
    ALIGN DWORD
    UNION Event
        KEY_EVENT_RECORD <>
        MOUSE_EVENT_RECORD <>
        WINDOW_BUFFER_SIZE_RECORD <>
        MENU_EVENT_RECORD <>
        FOCUS_EVENT_RECORD <>
    ENDS
INPUT_RECORD ENDS

; 其中KEY_EVENT_RECORD结构
KEY_EVENT_RECORD STRUCT
    bKeyDown DWORD ?
    wRepeatCount WORD ?
    wVirtualKeyCode WORD ?
    wVirtualScanCode WORD ?
    UNION uChar
        UnicodeChar WORD ?
        AsciiChar BYTE ?
    ENDS
    dwControlKeyState DWORD ?
KEY_EVENT_RECORD ENDS

2. 宏

宏过程是汇编语言语句的命名块。 一旦定义,就可以根据需要在程序中多次调用(调用)它。 当您调用宏过程时,其代码的副本将直接插入到调用它的位置的程序中。

定义格式:

PrintX MACRO
    mov al,'X'
    call WriteChar
ENDM
1). 宏定义

宏定义使用 MACROENDM.

格式:

macroname MACRO parameter-1, parameter-2...
    statement-list
ENDM
mPutchar MACRO char
    push eax
    mov al,char
    call WriteChar
    pop eax
ENDM
2). 调用宏

通过在程序中插入宏来调用宏,可能后跟宏参数。

macroname argument-1, argument-2, ...

调用mPutchar代码:mPutchar 'A'

3). 其他宏功能
mPutchar MACRO char:REQ
    push eax
    mov al,char
    call WriteChar
    pop eax
ENDM
mPutchar MACRO char:REQ
    push eax            ;; reminder: char must contain 8 bits
    mov al,char
    call WriteChar
    pop eax
ENDM
mPutchar MACRO char:REQ
    ECHO Expanding the mPutchar macro
    push eax
    mov al,char
    call WriteChar
    pop eax
ENDM
makeString MACRO text
    LOCAL string
    .data
        string BYTE text,0
ENDM
mWrite MACRO text
    LOCAL string ;; local label
    .data
        string BYTE text,0 ;; define the string
    .code
        push edx
        mov edx,OFFSET string
        call WriteString
        pop edx
ENDM
mWriteln MACRO text
    mWrite text
    call Crlf
ENDM
4). Macro 库(32位)
Macros in the Macros.inc Library.png
.data
array DWORD 1000h,2000h,3000h,4000h

mDumpMem OFFSET array, LENGTHOF array, TYPE array

宏实现:

;------------------------------------------------------
mDumpMem MACRO address:REQ, itemCount:REQ, componentSize:REQ
; Displays a dump of memory, using the DumpMem procedure.
; Receives: memory offset, count of the number of items
; to display, and the size of each memory component.
; Avoid passing EBX, ECX, and ESI as arguments.
;------------------------------------------------------
    push ebx
    push ecx
    push esi
    mov esi,address
    mov ecx,itemCount
    mov ebx,componentSize
    call DumpMem
    pop esi
    pop ecx
    pop ebx
ENDM
.data
    diskSize DWORD 12345h   
.code
    mDump diskSize      ; no label
    mDump diskSize,Y    ; show label

宏实现:

;----------------------------------------------------
mDump MACRO varName:REQ, useLabel
;
; Displays a variable, using its known attributes.
; Receives: varName, the name of a variable.
; If useLabel is nonblank, the name of the
; variable is displayed.
;----------------------------------------------------
    call Crlf
    IFNB <useLabel>
        mWrite "Variable name: &varName"
    ENDIF
    mDumpMem OFFSET varName, LENGTHOF varName, TYPE varName
ENDM
mGotoxy 10,20 ; immediate values
mGotoxy row,col ; memory operands
mGotoxy ch,cl ; register values

宏实现:

;------------------------------------------------------
mGotoxy MACRO X:REQ, Y:REQ
;
; Sets the cursor position in the console window.
; Receives: X and Y coordinates (type BYTE). Avoid
; passing DH and DL as arguments.
;------------------------------------------------------
    push edx
    mov dh,Y
    mov dl,X
    call Gotoxy
    pop edx
ENDM
.data
    firstName BYTE 30 DUP(?)
.code
    mReadString firstName

宏实现:

;------------------------------------------------------
mReadString MACRO varName:REQ
;
; Reads from standard input into a buffer.
; Receives: the name of the buffer. Avoid passing
; ECX and EDX as arguments.
;------------------------------------------------------
    push ecx
    push edx
    mov edx,OFFSET varName
    mov ecx,SIZEOF varName
    call ReadString
    pop edx
    pop ecx
ENDM
mov ax,4096
mShow AX        ; default options: HIN
mShow AX,DBN    ; unsigned decimal, binary, newline
mShowRegister EBX, ebx

宏实现:

;---------------------------------------------------
mShowRegister MACRO regName, regValue
LOCAL tempStr
;
; Displays a register's name and contents.
; Receives: the register name, the register value.
;---------------------------------------------------
    .data
        tempStr BYTE " &regName=",0
    .code
        push eax
        ; Display the register name
        push edx
        mov edx,OFFSET tempStr
        call WriteString
        pop edx
        ; Display the register contents
        mov eax,regValue
        call WriteHex
        pop eax
ENDM
; 默认为1
mWriteSpace 5

宏实现:

;------------------------------------------------------
mWriteSpace MACRO count:=<1>
;
; Writes one or more spaces to the console window.
; Receives: an integer specifying the number of spaces.
; Default value of count is 1.
;------------------------------------------------------
    LOCAL spaces
    .data
        spaces BYTE count DUP(' '),0
    .code
        push edx
        mov edx,OFFSET spaces
        call WriteString
        pop edx
ENDM
.data
    str1 BYTE "Please enter your name: ",0
.code
    mWriteString str1

宏实现:

;------------------------------------------------------
mWriteString MACRO buffer:REQ
;
; Writes a string variable to standard output.
; Receives: string variable name.
;------------------------------------------------------
    push edx
    mov edx,OFFSET buffer
    call WriteString
    pop edx
ENDM
5). 示例:包装
; Macros 包装程序 
; 使用Macros库中的:mGotoxy, mWrite, mWriteString
; mReadString, and mDumpMem.

INCLUDE Irvine32.inc
INCLUDE Macros.inc          ; macro 定义

.data
    array DWORD 1, 2, 3, 4, 5, 6, 7, 8
    firstName BYTE 31 DUP(?)
    lastName BYTE 31 DUP(?)

.code 
main PROC
    mGotoxy 0, 0
    mWrite <"Sample Macro Program", 0dh, 0ah>
    
    ; 输出用户信息
    mGotoxy 0, 5
    mWrite "Please enter your first name: "
    mReadString firstName
    call Crlf

    mWrite "Please enter your last name: "
    mReadString lastName
    call Crlf

    ; 显示用户姓名
    mWrite "Your name is "
    mWriteString firstName
    mWriteSpace
    mWriteString lastName
    call Crlf

    ; 显示整型数组
    mDumpMem OFFSET array, LENGTHOF array, TYPE array
    
    call WaitMsg
    call Crlf
    exit
main ENDP
END
Wraps.png

3. 条件装配指令

许多不同的条件汇编指令可以与宏结合使用,以使它们更加灵活。

IF condition
    statements
[ELSE
    statements]
ENDIF
Conditional-Assembly Directives.png
1). 检查丢失的参数

宏可以检查它的任何参数是否为空。 通常,如果宏接收到空白参数,则在预处理器扩展宏时会产生无效指令。

mWriteString MACRO string
    IFB <string>
        ECHO -------------------------------------------
        ECHO * Error: parameter missing in mWriteString
        ECHO * (no code generated)
        ECHO -------------------------------------------
        EXITM
    ENDIF
    push edx
    mov edx,OFFSET string
    call WriteString
    pop edx
ENDM
2). 参数的默认值

宏可以设置参数的默认值,如果用户没有为参数设置值,则使用该参数的默认值。

paramname := < argument >

示例:

mWriteln MACRO text:=<" ">
    mWrite text
    call Crlf
ENDM
3). Boolean 表达式
LT Less than
GT Greater than
EQ Equal to
NE Not equal to
LE Less than or equal to
GE Greater than or equal to
4). IF, ELSE, and ENDIF 指令

IF指令必须后跟一个常量布尔表达式。 表达式可以包含整数常量,符号常量或常量宏参数,但不能包含寄存器或变量名称。

IF expression
    statement-list
ENDIF

IF expression
    statement-list
ELSE
    statement-list
ENDIF

示例:

;-----------------------------------------------------
mGotoxyConst MACRO X:REQ, Y:REQ
;
; Sets the cursor position at column X, row Y.
; Requires X and Y coordinates to be constant expressions
; in the ranges 0 <= X < 80 and 0 <= Y < 25.
;------------------------------------------------------
    LOCAL ERRS ;; local constant
    ERRS = 0
    IF (X LT 0) OR (X GT 79)
        ECHO Warning: First argument to mGotoxy (X) is out of range.
        ECHO ******************************************************
        ERRS = 1
    ENDIF
    IF (Y LT 0) OR (Y GT 24)
        ECHO Warning: Second argument to mGotoxy (Y) is out of range.
        ECHO ******************************************************
        ERRS = ERRS + 1
    ENDIF
    IF ERRS GT 0 ;; if errors found,
        EXITM;; exit the macro
    ENDIF
    push edx
    mov dh,Y
    mov dl,X
    call Gotoxy
    pop edx
ENDM
5). IFIDN 和 IFIDNI 指令

IFIDNI指令在两个符号(包括宏参数名称)之间执行不区分大小写的匹配,如果它们相等则返回true。 IFIDN指令执行区分大小写的匹配。 当您想要确保宏的调用者没有使用可能与宏内的寄存器使用冲突的寄存器参数时,前者很有用。

IFIDNI <symbol>, <symbol>
    statements
ENDIF

使用:

;------------------------------------------------------
mReadBuf MACRO bufferPtr, maxChars
;
; Reads from the keyboard into a buffer.
; Receives: offset of the buffer, count of the maximum
; number of characters that can be entered. The
; second argument cannot be edx or EDX.
;------------------------------------------------------
    IFIDNI <maxChars>,<EDX>
        ECHO Warning: Second argument to mReadBuf cannot be EDX
        ECHO **************************************************
        EXITM
    ENDIF
    push ecx
    push edx
    mov edx,bufferPtr
    mov ecx,maxChars
    call ReadString
    pop edx
    pop ecx
ENDM
6). 特殊的运算符
Special Operators.png
.code
mShowRegister ECX

mShowRegister MACRO regName
.data
tempStr BYTE " &regName=",0

打印结果:
EAX = 00000101

效果用于显示寄存器名
count = 10
sumVal TEXTEQU %(5 + count) ; = "15"
mWrite <"Line three", 0dh, 0ah>
BadYValue TEXTEQU <Warning: Y-coordinate is !> 24> 
ShowWarning MACRO message
mWrite "&message"
ENDM

;打印结果:
Warning: Y-coordinate is > 24
7). 宏函数

宏函数类似于宏过程,因为它为汇编语言语句列表指定名称。 它的不同之处在于它总是通过EXITM指令返回一个常量(整数或字符串)。

IsDefined MACRO symbol
    IFDEF symbol
        EXITM <-1> ;; True
    ELSE
        EXITM <0> ;; False
    ENDIF
ENDM

4. 定义重复块

MASM有许多循环指令用于生成重复的语句块:
WHILE,REPEAT,FOR和FORC。 与LOOP指令不同,这些指令仅在汇编时工作,使用常量值作为循环条件和计数器:

1). WHILE 指令

WHILE指令基于布尔表达式重复语句块。

WHILE constExpression
    statements
ENDM

示例:

.data
    val1 = 1
    val2 = 1
    DWORD val1 ; first two values
    DWORD val2
    val3 = val1 + val2
    WHILE val3 LT 0F0000000h
        DWORD val3
        val1 = val2
        val2 = val3
        val3 = val1 + val2
    ENDM
2). REPEAT 指令

REPEAT指令根据计数器的值重复语句块。

REPEAT constExpression
    statements
ENDM

示例:

WEEKS_PER_YEAR = 52
WeatherReadings STRUCT
    location BYTE 50 DUP(0)
    REPEAT WEEKS_PER_YEAR
        LOCAL rainfall, humidity
        rainfall DWORD ?
        humidity DWORD ?
    ENDM
WeatherReadings ENDS
3). FOR 指令

FOR指令通过迭代符号列表来重复语句块。

FOR parameter,<arg1,arg2,arg3,...>
    statements
ENDM

示例:

COURSE STRUCT
    Number BYTE 9 DUP(?)
    Credits BYTE ?
COURSE ENDS

; A semester contains an array of courses.
SEMESTER STRUCT
    Courses COURSE 6 DUP(<>)
    NumCourses WORD ?
SEMESTER ENDS

.data
    Fall2013 SEMESTER <>
    Spring2014 SEMESTER <>
    Summer2014 SEMESTER <>
    Fall2014 SEMESTER <>
    FOR semName,<Fall2013,Spring2014,Summer2014,Fall2014>
        semName SEMESTER <>
    ENDM
4). FORC 指令

FORC指令通过迭代一串字符来重复语句块。

FORC parameter, <string>
    statements
ENDM

示例:

Delimiters LABEL BYTE
FORC code,<@#$%^&*!<!>>
    BYTE "&code"
ENDM
上一篇下一篇

猜你喜欢

热点阅读