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

时间:2009-08-09 09:59:06

标签: assembly x86 call function-calls

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

在代码中的某个时刻说有一个过程调用

call dword ptr[123]

并且该过程只包含一个命令ret:

ret 0004

此过程调用会产生什么影响,返回值将存储在何处?我在某处读到了一个2字节的返回值将存储在AX中,但当我用

替换过程调用时
mov AX, 0004

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

4 个答案:

答案 0 :(得分:12)

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

RET immediate

  

返回调用过程并从堆栈中弹出 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中的过程无法指定值是 return 值。这都是按惯例完成的。我所知道的大多数编译器都会使用EAX来保存返回值,但这只是因为调用函数会在那里得到结果。

所以你的主叫代码是:

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

并且返回值4的函数将是:

mov eax, 4
ret

答案 1 :(得分:2)

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

例如,在C calling convention中,返回值将在EAX / AX / AL中。你的单指令没有一个:它是一个void函数,占用大约4个字节的参数(可能是一个int),什么都不做。因为被调用者有责任在这个调用约定中清理堆栈,忽略这样做并用'mov ax'替换调用不起作用。

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

答案 2 :(得分: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。


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

答案 3 :(得分:-1)

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