通过 EBP 和 ESP 清理了解 STDCALL 与 CDECL 的概念

问题描述 投票:0回答:1

我相信我理解 STDCALL 和 CDECL 之间的区别,但我想知道是否可以在这段代码中找到一些说明。

我理解在 STDCALL 中 CALLEE 负责清理堆栈,并且我理解在 CDECL 中 CALLER 负责清理堆栈。

我也理解“清理堆栈”基本上意味着重新设置堆栈指针,但我想我的混乱出现在这行代码中,其中 esp 的值被移动到基指针 ebp 中。如果该功能发生,这与“清理堆栈”是一样的吗?或者它必须是专门进入 ESP 的东西吗?

这是我正在查看的代码

main PROC
    push 4
    push 5
    call sub_12
    push 5
    call sub_48
    add esp, 4
    INVOKE ExitProcess, 0
main endp

sub_12 PROC
    push ebp
    mov ebp, esp
    mov eax, 10
    mul DWORD PTR [ebp+12]
    pop ebp
    ret 8
sub_12 endp

sub_48 PROC
    push ebp
    mov ebp, esp
    mov eax, [ebp+8]
    mul DWORD PTR [ebp+8]
    pop ebp
    ret
sub_48 endp

我原来的答案是sub_12和sub_48都是CDECL,因为Caller负责清理堆栈。但现在我一直在查看 [mov ebp, esp] 指令,我想知道这是否实际上是 STDCALL 的示例。

有人对我有任何提示或一些我可能缺乏的额外信息吗?

assembly x86 callstack calling-convention stdcall
1个回答
0
投票

这里有一个关于 CDECL 与 STDCALL 的很好的讨论:

stdcall 和 cdecl

无论调用约定如何,被调用者通常都会将当前堆栈指针保存到帧指针(EBP),以便他可以随意将局部变量推入堆栈或从堆栈中拉出。

当他准备返回时,被调用者必须然后恢复堆栈指针(ESP)以便“返回”成功。

附加信息

有两个问题:1)调用子例程(这部分是“stdcall”与“cdecl”(除其他外 - 这不是唯一的两个选项),2)从子例程返回。

CDECL 和 STDCALL 之间的主要区别在于谁负责在“返回”时清理堆栈中的局部变量。

被调用者ALWAYS恢复堆栈指针。这是“返回”可以正常工作的唯一方法。

对于 STDCALL,被调用者 ALSO 清除其自己的局部变量的堆栈。

粗略地说:

  • STDCALL 可能使用稍少的空间,因为“清理代码”仅存在于一个位置:在被调用者中。对于 CDECL 调用,必须在调用子例程的所有地方重复清理操作。您的示例 sub_12 是“STDCALL”。

  • CDECL 更灵活:它允许您将可变数量的参数传递到子例程中。您的示例 sub_48 是“CDECL”。

© www.soinside.com 2019 - 2024. All rights reserved.