问题
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?
回答1:
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 beadd 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, useadd 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
.
回答2:
I listed some ways to remove things from the stack in this answer: Can I POP a value from the stack, but put it nowhere in NASM Assembly?, to summarise:
add rsp, x
lea rsp, [rsp + x]
mov rsp, rbp
(also part ofleave
)lea rsp, [rbp - x]
popping into otherwise unused registers
Other than that, whether you should remove parameters from the stack in the caller is determined by whether your calling convention mandates caller clean-up or the opposite, callee cleanup. Callee cleanup is done by specifying the number of bytes to remove from the stack as an immediate operand to the retn
instruction. For example:
...
; caller code
push rax
push rdi
call testfunction
...
; function code
testfunction:
push rbp
mov rbp, rsp
mov rcx, qword [rbp + 16]
...
mov rsp, rbp
pop rbp
retn 16
来源:https://stackoverflow.com/questions/60830765/nasm-should-i-pop-function-argument-after-calling-a-function