X86 build: pass function parameter via stack

I am trying to make a subroutine in an assembly that will draw a square on the screen. I don’t think that I can pass parameters to the subroutine, as I would do in C ++, so I decided that I could use the stack to store and access parameters (I cannot use shared data registers, because there are too many variables to pass through )

The problem is that when I use the call command to the address of the current "program", it is saved on the stack, so when she used the "ret" command, she knew where to return. But if I store something on the stack and then call the function, I will have to save the address somewhere (that is, on the top of the stack) and then set the parameters safely. Then, after completing the code and before calling ret, I will have to move the address.

I'm right? And, if so, where can I save the address (I don’t think the address is only 1 byte long, so that it matches AX or BX or any other data register). Can I use IP for this (although I know that it is used for something else)?

Here 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 
+6
source share
3 answers

Typically, you use a base pointer ( bp to 16 bits, ebp to 32 bits) to refer to parameters and locals.

The basic idea is that every time you enter a function, you save the stack pointer inside the base pointer to have a stack pointer when the function is called as a “fixed reference point” during the execution of the function. In this scheme, [ebp-something] usually local, [ebp+something] is a parameter.

Transpose typical 32-bit calling calling conventions, which you can do as follows:

subscriber:

 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 param2 mov bx,[bp+6] ; that 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 
+9
source

This will work, except from the perspective of the caller, your function modifies sp . In the 32-bit procedure of most calls, functions are only allowed to change eax/ecx/edx and must save / restore other registers if they want to use them. I assume 16 bit is similar. (Although, of course, in asm you can write functions with any conditional calling conventions that you like.)

Some calling conventions expect the caller to call the arguments invoked by the caller, so this will actually work. Matteo's ret 4 answer does this. (See x86 wiki tags for information on calling conventions and many other good links.)


This is super-weird and not the best way to do something, so it is usually not used. The biggest problem is that it gives you access to parameters in order, not random access . You can only access the first 6 or so, because you have run out of registers to insert them.

It also binds the register containing the return address. x86 (before x86-64) has very few registers, so this is really bad. You can push the return address after, apparently, you can add another args function to the registers to free it for use.

jmp ax will technically work instead of push / ret , but it defeats the return address predictor, slowing down future ret instructions.


But in any case, creating a stack frame with push bp / mov bp, sp universally used in 16-bit code, because it is cheap and gives you random access to the stack . ( [sp +/- constant] not a valid 16-bit addressing mode (but it is in 32 and 64 bits). ( [bp +/- constant] is valid). Then you can reload them when you need to.

In 32 and 64-bit code for compilers, the addressing mode is usually used, for example [esp + 8] or something else, instead of wasting instructions and binding ebp . ( -fomit-frame-pointer by default). This means that you need to track changes in esp in order to work out the correct bias for the same data in different instructions, so it is not popular in handwritten asm, esp in textbooks / training materials. In real code, you obviously do everything that is most efficient, because if you are willing to sacrifice efficiency, you just use the C compiler.

+3
source

I don’t think I can pass parameters to the subroutine, as I would in C ++ [...]

To pass parameters to a subroutine, you can do the following trick, as shown in the example below:

 .486 assume cs:code, ds:data, ss:stack macro_for_subroutine macro parameter1, parameter2 push parameter1 ; [bp+6] push parameter2 ; [bp+4] call subroutine ; [bp+2] (return address pushed onto the stack) endm stack segment use16 para stack db 256 dup(' ') stack ends data segment use16 value1 dw 0 value2 dw 0 data ends code segment use16 para public 'code' start: main proc far ; set up stack for return push ds mov ax, 0 push ax ; ---- ; set DS register to data segment mov ax, data mov ds, ax macro_for_subroutine 1111h, 2222h ret ; return to DOS main endp subroutine proc near push bp ; [bp+0] mov bp, sp push ax push bx mov ax, [bp+6] ; parameter1 mov value1, ax mov bx, [bp+4] ; parameter2 mov value2, bx pop bx pop ax pop bp ret 4 ; return and then increase SP by 4, because we ; pushed 2 parameters onto the stack from the macro subroutine endp code ends end start 

Note: this is written in a 16-bit MASM DOS assembly.

Macros can take parameters. Therefore, by defining a macro for a particular subroutine, you can simulate a subroutine call with parameters. Inside the macro, you push the parameters on the stack in the correct order and then call the subroutine.

You cannot pass string variables, but you can pass their offset (for more details see: assembly x86 - masm32: problems with moving a variable onto the stack ).

0
source

All Articles