• MASM 宏结构


    宏是一段汇编语句序列。定以后,在程序中进行宏调用,则由编译器在编译器前进行展开。

    1.宏定义和宏调用

    宏定义一般用一对宏汇编伪指令MACRO和ENDM完成,格式如下:

    宏名  MACRO  [形参表]

        ……        ;宏定义体

    ENDM

    宏名必须是合法的标识符,同一源程序中应该唯一。宏定义体中不仅可以是硬件指令组成的执行性语句序列,还可以是伪指令组成的指示性语句序列。可选的形参表给出了宏定义中用到的形式参数,各个形参之间用半角逗号进行分割。

    请看下面这段程序:

    .386
    .model    flat,stdcall
    option    casemap:none
    
    include        windows.inc
    include        kernel32.inc
    include        user32.inc
    includelib    kernel32.lib
    includelib    user32.lib
    
    
    ShowMessage    macro    szText,szCaption
        push    MB_OK
        push    offset szCaption
        push    offset szText
        push    0
        call    MessageBox
    endm
    
    .data
    szS1        db    '吞风吻雨葬落日未曾彷徨,欺山赶海践雪径也未绝望',0
    szS2        db    '难念的经',0
    
    .code
    
    Main    proc
        ShowMessage    szS1,szS2
        invoke    ExitProcess,0
        ret
    
    Main    endp
    
    _START:
        call    Main
    end    _START

    在编译时,编译器搜索所以宏调用,并用相应的宏定义体进行替换。宏定义的语法是否错误是不检查的,这类似于C语言中的#define,宏展开后由编译器进行语法检查。

    查看这段代码编译后的反汇编,可以看到:

    2.宏的参数和宏的操作符

    宏的参数功能强大,数量不限,可以是常数,变量,储存单元,指令(操作码),也可以是表达式。宏的参数还可以设置默认值。

    运用宏海需要一些宏操作符的配合,如下:

    宏操作符 作用或含义
    & 替换操作符,用于将参数与其他字符分开。如果参数紧接在其他字符之前或之后,或者参数出现在带引号的字符串中,必须使用该伪操作符
    <> 字符串传递操作符,如果字符串包含逗号,空格等,则必须使用该对操作符,以保证传递完整性
    ! 转义操作符,用于表明后一个字符是一般字符,不具有特殊含义
    % 表达式操作符,用于宏调用中表示将后跟的一个表达式的值作为实参,而不是将表达式本身作为参数
    ;; 宏注释符,用于表示在宏定义的注释。在展开中不出现。
    := 设定参数默认值

    请看如下示例程序:

    .386
    .model    flat,stdcall
    option    casemap:none
    
    include        windows.inc
    include        kernel32.inc
    include        user32.inc
    includelib    kernel32.lib
    includelib    user32.lib
    
    
    Text    macro    string,define
        define    byte    '&string&',0
    endm
    
    .data
    Text    <Assembly Is Very Good!!>,<szText>
    Text    <Title>,<szTitle>
    
    .code
    
    Main    proc
        invoke    MessageBox,0,offset szText,offset szTitle,MB_OK
        invoke    ExitProcess,0
    Main    endp
    
    _START:
        call    Main
    end    _START

    首先,我们定义了一个名为Text的宏,该宏有两个参数,第一个参数表示字符串内容,第二个参数表示定义字符串的标识符。在定义"Assembly is very Good!"字符串时,我使用了两个感叹号,为何?假如我们直接使用"Text <Assembly Is Very Good!>,<szText>"而不在尾部加两个!时会发生什么呢?!号表示后一个字符不具有特殊意义,那么>就不再表示字符串传递符号了。而且,宏定义体我使用了&&操作符,因为我在''里面使用了参数,如果不指明,那么'string'就会变成普通的字符串,不具备任何其它意义。

    3.宏的伪指令

    我们考虑如下宏:

    Bigger    macro    Num1,Num2
        mov    eax,Num1
        cmp    eax,Num2
        jg    next
        mov    eax,Num2
    next:
    endm

    这段Bigger宏有什么作用呢?它接受两个参数,并将较大的那个参数放入EAX。

    如果我们在同一个子程序里面多次调用它会发生什么呢?调用一次呢?多次调用时,错误如下:

    Test.asm(26) : error A2005: symbol redefinition : next
    Bigger(5): Macro Called From
    Test.asm(26): Main Line Code

    为什么呢?因为next标号,多次调用宏时,宏被重复展开,next标号被重复定义,同一个子程序里面怎么能出现多个同名标号呢?这自然会引发错误,那么如何改进呢?

    我们可以在宏里面使用LOCAL伪指令。

    LOCAL伪指令使用格式如下:

    LOCAL 标号列表

    改进之后的宏如下:

    Bigger    macro    Num1,Num2
        LOCAL    next
        mov    eax,Num1
        cmp    eax,Num2
        jg    next
        mov    eax,Num2
    next:
    endm

    您可以尝试在同一个子程序里面重复使用试试看还会出现错误吗?

  • 相关阅读:
    R、Python、Scala 和 Java,到底该使用哪一种大数据编程语言?
    iOS7
    The “Experimental” status of Multipath TCP
    (OK) porting MPTCP to LineageOS-14.1-kiwi (Android-7.1.1,运行在Huawei honor 5x) for VirtualBox- 100% 成功
    ip_route_output_key函数分析(1)
    (OK) porting MPTCP to LineageOS-14.1-kiwi (Android-7.1.1,运行在Huawei honor 5x) for VirtualBox
    (2) linux 3.x
    【CodeForces 271D】Good Substrings
    【CodeForces 987C】Three displays
    【CodeForces 574B】Bear and Three Musketeers
  • 原文地址:https://www.cnblogs.com/galano/p/8721350.html
Copyright © 2020-2023  润新知