I'm trying to make a subprogram in assembly which will draw a square on the screen. I don't think I can pass parameters to the subprogram like I would do in C++, so I figured that I could use stack to store and access the parameters (I can't use the common data registers because there are too many variables to pass).
The problem is (I remember reading somewhere) that when I use the call command to the address of the current "program" it is saved on the stack, so that when it's used the "ret" command it would know where to return. But if I store something on the stack and then call the function, I will have to save somewhere the address (that is on the top of stack) and then safely pop the parameters. Then after the code has finished and before calling "ret", I would have to push back the address.
Am I right? And, if yes, where can I store the address (I don't think the address is only 1 byte long so that it would fit in AX or BX or any other data register). Can I use IP to do this (although I know this is used for something else)?
This is what I imagine:
[BITS 16]
....
main:
mov ax,100b
push ax
call rectangle ;??--pushes on the stack the current address?
jml $
rectangle:
pop ax ;??--this is the addres of main right(where the call was made)?
pop bx ;??--this is the real 100b, right?
....
push ax
ret ;-uses the address saved in stack
Typically, you use the base pointer (bp
on 16 bit, ebp
on 32 bit) to refer to parameters and locals.
The basic idea is that every time you enter into a function you save the stack pointer inside the base pointer, to have the stack pointer at when the function was called as a "fixed reference point" throughout execution of the function. In this schema [ebp-something]
typically is a local, [ebp+something]
is a parameter.
Transposing the typical 32-bit, callee-cleanup calling conventions you can do like this:
caller:
push param1
push param2
call subroutine
subroutine:
push bp ; save old base pointer
mov bp,sp ; use the current stack pointer as new base pointer
; now the situation of the stack is
; bp+0 => old base pointer
; bp+2 => return address
; bp+4 => param2
; bp+6 => param1
mov ax,[bp+4] ; that's param2
mov bx,[bp+6] ; that's param1
; ... do your stuff, use the stack all you want,
; just make sure that by when we get here push/pop have balanced out
pop bp ; restore old base pointer
ret 4 ; return, popping the extra 4 bytes of the arguments in the process