Reputation: 23
I was supposed to write recursive procedure that calculates the sum of numbers divisible by 3 in a given range. At first, two-digit number N is being read from keybord and that gives us the 1 to N range. The N number is passed to the procedure via stack. Also, the sum of the numbers in the range should be returned via stack. The thing is, I couldn't manage to return the sum through the stack. So, a little help won't hurt. Here's the code:
data segment
n dw ?
sum dw ?
ends
stack segment
dw 128 dup(0)
ends
code segment
start:
mov ax,@data
mov ds,ax
mov es,ax
mov cx,3
mov ah,1
int 21h
sub al,30h
mov ah,0
mov bx,10d
mul bx
mov n,ax
mov ah,1
int 21h
sub al,30h
mov ah,0
add n,ax
mov ax,n
push ax
call suma
mov ax, 4c00h
int 21h
suma proc
push bp
mov bp,sp
mov ax,[bp+4]
cmp ax,1
je l1
dec ax
push ax
call suma
mov ax,[bp+4]
push ax
div cl
cmp ah,0
pop ax
JNE l1
add sum,ax
L1:
pop bp
ret 2
suma endp
ends
end start
Upvotes: 1
Views: 74
Reputation: 16586
As Jester points out, that's silly task, but you should be able to resolve it any way, if you understand stack well.
Your current code does:
; For example let's say sp = 54 (address 54 in memory)
push ax ; store argument n, sp = 52
call suma ; do the call
; inside suma under the argument there are pushed also
; return address by CALL, sp =50
; and old bp by PUSH bp, sp = 48
; then [sp+4] points to argument n (48+4 = 52)
; stack is restored by the function ("ret 2"), sp = 54
Now if you want to place result on the stack, you must reserve the stack space from the point of view of caller, because after the suma
returns, the sp
is restored to "54" in my example, and anything written on the stack from suma
call on lower sp
address may be already overwritten (for example if interrupt happened between ret 2
and your next instruction, then the interrupt did use the stack memory below address 54, overwriting it). And anything written into memory at address 54+ would survive for caller, but destroy the values which caller had stored there.
BTW, your current code in question doesn't return result in ax
, as it overwrites it itself while doing recursion in wrong way, and cumulates result in memory at address sum
, which is not initialized by suma
, so it will work only once. It's possible to write it in such way, that the recursion will return correct sum even for multiple calls (by zeroing total sum first, then calling F(n-1) and adding "n" as needed to result of that F(n-1)).
So either decide, that the value will be returned in place of the argument n, then you have to:
suma
store result into [ebp+4]
memoryret
(not releasing argument from stack)call suma
everywhere pop ax
to pick the result from stackOr reserve stack space above argument, like:
sub sp,2 ; make space for result in stack
; you can also use another bogus "push ax", not caring about value, just adjusting sp
push ax ; push argument n
call suma
pop ax ; read result + restore stack
Then inside suma
you have to store result into [bp+6]
, ret 2
stays as is, releasing only the argument.
Either way, the stack space must be reserved by caller, as any stack space not reserved (below current value of sp
) may be overwritten any time by interrupt handler (in x86 16b real mode).
Upvotes: 3