汇编语言递归程序的三种传参方式

 用递归子程序实现如下题目

设计汇编子程序来实现如下数列计算,输入项数n,输出对应第n项的16进制数值。数列以如下被以递推的方法定义:
 F(0)=0,F(1)=1, F(2)=2, F(n)=F(n - 1)+F(n - 2)(n≥ 3,n∈ N*)

 方案一:用寄存器传递出入口参数

;PREPEND BEGIN
	.model small
	.stack
	.data
	.code
start:
	mov ah, 08h
    int 21h
    sub al, '0'
	xor ah,ah
	call ditui1
	call print_ax
;******exit******
    mov ax, 4c00h
    int 21h
;******exit******
;PREPEND END
;TEMPLATE BEGIN
;ax=n 寄存器ax传递参数   
ditui1 proc
;ditui1
;***begin****      注意这里开始主程序!!!    
    push cx
    push bx
    push dx
    mov cx,ax     ;用cx记录n的值
    cmp cx,2      ;n为0、1、2则跳转
    je f2
    cmp cx,1
    je f1
    cmp cx,0
    je f0
    dec cx             ;n-1
    mov ax,cx          ;将n给ax,调用子函数
    call ditui1
    mov bx,ax
    mov ax,cx
    dec ax             ;n-2
    call ditui1
    add ax,bx          ;结果
    jmp done           ;n非0、1、2,结束
f2:
    mov ax,2
    jmp done
f1:
    mov ax,1
    jmp done
f0:
    mov ax,0
    jmp done
done:
    pop dx             ;寄存器恢复
    pop bx
    pop cx
    ret
;****end******
ditui1 endp
;TEMPLATE END
;APPEND BEGIN
print_ax proc
	push ax	;过程中使用了AX、CX和DX
	push cx
	push dx
	push ax	;暂存ax
	mov dl,al	;转换al的高4位
	mov cl,4
	shr dl,cl
	or dl,30h	;al高4位变成3
	cmp dl,39h
	jbe aldisp1
	add dl,7	;是0Ah~0Fh,还要加上7
aldisp1:	mov ah,2	;显示
	int 21h
	pop dx	;恢复原ax值到dx
	and dl,0fh	;转换al的低4位
	or dl,30h
	cmp dl,39h
	jbe aldisp2
	add dl,7
aldisp2:	mov ah,2	;显示
	int 21h
	pop dx
	pop cx
	pop ax
	ret	;过程返回
print_ax endp
end start
;//APPEND END

难点:出入口参数寄存器如何使用。

由于要求出入口参数使用同一个寄存器传递,所以每次ax传入参数n后,用cx记录入口参数,并且在调用子函数的时候,将cx的值给ax再调用子函数,由此保证入口参数正确(一直为n-1)且出口的ax为f(cx)的值。

方案二:用栈传出入口参数

;PREPEND BEGIN
	.model small
	.stack
	.data
	.code
start:
	mov ah, 08h
    int 21h
    sub al, '0'
	xor ah,ah
	push ax	
	call ditui1
	pop ax
	call print_ax
;******exit******
    mov ax, 4c00h
    int 21h
;******exit******
;PREPEND END
;TEMPLATE BEGIN   
ditui1 proc
;***begin****
    push bp         ;子程序在这开始!!!
    mov bp,sp
    push cx
    push ax
    push bx
    mov cx,[bp+4]  ;取出参数
    cmp cx,2      ;n为0、1、2则跳转
    je f2
    cmp cx,1
    je f1
    cmp cx,0
    je f0
    dec cx        ;n-1
    push cx       ;压入参数
    call ditui1   ;调用第一次子程序
    pop bx        ;取出结果
    dec cx        ;n-1-1=n-2
    push cx
    call ditui1   ;调用第二次子程序
    pop ax
    add ax,bx     ;结果用ax暂存
    jmp done
f2:
    mov ax,2
    jmp done
f1:
    mov ax,1
    jmp done
f0:
    mov ax,0
    jmp done
