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

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

读者可以学习编译器怎样优化代码。此外,与典型编译器在乘法操作后检查乘积大小相比,还能实现更好的错误检查。进行 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         ;商
< 上一页IDICV指令 ADC指令下一页 >