使用汇编语言实现算术表达式[实例]
前面已经介绍了如何用加减指令实现算术表达式,现在还可以再加上乘法和除法指令。初看上去,实现算术表达式的工作似乎最好是留给编译器的编写者,但是动手研究一下还是能学到不少东西。
读者可以学习编译器怎样优化代码。此外,与典型编译器在乘法操作后检查乘积大小相比,还能实现更好的错误检查。进行 32 位操作数相乘时,绝大多数高级语言编译器都会忽略乘积的高 32 位。而在汇编语言中,可以用进位标志位和溢出标志位来说明乘积是否为 32 位。
【示例 1】使用 32 位无符号整数,用汇编语言实现下述 C++ 语句:
【示例 2】使用 32 位无符号整数实现下述 C++ 语句:
【示例 3】使用 32 位有符号整数实现下述 C++ 语句:
读者可以学习编译器怎样优化代码。此外,与典型编译器在乘法操作后检查乘积大小相比,还能实现更好的错误检查。进行 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 ;商