汇编程序中的过程调用如何工作?
我刚刚开始摆弄 ASM,我不确定我对过程调用的理解是否正确。
假设在代码中的某个时刻有一个过程调用
call dword ptr[123]
,并且该过程仅包含一个命令 ret:
ret 0004
此过程调用的效果是什么,返回值将存储在哪里? 我在某处读到 2 个字节的返回值将存储在 AX 中,但是当我用(以及必要的 NOP)替换过程调用时,
mov AX, 0004
程序崩溃了。
I just started tinkering with ASM and I'm not sure if my understanding of procedure calls is correct.
say at some point in the code there is a procedure call
call dword ptr[123]
and the procedure consists of only one command, ret:
ret 0004
what would be the effect of this procedure call, and where would the return value be stored? I read somewhere that a return value of 2 bytes would be stored in AX, but when I replace the procedure call by
mov AX, 0004
(together with the necessary NOPs) the program crashes.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在 x86 汇编器中,
ret
指令的参数表示:RET immediate
(引自英特尔® 64 和 IA-32 架构软件开发人员手册 < a href="http://www.intel.com/Assets/PDF/manual/253667.pdf" rel="noreferrer">Vol 2B)
因此,当您键入时:
您是在告诉 CPU 返回立即调用
调用
之后的指令,并从堆栈中弹出 4 个字节。 如果您在调用之前压入 4 个字节到堆栈中,那就太好了。请注意,这与返回值无关。 事实上,Assembly 中的过程无法指定某个值是返回值。 这都是按照惯例完成的。 据我所知,大多数编译器都会使用 EAX 来保存返回值,但这只是因为调用函数会期望那里的结果。
因此,您的调用代码将是:
返回值 4 的函数将是:
in x86 assembler the parameter to the
ret
instruction means:RET immediate
(quoting from Intel® 64 and IA-32 Architectures Software Developer's Manuals Vol 2B)
So when you type:
You're telling the CPU to return to the instruction immediately after the
call
, and to pop 4 bytes off the stack. This is great if you pushed 4 bytes onto the stack before the call.Note that this has nothing to do with the return value. In fact, a procedure in Assembly has no way of specifying that a value is a return value. This is all done by convention. Most compilers of which I am aware will use
EAX
to hold the return value, but this is true only because the calling function will expect the result there.So your calling code would be:
and your function that returns the value 4 would be:
这完全取决于所使用的调用约定。 我不会在这里重复维基百科的文章,只需阅读定义即可。
例如,在 C 调用约定中,返回值将位于 EAX/AX 中/AL。 您的单指令没有:它是一个 void 函数,带有大约 4 个字节的参数(可能是一个 int),不执行任何操作。 由于在此调用约定中清理堆栈是被调用者的责任,因此忽略此操作并将调用替换为“mov ax”是行不通的。
另外,我怀疑您在阅读 16 位文档时可能会修改 32 位程序集。 这不是一个大问题,但您应该意识到其中的差异。
It all depends on the calling convention being used. I won't repeat the Wikipedia article here, just read the definition.
In the C calling convention, for example, the return value would be in EAX/AX/AL. Your single-instruction does not have one: It is a void function taking around 4 bytes of parameters (possibly a single int) that does nothing. As it is the callee's duty to clean up the stack in this calling convention, ignoring to do that and replacing the call with a 'mov ax' does not work.
Also I suspect you may be tinkering with 32-bit assembly while reading a 16-bit document. It's not a big problem, but you should be aware of the differences.
我认为返回值没有存储在寄存器AX中
I don't think the return value is stored in the register AX
如果我们在调用过程之前将参数推送到堆栈中,那么我们另外会减少 ESP。
如果有压入的参数,您的程序会崩溃,因为您没有弹出它们。 当前过程的返回偏移量将是错误的,因为它将从推送的参数之一获取一个值作为偏移量。
we additionally decrease the ESP if we had pushed arguments in the stack prior calling the procedure.
If there are pushed arguments, your program crashes because you don't pop them. The return offset for the current procedure will be wrong since it will get a value from one of the pushed arguments as the offset.