如何在汇编程序x86函数调用中传递参数 [英] How can i pass parameters in assembler x86 function call
问题描述
查看此汇编代码.它是为32位x86设计的,将由nasm编译
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
我很久以前就了解到,我们可以使用堆栈在主程序和函数之间传递参数. 我希望eax包含0x08,但这是错误的,我无法解释原因. 我应该如何获取函数参数?
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 ?
推荐答案
首先,如果要与平台上的其他语言或库进行接口,请确保阅读该平台的已定义接口.可以使用多种调用机制.
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.
在您的情况下,call
指令将返回地址压入堆栈.您可以使用一些算术运算符和esp
来访问参数.由于您正在使用eax
,因此我将假定32位代码(以及32位堆栈宽度).我使用的是intel语法,因为我可以在不查找任何内容的情况下编写它:
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
请注意,当我们将堆栈对齐(如果不确定为什么会发生,在研究平台的调用标准时会很快找到它)到16字节边界时,我们甚至不会尝试找出esp
更改了多少.由于ebp
将充当我们的书签",因此我们可以让esp
移动以进行对齐或局部变量分配,而无需其他思考.
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.
在函数结尾中,我们将ebp
移回esp
,这将在调用该函数时将esp
恢复为其原始值,从而清除发生的所有本地分配和对齐操作.最后,我们pop ebp
离开堆栈,将返回地址指针作为最终值保留在函数内的堆栈上.我们现在返回.
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.
或者,可以使用返回值指定堆栈上要释放的字节数来清理堆栈(例如ret 4
).这完全取决于您的呼叫标准是指定呼叫方清除还是被呼叫方清除.
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.
这篇关于如何在汇编程序x86函数调用中传递参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!