• 使用汇编语言实现算术表达式[实例]

    前面已经介绍了如何用加减指令实现算术表达式,现在还可以再加上乘法和除法指令。初看上去,实现算术表达式的工作似乎最好是留给编译器的编写者,但是动手研究一下还是能学到不少东西。

    读者可以学习编译器怎样优化代码。此外,与典型编译器在乘法操作后检查乘积大小相比,还能实现更好的错误检查。进行 32 位操作数相乘时,绝大多数高级语言编译器都会忽略乘积的高 32 位。而在汇编语言中,可以用进位标志位和溢出标志位来说明乘积是否为 32 位。


    有两种简单的方法可以查看 C++ 编译器生成的汇编代码:

    • 一种方法是用 Visual Studio 调试时,在调试窗口中右键点击,选择 Go to Disassembly。
    • 一种方法是,在 Project 菜单中选择 Properties,生成一个列表文件。在 Configuration Properties,选择 Microsoft Macro Assembler,再选择 Listing Fileo 在对话窗口中,将 Generate Preprocessed Source Listing 设置为 Yes,List All Available Information 也设置为 Yes。

    【示例 1】使用 32 位无符号整数,用汇编语言实现下述 C++ 语句:

    var4 = (var1 + var2) * var3;

    这个问题很简单,因为可以从左到右来处理 (先加法再乘法)。执行了第二条指令后,EAX 存放的是 val1 与 var2 之和。第三条指令中,EAX 乘以 var3,乘积存放在 EAX 中:

    mov eax, var1
    add eax, var2
    mul var3                   ; EAX = EAX * var3
    jc tooBig                  ;无符号溢出?
    mov var4, eax
    jmp next
    tooBig:                    ;显示错误消息

    如果 MUL 指令产生的乘积大于 32 位,则 JC 指令跳转到有标号指令来处理错误。

    【示例 2】使用 32 位无符号整数实现下述 C++ 语句:

    var4 = (var1 * 5) / (var2 - 3);

    本例有两个用括号括起来的子表达式。左边的子表达式可以分配给 EDX:EAX,因此不必检查溢出。右边的子表达式分配给 EBX,最后用除法完成整个表达式:

    mov eax, var1             ;左边的子表达式
    mov ebx, 5
    mul ebx                   ;EDX:EAX=乘积
    mov ebx, var2             ;右边的子表达式
    sub ebx, 3
    div ebx                   ;最后的除法
    mov var4, eax

    【示例 3】使用 32 位有符号整数实现下述 C++ 语句:

    var4 = (varl * -5) / (-var2 % var3);

    与之前的例子相比,这个例子需要一些技巧。可以先从右边的表达式开始,并将其保存在 EBX 中。由于操作数是有符号的,因此必须将被除数符号扩展到 EDX,再使用 IDIV 指令:

    mov eax,var2         ;开始计算右边的表达式
    neg eax
    cdq                  ;符号扩展被除数
    idiv var3            ;EDX = 余数
    mov ebx,edx          ;EBX = 右边表达式的结果

    第二步,计算左边的表达式,并将乘积保存在 EDX:EAX 中:

    mov eax, -5          ;开始计算左边表达式
    imul var1            ;EDX:EAX=左边表达式的结果

    最后,左边表达式结果 (EDX:EAX) 除以右边表达式结果 (EBX):

    idiv ebx             ;最后计算除法
    mov var4,eax         ;商

更多...

加载中...