过程定义由PROC与ENDP伪指令实现,形式如下:
过程名 PROC [NEAR|FAR]
<过程体>
过程名 ENDP
过程名在整个程序中必须是唯一的。
过程名本质上与标号一样,也具有3种属性:段地址、偏移地址和类型(NEAR或FAR)。
PROC后用关键字NEAR、FAR或空,以表示过程的类型(缺省为NEAR)。
过程名 PROC [NEAR|FAR]
<过程体>
过程名 ENDP
过程名在整个程序中必须是唯一的。
过程名本质上与标号一样,也具有3种属性:段地址、偏移地址和类型(NEAR或FAR)。
PROC后用关键字NEAR、FAR或空,以表示过程的类型(缺省为NEAR)。
1.过程调用和返回指令
(1)CALL:过程调用
与JMP指令类似,CALL指令包括下列4种调用方式:
段内直接调用(Intrasegment/Direct Call)
段间直接调用(Intersegment/Direct Call)
段内间接调用(Intrasegment/Indirect Call)
段间间接调用(Intersegment/Indirect Call)
段内调用在同一代码段内进行,又称近(Near)调用;
段间调用可以在不同代码段之间进行,又称远(Far)调用。
语法格式:
CALL ProcName ; 若ProcName与该指令在同一代码段,则为段内直接调用:
; IP进栈,IP = label的偏移地址;
; 若ProcName与该指令不在同一代码段,则为段间直接调用:
; CS:IP 进栈,CS:IP = label的分段地址
CALL reg16/mem16 ; 段内间接调用:IP进栈,IP = reg16 / [mem16]
CALL mem32 ; 段间间接调用:
; CS:IP 进栈,CS = mem32高字,IP = mem32低字
功能描述:
(1)返回地址进栈。
远调用:CS与IP(下一条指令的地址)依次进栈。
近调用:IP(下一条指令的16位偏移地址)进栈。
(2)转移到过程的第1条指令去执行。
远调用:根据操作数,将32位分段地址送CS:IP。
近调用:根据操作数,将16位偏移地址送IP。
对标志位的影响:无。
(2)RET指令RET(Return):过程返回
过程返回分为近(段内)返回和远(段间)返回。
语法格式:
RET ; 近返回或远返回
RET imm16 ; 近返回或远返回,并调整堆栈:SP = SP + imm16
功能描述:
RET:返回地址出栈,从而实现转移到返回地址处。其中,
远返回:POP 1个双字到CS:IP。
近返回:POP 1个字到IP。
RET imm16:在返回地址出栈后,CPU立即将imm16加到堆栈指针SP。这种机制用来在返回前将参数从栈中移出。
对标志位的影响:无。
说明:RET由汇编器根据其所在过程的类型(NEAR或FAR)决定是近返回还是远返回。缺省为近返回。
(1)CALL:过程调用
与JMP指令类似,CALL指令包括下列4种调用方式:
段内直接调用(Intrasegment/Direct Call)
段间直接调用(Intersegment/Direct Call)
段内间接调用(Intrasegment/Indirect Call)
段间间接调用(Intersegment/Indirect Call)
段内调用在同一代码段内进行,又称近(Near)调用;
段间调用可以在不同代码段之间进行,又称远(Far)调用。
语法格式:
CALL ProcName ; 若ProcName与该指令在同一代码段,则为段内直接调用:
; IP进栈,IP = label的偏移地址;
; 若ProcName与该指令不在同一代码段,则为段间直接调用:
; CS:IP 进栈,CS:IP = label的分段地址
CALL reg16/mem16 ; 段内间接调用:IP进栈,IP = reg16 / [mem16]
CALL mem32 ; 段间间接调用:
; CS:IP 进栈,CS = mem32高字,IP = mem32低字
功能描述:
(1)返回地址进栈。
远调用:CS与IP(下一条指令的地址)依次进栈。
近调用:IP(下一条指令的16位偏移地址)进栈。
(2)转移到过程的第1条指令去执行。
远调用:根据操作数,将32位分段地址送CS:IP。
近调用:根据操作数,将16位偏移地址送IP。
对标志位的影响:无。
(2)RET指令RET(Return):过程返回
过程返回分为近(段内)返回和远(段间)返回。
语法格式:
RET ; 近返回或远返回
RET imm16 ; 近返回或远返回,并调整堆栈:SP = SP + imm16
功能描述:
RET:返回地址出栈,从而实现转移到返回地址处。其中,
远返回:POP 1个双字到CS:IP。
近返回:POP 1个字到IP。
RET imm16:在返回地址出栈后,CPU立即将imm16加到堆栈指针SP。这种机制用来在返回前将参数从栈中移出。
对标志位的影响:无。
说明:RET由汇编器根据其所在过程的类型(NEAR或FAR)决定是近返回还是远返回。缺省为近返回。
*使用过程应注意的问题
在过程体内必须有一条RET指令被执行到。如果在过程内没有执行到RET或其它转移指令,程序将继续执行ENDP后的指令。
正确选择过程的类型。通常基于下列原则:
若过程只在同一代码段中被调用,则定义为NEAR。
若过程可以在不同代码段中被调用,则定义为FAR。
CALL与RET的类型要一致。
通常要保证RET指令执行前,栈顶内容正好是返回地址。
注意保护相关寄存器的值。通常,除了作为返回参数的寄存器外,过程不应改变其它寄存器的值。
可以将过程定义放在单独的代码段中。若过程定义与主程序处于同一代码段,则要保证其只有被调用时,才会执行。
对于大多数过程,需要与调用者之间传递一定数量的数据,即参数。根据传递的方向,将参数分为两类:
入口参数:由调用者向过程传递的数据,作为过程的输入参数。
出口参数:由过程向调用者返回的数据,作为过程的输出参数。
根据问题的需要,过程可以只有入口参数或只有出口参数,也可以二者兼有。
对于过程与调用者之间的参数传递,可根据传递的数据量,选择采用寄存器、变量或堆栈等方式。由于过程是相对独立的功能块, 因此,在定义过程时,通常要加上适当的注释,主要包括功能、入口参数与出口参数等。
在过程体内必须有一条RET指令被执行到。如果在过程内没有执行到RET或其它转移指令,程序将继续执行ENDP后的指令。
正确选择过程的类型。通常基于下列原则:
若过程只在同一代码段中被调用,则定义为NEAR。
若过程可以在不同代码段中被调用,则定义为FAR。
CALL与RET的类型要一致。
通常要保证RET指令执行前,栈顶内容正好是返回地址。
注意保护相关寄存器的值。通常,除了作为返回参数的寄存器外,过程不应改变其它寄存器的值。
可以将过程定义放在单独的代码段中。若过程定义与主程序处于同一代码段,则要保证其只有被调用时,才会执行。
对于大多数过程,需要与调用者之间传递一定数量的数据,即参数。根据传递的方向,将参数分为两类:
入口参数:由调用者向过程传递的数据,作为过程的输入参数。
出口参数:由过程向调用者返回的数据,作为过程的输出参数。
根据问题的需要,过程可以只有入口参数或只有出口参数,也可以二者兼有。
对于过程与调用者之间的参数传递,可根据传递的数据量,选择采用寄存器、变量或堆栈等方式。由于过程是相对独立的功能块, 因此,在定义过程时,通常要加上适当的注释,主要包括功能、入口参数与出口参数等。
1 用变量传递参数
在程序中定义全局变量,如放在数据段,过程直接按名访问该变量。
过程直接以变量作为参数,虽然方便,但通用性较差。
2 用寄存器传递参数
通过寄存器传递数据或数据地址。
通常选择AL、AX、DX:AX(或EAX)传递字节、字或双字。
传递16位偏移地址最好选择SI、DI或BX,
传递32位分段地址可以用DS:BX、DS:SI、DS:DI、ES:BX、ES:SI或ES:DI等。
当然,要根据需要来选择,以方便为主,但很少使用BP来传递参数。
通过寄存器传递数据或数据地址。
通常选择AL、AX、DX:AX(或EAX)传递字节、字或双字。
传递16位偏移地址最好选择SI、DI或BX,
传递32位分段地址可以用DS:BX、DS:SI、DS:DI、ES:BX、ES:SI或ES:DI等。
当然,要根据需要来选择,以方便为主,但很少使用BP来传递参数。
3 用地址表传递参数
建立一个地址表,存放所有参数的地址,传递地址表的首地址给过程。
这种方法特别适合于参数较多的情况。
建立一个地址表,存放所有参数的地址,传递地址表的首地址给过程。
这种方法特别适合于参数较多的情况。
4 用堆栈传递参数
调用者通过调整堆栈指针为返回参数预留空间,然后将过程所需的入口参数进栈;
过程从堆栈得到入口参数,返回前将出口参数写入堆栈;
调用者通过出栈得到返回参数。
过程从堆栈存取参数时,通常使用BP,因为其隐含的段地址在SS中。
采用堆栈传递参数时,典型的过程结构如下:
StdProc proc near
push bp
mov bp, sp ; BP指向当前栈顶,用于取入口参数
...
pop bp
ret ParmSize ; 返回前从堆栈移出入口参数
StdProc endp
其中,ParmSize是过程被调用前进栈的入口参数的字节数。
调用者通过调整堆栈指针为返回参数预留空间,然后将过程所需的入口参数进栈;
过程从堆栈得到入口参数,返回前将出口参数写入堆栈;
调用者通过出栈得到返回参数。
过程从堆栈存取参数时,通常使用BP,因为其隐含的段地址在SS中。
采用堆栈传递参数时,典型的过程结构如下:
StdProc proc near
push bp
mov bp, sp ; BP指向当前栈顶,用于取入口参数
...
pop bp
ret ParmSize ; 返回前从堆栈移出入口参数
StdProc endp
其中,ParmSize是过程被调用前进栈的入口参数的字节数。
5 用代码流传递参数
由位于CALL指令之后的代码流(Code Stream)传递参数。
由位于CALL指令之后的代码流(Code Stream)传递参数。
递归过程
1.递归过程的主要思想
将一个问题分解为几个子问题,而其中的有些子问题与原问题相同,只是规模要小。
随着问题的不断分解,一定存在一个与原问题相同的最小问题,可以直接解决,这便是递归出口。
2.递归过程设计的关键
保证除了出口参数外,每次调用都不破坏以前调用时所用到的参数和中间结果。
递归过程的参数传递常使用堆栈,也可使用寄存器,但通常不用变量。
保证除了出口参数外,每次调用都不破坏以前调用时所用到的参数和中间结果。
递归过程的参数传递常使用堆栈,也可使用寄存器,但通常不用变量。
转载于:https://blog.51cto.com/zhangbikai/185801