How can I pass parameters in assembler x86 function call?
Asked Answered
Z

3

18

Look at this assembler code. It is designed for 32 bits x86 and will be compiled by nasm

   ...
   my_function:
        pop %eax
        ...
        ret


   main:
       push 0x08
       call my_function

I have learned a long time ago that we can use stack for passing parameters between main program and functions.

I would expect that eax contains 0x08, but this is false and I can not explain why.

How should I do for fetching my function parameters ?

Zitazitah answered 22/6, 2016 at 17:58 Comment(1)
Look at his other answer. The problem is that CALL puts the return address on the stack, and that is what you will find in EAX with your code.Unmade
L
30

Firstly, if you are looking to interface with other languages or libraries on your platform, be sure to read the defined interface for that platform. There are a variety of calling mechanisms that might be used.

In your case, the call instruction is pushing the return address onto the stack. You can access your parameter by using some arithmetic and esp. I will assume 32 bit code (and a 32 bit stack width) since you are using eax. I'm using intel syntax since I can write that without looking anything up:

my_function:
    mov eax, [esp+4]    ; Move the contents of ESP+4 into EAX
                        ; ESP should be pointing at the 32 bit RIP.
                        ; ESP+4 should be the pushed parameter.
    ...
    ret


main:
   push 0x08
   call my_function

In your comments you ask, regarding this answer, if this represents a memory leak. The answer is "No." The reason is that the caller is responsible to clean up anything that it adds to the stack. A more complete example based on the other comments that have been written might look like this:

my_function:
    push ebp            ; Store the current stack frame
    mov  ebp, esp       ; Preserve ESP into EBP for argument references
    and  esp, 0xfffffff0; Align the stack to allow library calls
    mov  eax, [ebp+8]   ; Move the contents of EBP+8 into EAX
                        ; [EBP] should be the saved 32 bit EBP.
                        ; [EBP+4] should be the 32 bit EIP (return address).
                        ; [EBP+8] should be the pushed parameter.
    ...                 ; Do lots of cool stuff
    mov  esp, ebp       ; Restore the stack and ebp
    pop  ebp
    ret


main:
   push 0x08
   call my_function
   pop ebx              ; Clean up the stack

Notice that when we align the stack (if you're not sure why this is happening, you will quickly find it when you research the calling standard for your platform) to a 16 byte boundary, we don't even try to figure out how much esp has changed. Since ebp will act as a "bookmark" for us, we can let esp move for alignment or perhaps local variable allocation without another thought.

In the function epilogue we move ebp back into esp, which restores esp to its original value when the function was called, thus cleaning up any local allocations and alignment operations that have happened. Finally, we pop ebp off of the stack, leaving the return address pointer as the final value on the stack within the function. We now return.

After returning we clean up with a pop.

Alternatively, it is possible to clean up the stack with a return specifying the number of bytes to free on the stack (eg ret 4). It all depends on whether your calling standard specifies caller cleanup or callee cleanup.

Lolalolande answered 22/6, 2016 at 21:52 Comment(5)
Thanks David but in your case you never call pop. Don t you think it is a memory leak?Zitazitah
@Bob5421: Usually it's up to caller (after call my_function) to do the pop. This is just shortest example of how to access the stack parameter in the function inside, it's not an complete example. So yeah, it would "leak".Seline
I have disassemble some elf executables. Sometimes i see they change esp value directly. I suppose it is the same thing that pop/push (except they do not fetch or add value). I also see ebp. I suppose the real memory address for stack éléments is at ebp+esp ?Zitazitah
ESP is changed directly to allocate space on the stack. EBP is usually used to track the original EBP value when the function is called so that the stack can be cleaned up easily. The value of EBP is typically stored onto the stack as a part of the function preamble, so in normal use you should expect to see things on the stack at +8. At this point you have described a typical "stack frame." The biggest thing for you to know, though, is that passing things on the stack is not typical. These days, most interfaces prefer to pass using registers, which is faster since no pushes and pops are...Lolalolande
...required. This is why I recommend that you look up the calling standard for the platform on which you will be working!Lolalolande
B
8

In Addition to David answers, this is another example

push 0       ; fourth parameter
push 4       ; third parameter
push 4       ; second parameter
push [eax]   ; first parameter
call printf

Same in C or C++ as

somefunction(first,second,third,fourth);
Booty answered 3/12, 2019 at 23:56 Comment(0)
A
0

See below for explanation:-

[BITS 32]

%include "nagoa+.inc"

%include "cfunctions.txt"

[SEGMENT .DATA USE32]

    ret_value   db  "I am the Return Value",0
    localvar    db  "My Local Variable Value",0

[SEGMENT .BSS USE32]
    arg_param   resb    160


[SEGMENT .TEXT USE32]

my_function:
    ;save arguments/parameters as this esp+ space will be destroyed by system function calls
        mov eax,[esp+4]

    ;enjoy local variables for processing
    ;enter 4,0 
        mov dword [esp-4],localvar

        call printf,`Argument/Parmeter=%s  and Local Variable=%s`,eax,[esp-4]
        add esp,12
    ;leave

    ;fill-up return values
        mov eax,ret_value

    ret 
    ;ret 4

..start:
    call puts,`Enter Argument/Parmeter`
    add esp,4
    call gets,arg_param
    add esp,4

    push arg_param
    CALL my_function

    call printf,`Return Value From Called Function=%s`,eax
    add esp,4

call exit, 0
Anoint answered 30/3, 2019 at 20:31 Comment(2)
Storing to [esp-4] isn't safe: it can (at least in theory) be clobbered asynchronously, unless you're using a custom system / calling convention with a red-zone for 32-bit code. Also, what assembler is this where extra operands to call magically get pushed for you? (And string constants created from string literals for you?) Also, the final printf has 2 args, but only does add esp,4 not 8.Noseband
@Booty Cordes: This is NASM source which uses the macro collection nagoa+.inc. The call_ macro (with %define call call_ which means that capitalised CALL does not invoke the macro) indeed implements pushing parameters to the stack that are specified after the call destination, and creating constants from string literals whose address is pushed.Tungusic

© 2022 - 2024 — McMap. All rights reserved.