使用MASM-高级语法(2)


可以看到,MASM编译器对这些条件分支伪指令优化得相当好,看到这些反汇编后的指令,惟一的感觉是好像又回到了DOS汇编时代分支指令堆中,从这里可以发现,这些伪指令把汇编程序的可读性基本上提高到了高级语言的水平。

分析反汇编代码可以发现,在不同的条件满足之后,先是执行满足条件后需要执行的指令,如上面的mov esi,0001和mov esi,0002等指令,这些指令执行后,后面都有一句直接跳转的指令jmp 0040103E,0040103E地址对应整个条件分支结构的尾部,这意味着,由.if/.elseif/.else/.endif条件分支伪指令构成的分支结构只能有一个条件被满足,也就是说,程序按照从上到下的各个条件表达式,顺序判断,当第一个条件表达式满足的时候,执行相应的代码,然后就忽略掉下面所有的其他条件表达式,即使后面有另一个满足条件时也是如此!

如果需要构成的分支结构对于所有的表达式为“真”都要执行相应的代码,可以利用多个.if/.endif来完成,如下所示:

.if     表达式1

        表达式1为“真”要执行的指令

.endif

.if     表达式2

        表达式2为“真”要执行的指令

.endif

 使用 .if/.else/.endif构成分支伪指令的时候,不要漏写前面的小数点,if/else/endif是宏汇编中条件汇编宏操作的伪操作指令,作用是根据条件决定在最后的可执行文件中包不包括某一段代码。比如在程序的调试阶段:

DEBUG     equ 1

          …

if            DEBUG

          invoke  MessageBox,NULL,offset szText,offset szCaption,MB_OK

endif

该代码用来显示一个调试信息,当程序正式发行时,将第一句改为DEBUG equ 0,然后再编译,那么可执行文件中根本不会包括这段代码,这和.if/.else/.endif构成分支的伪指令完全是两回事情。

3.5.3  循环语句

循环是重复执行的一组指令,MASM的循环伪指令可以根据条件表达式的真假来控制循环是否继续,也可以在循环体中直接退出,使用循环的语法是:

.while  条件测试表达式

    指令

    [.break [.if 退出条件]]

    [.continue]

.endw

.repeat

    指令

    [.break [.if 退出条件]]

    [.continue]

    .until  条件测试表达式 (或.untilcxz [条件测试表达式])

.while/.endw循环首先判断条件测试表达式,如果结果是“真”,则执行循环体内的指令,结束后再回到 .while处判断表达式,如此往复,一直到表达式结果为“假”为止。.while/.endw指令有可能一遍也不会执行到循环体内的指令,因为如果第一次判断表达式时就遇到结果为“假”的情况,那么就直接退出循环。

.repeat/.until循环首先执行一遍循环体内的指令,然后再判断条件测试表达式,如果结果为“真”的话,就退出循环,如果为“假”,则返回 .repeat处继续循环,可以看出,.repeat/.until不管表达式的值如何,至少会执行一遍循环体内的指令。

也可以把条件表达式直接设置为固定值,这样就可以构建一个无限循环,对于.while/.end直接使用TRUE,对 .repeat/.until直接使用FALSE来当表达式就是如此,这种情况下,可以使用.break伪指令强制退出循环,如果 .break伪指令后面跟一个 .if测试伪指令的话,那么当退出条件为“真”时才执行 .break伪指令。

在循环体中也可以用 .continue伪指令忽略以后的指令,遇到 .continue伪指令时,不管下面还有没有其他循环体中的指令,都会直接回到循环头部开始执行。

同样,为了深入了解MASM编译器把循环伪指令变成了什么,下面对比一段源程序和反汇编后的代码。首先是源程序:

    .while  eax > 1

    mov     esi,1

        .break  .if ebx

        .continue

        mov     esi,2

    .endw

    .repeat

        mov     esi,1

        .break  .if !ebx

        .continue

        mov     esi,2

    .until      eax > 1

    .repeat

        mov     esi,1

        .break

    .untilcxz

以下是反汇编后的代码:

;       .while  第一个循环开始

:00401000 EB10                  jmp 00401012

:00401002 BE01000000            mov esi, 00000001

:00401007 0BDB                  or ebx, ebx

;   .break .if ebx

:00401009 750C                  jne 00401017

;   .continue

:0040100B EB05                  jmp 00401012

:0040100D BE02000000            mov esi, 00000002

;   .while eax > 1

:00401012 83F801                cmp eax, 00000001

:00401015 77EB                  ja 00401002

;   .repeat 第二个循环开始

:00401017 BE01000000                mov esi, 00000001

;   .break .if !ebx

:0040101C 0BDB                  or ebx, ebx

:0040101E 740C                  je 0040102C

;   .continue

:00401020 EB05                  jmp 00401027

:00401022 BE02000000            mov esi, 00000002

;   .until eax > 1

:00401027 83F801                cmp eax, 00000001

:0040102A 76EB                  jbe 00401017

;   .repeat 第三个循环开始

:0040102C BE01000000                mov esi, 00000001

;   .break

:00401031 EB02                  jmp 00401035

;   .untilcxz

:00401033 E2F7                  loop 0040102C   ;注意这里是loop指令!

对比伪指令和翻译成的实际指令,可以对循环的伪指令有更好的理解:.break翻译成一个跳转指令跳到循环结束的地方,.continue是一个无条件跳转指令跳到循环开始的地方,.while是先比较条件再执行循环体,而 .repeat是先执行循环体再比较条件的。

对指令的分析中可以发现,.while/.endw和 .repeat/.until循环没有使用loop指令的优势,因为loop指令可以自动递减ecx的值来控制循环,不使用loop将会在循环体内多设置一条参数递减的指令,但不用loop指令的好处是带来更多的灵活性。当然,为了弥补这个缺陷,使用.repeat/.untilcxz伪指令,编译器将会指定用loop指令来完成循环,当然,在这种用法中,程序员必须在循环开始前正确设置ecx的值。

如果又想用loop指令来构成循环又要使用条件表达式怎么办,这时同样可以在 .untilcxz伪指令后加条件测试语句,只不过这时候有很大的限制,第一只能是单个条件表达式,不能用&&或||来构成多项表达式了;第二即使是单个表达式中,也只能用==或!=操作符,不能用其他比较大小的操作符,因为这时编译器的翻译方式是在一个比较指令后使用loopz或loopnz来构成循环,这个指令不能测试其他标志位。

 在分支和循环的伪指令反汇编后可以发现,在使用>、>=、<和<=比较符时,MASM的伪指令总是将比较以后的跳转指令使用为jb和jnb等无符号数比较跳转的指令,这就意味着,MASM的条件测试总是把操作数当做无符号数看待,这样,假设eax等于1,那么表达式(eax > -1)的值是“假”,因为-1表示为0ffffffffh,如果当做无符号数看,它是最大的数!如果程序中需要构造有符号数的比较分支或循环结构,那么必须另外用jl和jg等有符号数比较跳转的指令来完成,使用条件测试配合分支或循环伪指令可能会得到错误的结果!



来源:电子工业出版社 作者:罗云彬
分享到: 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值