如果大家已经学过了高级编程语言,那么就会知道将程序分割为子过程(subroutine)是多么有用。一个复杂的问题常常要分解为相互独立的任务,这样才易于被理解、实现以及有效地测试。
在汇编语言中,通常用术语过程(procedure)来指代子程序。在其他语言中,子程序也被称为方法或函数。
就面向对象编程而言,单个类中的函数或方法大致相当于封装在一个汇编语言模块中的过程和数据集合。汇编语言出现的时间远早于面向对象编程,因此它不具备面向对象编程中的形式化结构。汇编程序员必须在程序中实现自己的形式化结构。
过程可以非正式地定义为:由返回语句结束的已命名的语句块。过程用 PROC 和 ENDP 伪指令来定义,并且必须为其分配一个名字(有效标识符)。到目前为止,所有编写的程序都包含了一个名为 main 的过程,例如:
当在程序启动过程之外创建一个过程时,就用 RET 指令来结束它。RET 强制 CPU 返回到该过程被调用的位置:
默认情况下,标号只在其被定义的过程中可见。这个规则常常影响到跳转和循环指令。在下面的例子中,名为 Destination 的标号必须与 JMP 指令位于同一个过程中:
解决这个限制的方法是定义全局标号,即在名字后面加双冒号 (::)。
就程序设计而言,跳转或循环到当前过程之外不是个好主意。过程用自动方式返回并调整运行时堆栈。如果直接跳出一个过程,则运行时堆栈很容易被损坏。
现在创建一个名为 SumOf 的过程计算三个 32 位整数之和。假设在过程调用之前,整数已经分配给 EAX、EBX 和 ECX。过程用 EAX 返回和数:
SumOf PROC
add eax,ebx
add eax,ecx
ret
SumOf ENDP
要培养的一个好习惯是为程序添加清晰可读的说明。下面是对放在每个过程开头的信息的一些建议:
上述选择的描述性标号,如 ReceivesReturns 和 Requires,不是绝对的;其他有用的名字也常常被使用。
有了这些思想,现在对 SumOf 过程添加合适的说明:
;-------------------------------------------------------
; sumof
; 计算 3 个 32 位整数之和并返回和数。
; 接收:EAX、EBX和ECX为3个整数,可能是有符号数,也可能是无符号数。
; 返回:EAX=和数
;------------------------------------------------------
SumOf PROC
add eax,ebx
add eax,ecx
ret
SumOf ENDP
用高级语言,如 C 和 C++,编写的函数,通常用 AL 返回 8 位的值,用 AX 返回 16 位的值,用 EAX 返回 32 位的值。