Reputation: 4383
I wanna make recursive proc with local variables in assembly ( intel 8086 ). so I do it like following code:
MOEIN PROC NEAR
IPTEMP DW ?
NUM DW ?
POP IPTEMP
POP NUM
DEC NUM
CMP NUM,0H
JZ EXIT
PUSH NUM
CALL MOEIN
EXIT:
PUSH IPTEMP
RET
MOEIN ENDP
it should do following code:
void moein(int x)
{
x--;
if (x != 0)
moein(x);
}
but it can't do it.it will lost the back way. how could I do it by assembly like what I write in C?
Upvotes: 0
Views: 2727
Reputation: 490038
You can explicitly allocate space on the stack, or with MASM or compatible assembler you can use the LOCAL
directive to create your local variables.
Upvotes: 1
Reputation: 4199
Homework?
The main problem with your code is the fact that the declared variables (IPTEMP and NUM) are being shared by all invocations of the function, as opposed being created anew every time the function is called. Therefore, every time you recursively invoke yourself, the variables get overwritten. The way you can think of it is DW
is compile-time instruction, therefore it reserves a pice of memory during compile-time. Compiler doesn't know how many times the function will be called, therefore it has no knowledge of how many variables it has to create.
The other problem is that it messes with the stack in a wrong way. Imagine you called the function 10 times. But the amount of stack used after POP NUM
is exactly zero: you pop all its content for this instance and for every previous instance. Which means all the information about the context of last 9 instances is lost.
The simplest way to fix this is to use what's called the "stack frame" -- that's what higher-level languages do most of the time. The stack frame for each function looks like this, from top (higher addresses) to bottom (lower addresses):
Assuming we're in 16-bit mode (since there is 8086
tag), all the following will use 16-bit integers and 16-bit address arithmetic.
So, the [SP] points to the return address, therefore [SP + 2] points to the first (closest, only in your case) argument. What you need to do is to read the argument, decrement, compare and call self:
MOEIN PROC NEAR
MOV AX, [SP+2] ; read the argument from the stack
DEC AX
; you don't need CMP AX,0H here, since DEC sets the same flags
JZ EXIT
PUSH AX ; place the argument on the stack for the next call
CALL MOEIN
ADD SP, 2 ; don't forget to clean the passed argument from the stack
EXIT:
RET
MOEIN ENDP
Other variants may include:
RET 2
instruction to clear the stack: you won't need ADD SP, 2
thenBP
register for defining the stack frameAll of this is available in multiple sources -- or just read the compiled code and experiment with compiler options: you'll find many approaches there. Good luck: it's a lot of fun!
Upvotes: 2