Let's say I have a nasm function like this:
inc:
mov rax,[rsp + 8]
add [rax],BYTE 1
ret
And I am calling this function like this:
push some_var
call inc
I want to pass an argument to the function through the stack, so I push some_var
and then call my function. In the function my item is second on the stack so I take it like: mov rax,[rsp+8]
My question is: after calling function should I somehow pop my argument from the stack? If so, can I somehow delete it from the stack, I mean pop it, but not to register? (Because I don't need this argument anymore.)
UPDATE: I found that I can simply add rsp,8
and that's how I can remove item from stack. But is that good practice? To remove the argument from the stack after calling function?
Best practice is to pass args in registers like the standard x86-64 calling conventions that compilers use. e.g. x86-64 System V passes the first 6 integer/pointer args in registers, so your function would be
add byte [rdi], 1
/ ret
, and not need any cleanup.
The caller would only need mov edi, some_var
or lea rdi, [rel some_var]
.
(Basics of user-space function calling documented in What are the calling conventions for UNIX & Linux system calls on i386 and x86-64 even though the title mentions system calls. Full details in https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI. It's also handy to actually look at what compilers do for simple C functions: see How to remove "noise" from GCC/clang assembly output?)
If you do need to pass a stack arg, popping it into a dummy register like pop rcx
can actually be more efficient than add rsp, 8
, for similar reasons to why compilers sometimes use a dummy push
to reserve one qword stack slot / re-align the stack by 16: Why does this function push RAX to the stack as the first operation? But if you have more than 1 stack arg for the caller to clean up, use
add rsp, 8 * n
where n
is the number of stack slots.
It's also possible to have the callee clean the stack by using ret 8
. But that defeats the chance for you to have the caller leave the stack space allocated and do mov
stores into it, e.g. in preparation for another call
.