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
15.4.3 Passing Parameters via the StackThe stack is usually the preferred way to pass arguments to a subroutine. Although this technique is a bit more involved once you get it right, it is bullet proof, and allows one to pass as many parameters to a subroutine as desired.
The caller uses registers to pass the first 6 arguments to the callee. Given the arguments in left-to-right order, the order of registers used is: %rdi, %rsi, %rdx, %rcx, %r8, and %r9. Any remaining arguments are passed on the stack in reverse order so that they can be popped off the stack in order.
Parameter passing involves passing input parameters into a module (a function in C and a function and procedure in Pascal) and receiving output parameters back from the module. For example a quadratic equation module requires three parameters to be passed to it, these would be a, b and c.
To call an external function, such as NetRun's "print_int", or a standard C library function like "exit", you need to tell the assembler the function is "extern". "extern" isn't actually an instruction--it doesn't show up in the disassembly--it's just a message to the assembler, often called a pseudoinstruction.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With