done:
    mov [bp+4],ax      ;出口参数放入对应位置
    pop bx             ;寄存器恢复
    pop ax
    pop cx
    pop bp
    ret
;****end******
;TEMPLATE END
ditui1 endp
;APPEND BEGIN
print_ax proc
	push ax	;过程中使用了AX、CX和DX
	push cx
	push dx
	push ax	;暂存ax
	mov dl,al	;转换al的高4位
	mov cl,4
	shr dl,cl
	or dl,30h	;al高4位变成3
	cmp dl,39h
	jbe aldisp1
	add dl,7	;是0Ah~0Fh,还要加上7
aldisp1:	mov ah,2	;显示
	int 21h
	pop dx	;恢复原ax值到dx
	and dl,0fh	;转换al的低4位
	or dl,30h
	cmp dl,39h
	jbe aldisp2
	add dl,7
aldisp2:	mov ah,2	;显示
	int 21h
	pop dx
	pop cx
	pop ax
	ret	;过程返回
print_ax endp
end	start
;//APPEND END

难点: 

1.寄存器保护顺序,先保护bp,在用bp取sp,在保护寄存器,注意顺序,参数在【bp+4】的位置

2.堆栈传出口参数,注意ip的位置,ret会取栈中的元素,所以不能直接把出口参数压入栈,否则ret会出口参数赋值给ip。应该把出口参数放到入口参数的位置(利用bp随机访问)。

方案三:利用变量传递出入口参数

;PREPEND BEGIN
	.model small
	.stack
	.data
	N dw 0 ;
	result dw 0 ;
	.code
start:
	mov ah, 08h
    int 21h
    sub al, '0'
	xor ah,ah
	mov N,ax
	xor ax,ax
	call ditui1
	mov ax,result
	call print_ax
;******exit******
	mov ax, 4c00h
	int 21h
;******exit******
;PREPEND END
;TEMPLATE BEGIN
ditui1 proc
;ditui1
;***begin****    ;子程序在这里开始!!!
    push N       ;一定要保护全局变量的值!!!
    push ax
    cmp N,2      ;n为0、1、2则跳转
    je f2
    cmp N,1
    je f1
    cmp N,0
    je f0
    dec N          ;n-1
    call ditui1
    mov ax,result  ;ax存第一个结果
    dec N          ;n-1-1=n-2
    call ditui1
    add result,ax  ;f(n)=f(n-1)+f(n-2)
    jmp done
f2:
    mov result,2
    jmp done
f1:
    mov result,1
    jmp done
f0:
    mov result,0
    jmp done
done:
    pop ax             ;寄存器恢复
    pop N              ;全局变量的恢复
    ret
;****end******
ditui1 endp
;TEMPLATE END
;function: print_eax value in decimal;
;input:eax, use buffer (10 bytes)
print_ax proc
	push ax	;过程中使用了AX、CX和DX
	push cx
	push dx
	push ax	;暂存ax
	mov dl,al	;转换al的高4位
	mov cl,4
	shr dl,cl
	or dl,30h	;al高4位变成3
	cmp dl,39h
	jbe aldisp1
	add dl,7	;是0Ah~0Fh,还要加上7
aldisp1:	mov ah,2	;显示
	int 21h
	pop dx	;恢复原ax值到dx
	and dl,0fh	;转换al的低4位
	or dl,30h
	cmp dl,39h
	jbe aldisp2
	add dl,7
aldisp2:	mov ah,2	;显示
	int 21h
	pop dx
	pop cx
	pop ax
	ret	;过程返回
print_ax endp
;function end
end	start
;//APPEND END

1.每一次递归都会改变入口参数的值,如果要两次递归的话(如f(n)=f(n-1)+f(n-2)),做完n-1后记得恢复全局变量的值,与方案一很类似,其实是保证每次进入的参数是正确的的。

三种方案的核心就是每次出入子程序时要保护现在的所有参数。

第二种方案注意一定要将出口参数保存在ip前面,可以放在入口参数处。

还有一个小问题,bp[4]是非法的,只能用[bp+4]。这种访问方式只对数组的偏移首地址有用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值