Joanna
Joanna

Reputation: 23

Recursive procedure

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

Answers (1)

Ped7g
Ped7g

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:

  • inside suma store result into [ebp+4] memory
  • return by ret (not releasing argument from stack)
  • after call suma everywhere pop ax to pick the result from stack

Or 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

Related Questions