• 学 Win32 汇编[34]


    从接触 C 语言时, 我就不大喜欢宏; 但为了看懂别人的代码也不得不去了解.

    宏可定义在源程序的任意位置, 但一般放在 .data 前面.
    有些简单的宏可以用 equ、textequ 或 = 来代替, 但宏有更复杂的功能.

    "宏" 的本质是 "替换", 但又像极了 "子过程";
    所以即有宏过程(macro procedure)、也有宏函数(macro function).
    它既以有参数(可以是: 常数、变量、寄存器、指令、表达式), 有时也需要像子过程一样声明.
    宏可以指定哪些参数是必须的, 还可以给参数默认值.

    宏可以包含数据(.data)和代码(.code)、还可以嵌套.
    宏中的注释使用 ;; 如果只用 ; 将会被一起替换到代码中.

    宏的功能很强大, 现在常用的 PrintDec、PrintHex、PrintString、PrintText 等等都是宏.
    再强大它也只是 "文本替换".

    "宏" 和 "子程序" 相比:
    1、宏展开后顺序执行, 不像调用子程序跳来跳去, 这样程序会更 "快";
    2、宏展开后会让代码量增大, 导致程序变 "大".



    一个简单的宏:


    ; Test34_1.asm
    .386
    .model flat, stdcall
    
    include    windows.inc
    include    kernel32.inc
    include    masm32.inc
    include    debug.inc
    includelib kernel32.lib
    includelib masm32.lib
    includelib debug.lib
    
    ;定义一个 mExit 宏
    mExit macro
        PrintLine
        ret
    endm
    
    .code
    sum proc v1, v2, v3
        mov eax, v1
        add eax, v2
        add eax, v3
        ret
    sum endp
    ;
    main proc
        invoke sum, 11, 22, 33
        PrintDec eax ;66
        ;PrintLine
        ;ret
        mExit ;mExit 将被替换为上面两行代码
    main endp
    end main


    一个代替求和函数的宏:


    ; Test34_2.asm
    .386
    .model flat, stdcall
    
    include    windows.inc
    include    kernel32.inc
    include    masm32.inc
    include    debug.inc
    includelib kernel32.lib
    includelib masm32.lib
    includelib debug.lib
    
    mSum macro v1, v2, v3
        mov eax, v1
        add eax, v2
        add eax, v3
    endm
    
    .code
    main proc
        mSum 11, 22, 33
        PrintDec eax ;66
        PrintLine
        mSum 11, 22, 33, 44, 55 ;多余的参数会被忽略
        PrintDec eax ;66
        PrintLine
        ret
    main endp
    end main


    宏参数的默认值:


    ; Test34_3.asm
    .386
    .model flat, stdcall
    
    include    windows.inc
    include    kernel32.inc
    include    masm32.inc
    include    debug.inc
    includelib kernel32.lib
    includelib masm32.lib
    includelib debug.lib
    
    ;参数 v1、v2 通过 REQ 标识说明是必备参数
    ;参数 v3、v4 给出了默认值
    mSum macro v1:req, v2:req, v3:=<33>, v4:=<44>
        mov eax, v1
        add eax, v2
        add eax, v3
        add eax, v4
    endm
    
    .code
    main proc
        mSum 11, 22
        PrintDec eax ;110
        PrintLine
        ret
    main endp
    end main


    EXITM: 退出宏


    ; Test34_4.asm
    .386
    .model flat, stdcall
    
    include    windows.inc
    include    kernel32.inc
    include    masm32.inc
    include    debug.inc
    includelib kernel32.lib
    includelib masm32.lib
    includelib debug.lib
    
    mPrint macro
        PrintText '第一行'
        PrintText '第二行'
        exitm
        PrintText '第三行'
    endm
    
    .code
    main proc
        mPrint ;只会输出前两行
        ret
    main endp
    end main


    PURGE: 取消宏


    ; Test34_5.asm
    .386
    .model flat, stdcall
    
    include    windows.inc
    include    kernel32.inc
    include    masm32.inc
    include    debug.inc
    includelib kernel32.lib
    includelib masm32.lib
    includelib debug.lib
    
    mPrint macro
        PrintText '第一行'
        PrintText '第二行'
        PrintText '第三行'
        PrintLine
    endm
    
    .code
    main proc
        mPrint
        mPrint
        purge mPrint ;可用逗号隔开取消多个宏
        mPrint       ;这个宏不会展开了
        ret
    main endp
    end main


    宏中 local 的使用:


    ; Test34_6.asm
    .386
    .model flat, stdcall
    
    include    windows.inc
    include    kernel32.inc
    include    masm32.inc
    include    debug.inc
    includelib kernel32.lib
    includelib masm32.lib
    includelib debug.lib
    
    ;从三个数中求最大数的宏
    mMax macro v1, v2, v3
        LOCAL L1, L2 ;;如没有这句, 宏在多次展开时会让 L1、L2 重名, 这样宏会把标号名称协调好
        mov eax, v1
        cmp eax, v2
        jge L1
        mov eax, v2
    L1: cmp eax, v3
        jge L2
        mov eax, v3
    L2:
    endm
    
    .code
    main proc
        mMax 11, 22, 33
        PrintDec eax  ;33
        ret
    main endp
    end main


    灵活的参数, 用到 & 操作符:


    ; Test34_7.asm
    .386
    .model flat, stdcall
    
    include    windows.inc
    include    kernel32.inc
    include    masm32.inc
    include    debug.inc
    includelib kernel32.lib
    includelib masm32.lib
    includelib debug.lib
    
    ;求最数中的最大值:
    mMax macro v1, v2
        LOCAL L1
        mov eax, v1
        cmp eax, v2
        jge L1
        mov eax, v2
    L1:
    endm
    
    ;求最数中的最小值:
    mMin macro v1, v2
        LOCAL L1
        mov eax, v1
        cmp eax, v2
        jle L1
        mov eax, v2
    L1:
    endm
    
    ;能把 JGE 或 JLE 做参数:
    mCom1 macro XX, v1, v2
        LOCAL L1
        mov eax, v1
        cmp eax, v2
        XX L1
        mov eax, v2
    L1:
    endm
    
    ;能通过参数让 J*E 变为 JGE 或 JLE:
    mCom2 macro X, v1, v2
        LOCAL L1
        mov eax, v1
        cmp eax, v2
        J&X&E L1    ;;这里用到特殊操作符 &
        mov eax, v2
    L1:
    endm
    
    .code
    main proc
        mMax 11, 22
        PrintDec eax ;22
        
        mMin 11, 22
        PrintDec eax ;11
        
        mCom1 JGE, 11, 22
        PrintDec eax ;22
        
        mCom1 JLE, 11, 22
        PrintDec eax ;11
        
        mCom2 G, 11, 22
        PrintDec eax ;22
        
        mCom2 L, 11, 22
        PrintDec eax ;11
        ret
    main endp
    end main


    特殊操作符: &、<>、%、!


    &  ;替换操作符
    <> ;字符串传递操作符
    %  ;表达式操作符, 也用于得到一个变量或常量的值
    !  ;转义操作符

    
    ; Test34_8.asm
    .386
    .model flat, stdcall
    
    include    windows.inc
    include    kernel32.inc
    include    masm32.inc
    include    debug.inc
    includelib kernel32.lib
    includelib masm32.lib
    includelib debug.lib
    
    ;自定义的宏
    mPrint macro Text
        PrintText '* &Text& *'
    endm
    
    .code
    main proc
        ;该宏会把参数直接替换过去
        mPrint 1234    ;* 1234 *
        
        ;要保证参数的完整应该使用 <>
        mPrint 12,34   ;* 12 *
        mPrint <12,34> ;* 12,34 *
        
        ;需要计算结果应该使用 %()
        mPrint 34+12   ;* 34+12 *
        mPrint %(34+12)   ;* 46 *
        
        ;用到 &、<、>、%、! 应该使用 ! 转义
        mPrint 10 !% 2 = %(10/2)!! ;* 10 % 2 = 5! *
        ret
    main endp
    end main

  • 相关阅读:
    20155322 2017-2018-1《信息安全系统设计》第七周学习总结
    20155322 2017-2018-1《信息安全系统设计》实验二:固件程序设计
    20155322 2017-2018-1《信息安全系统设计》第六周学习总结
    20155322 2017-2018-1《信息安全系统设计》第六周 课下作业
    01--DNS服务器1
    华为lab-rs-v1-2.5_流量优化
    华为lab-rs-v1-2.4_OSPF提升
    华为lab-rs-v1-2.3_OSPF基础
    华为lab-rs-v1-2.2_RIP基础
    华为lab-rs-v1-2.1_IP基础
  • 原文地址:https://www.cnblogs.com/qanholas/p/3534033.html
Copyright © 2020-2023  润新知