汇编程序中的过程调用如何工作?

发布于 2024-08-01 19:21:25 字数 312 浏览 5 评论 0原文

我刚刚开始摆弄 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夜雨飘雪 2024-08-08 19:21:25

在 x86 汇编器中,ret 指令的参数表示:

RET immediate

返回调用过程并从堆栈中弹出立即字节。

(引自英特尔® 64 和 IA-32 架构软件开发人员手册 < a href="http://www.intel.com/Assets/PDF/manual/253667.pdf" rel="noreferrer">Vol 2B)

因此,当您键入时:

ret 0004

您是在告诉 CPU 返回立即调用调用之后的指令,并从堆栈中弹出 4 个字节。 如果您在调用之前压入 4 个字节到堆栈中,那就太好了。

push eax
call dword ptr[123]

请注意,这与返回值无关。 事实上,Assembly 中的过程无法指定某个值是返回值。 这都是按照惯例完成的。 据我所知,大多数编译器都会使用 EAX 来保存返回值,但这只是因为调用函数会期望那里的结果。

因此,您的调用代码将是:

call dword ptr [123]
mov dword ptr [result], eax

返回值 4 的函数将是:

mov eax, 4
ret

in x86 assembler the parameter to the ret instruction means:

RET immediate

Return to calling procedure and pop immediate bytes from the stack.

(quoting from Intel® 64 and IA-32 Architectures Software Developer's Manuals Vol 2B)

So when you type:

ret 0004

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.

push eax
call dword ptr[123]

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:

call dword ptr [123]
mov dword ptr [result], eax

and your function that returns the value 4 would be:

mov eax, 4
ret
土豪我们做朋友吧 2024-08-08 19:21:25

这完全取决于所使用的调用约定。 我不会在这里重复维基百科的文章,只需阅读定义即可。

例如,在 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.

邮友 2024-08-08 19:21:25

我认为返回值没有存储在寄存器AX中

I don't think the return value is stored in the register AX

猫性小仙女 2024-08-08 19:21:25
// possibly there are arguments pushed here
...
call dword ptr[123] // push next OP code offset in the stack and jump to procedure

// procedure
...
ret 0004 // pop offset, set EIP to that offset and decrease ESP by 4

如果我们在调用过程之前将参数推送到堆栈中,那么我们另外会减少 ESP。

如果有压入的参数,您的程序会崩溃,因为您没有弹出它们。 当前过程的返回偏移量将是错误的,因为它将从推送的参数之一获取一个值作为偏移量。

// possibly there are arguments pushed here
...
call dword ptr[123] // push next OP code offset in the stack and jump to procedure

// procedure
...
ret 0004 // pop offset, set EIP to that offset and decrease ESP by 4

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文