8

我刚开始修补 ASM,我不确定我对过程调用的理解是否正确。

在代码中的某个位置说有一个过程调用

call dword ptr[123]

该过程仅包含一个命令 ret:

ret 0004

这个过程调用会产生什么影响,返回值将存储在哪里?我在某处读到 2 个字节的返回值将存储在 AX 中,但是当我将过程调用替换为

mov AX, 0004

(连同必要的 NOP)程序崩溃。

4

4 回答 4

12

在 x86 汇编程序中,ret指令的参数意味着:

RET immediate

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

(引自Intel® 64 and IA-32 Architectures Software Developer's Manuals Vol 2B

所以当你输入:

ret 0004

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

push eax
call dword ptr[123]

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

所以你的调用代码是:

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

您返回值 4 的函数将是:

mov eax, 4
ret
于 2009-08-09T10:33:35.273 回答
2

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

例如,在C 调用约定中,返回值将在 EAX/AX/AL 中。您的单指令没有:它是一个 void 函数,采用大约 4 个字节的参数(可能是单个 int),什么都不做。由于在此调用约定中清理堆栈是被调用方的职责,因此忽略这样做并用“mov ax”替换调用是行不通的。

此外,我怀疑您在阅读 16 位文档时可能正在修补 32 位汇编。这不是一个大问题,但你应该意识到这些差异。

于 2009-08-09T11:00:06.373 回答
1
// 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。


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

于 2009-08-09T10:17:20.423 回答
-1

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

于 2009-08-09T10:04:44.240 回答