在上一节《整数数组求和》的 ArraySum 示例中,ECX 和 ESI 在过程开始时被压入堆栈,在过程结束时被弹出堆栈。这是大多数过程修改寄存器的典型操作。总是保存和恢复被过程修改的寄存器,将使得调用程序确保自己的寄存器值不会被覆盖。但是对用于返回数值的寄存器应该例外,通常是指 EAX,不要将它们压入和弹出堆栈。
USES 运算符与 PROC 伪指令一起使用,让程序员列出在该过程中修改的所有寄存器名。USES 告诉汇编器做两件事情:第一,在过程开始时生成 PUSH 指令,将寄存器保存到堆栈;第二,在过程结束时生成 POP 指令,从堆栈恢复寄存器的值。
USES 运算符紧跟在 PROC 之后,其后是位于同一行上的寄存器列表,表项之间用空格符或制表符(不是逗号)分隔。
在 ArraySum 过程使用 PUSH 和 POP 指令来保存和恢复 ESI 和 ECX。 USES 运算符能够更加容易地实现同样的功能:
ArraySum PROC USES esi ecx
mov eax, 0 ;置和数为0
L1:
add eax,[esi] ;将每个整数与和数相加
add esi, TYPE DWORD ;指向下个整数
loop L1 ;按照数组大小重复
ret ;和数在 EAX 中
ArraySum ENDP
汇编器生成的相应代码展示了使用 USES 的效果:
ArraySum PROC
push esi
push ecx
mov eax, 0 ;置和数为0
L1:
add eax, [esi] ;将每个整数与和数相加
add esi, TYPE DWORD ;指向下一个整数
loop L1 ;按照数组大小重复
pop ecx
pop esi
ret
ArraySum ENDP
调试提示:使用 Microsoft Visual Studio 调试器可以查看由 MASM 高级运算符和伪指令生成的隐藏机器指令。在调试窗口中右键点击,选择 Go To Disassembly。该窗口显示程序源代码,以及由汇编器生成的隐藏机器指令。
当过程利用寄存器(通常用 EAX)返回数值时,保存使用寄存器的惯例就岀现了一个重要的例外。在这种情况下,返回寄存器不能被压入和弹出堆栈。例如下述 SumOf 过程把 EAX 压入、弹出堆栈,就会丢失过程的返回值:
SumOf PROC ;三个整数之和
push eax ;保存EAX
add eax, ebx
add eax, ecx ;计算EAX、EBX和ECX之和
pop eax ;和数丢失!
ret
SumOf ENDP