首先,如果您希望在您的平台上与其他语言或库进行交互,请务必阅读为该平台定义的接口。可以使用多种调用机制。
在您的情况下,call 指令将返回地址推入堆栈。您可以使用一些算术和esp 来访问您的参数。由于您使用的是eax,因此我将假设使用 32 位代码(和 32 位堆栈宽度)。我使用的是 intel 语法,因为我可以在不查找任何内容的情况下编写它:
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
在您的 cmets 中,您询问此答案是否表示内存泄漏。答案是不。”原因是 调用者 负责清理它添加到堆栈中的任何内容。基于已编写的其他 cmets 的更完整示例可能如下所示:
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
请注意,当我们将堆栈(如果您不确定为什么会发生这种情况,您会在研究平台的调用标准时很快找到)对齐 16 字节边界时,我们甚至不会尝试弄清楚esp 发生了多少变化。由于ebp 将充当我们的“书签”,我们可以让esp 移动以进行对齐或局部变量分配,而无需再考虑。
在函数尾声中,我们将ebp 移回esp,这会将esp 恢复为其调用函数时的原始值,从而清除已发生的任何本地分配和对齐操作。最后,我们将pop ebp 移出堆栈,将返回地址指针作为函数内堆栈上的最终值。我们现在回来了。
回来后,我们用砰的一声清理干净。
或者,可以通过返回指定要在堆栈上释放的字节数来清理堆栈(例如ret 4)。这完全取决于您的调用标准是指定调用者清理还是被调用者清理。