【问题标题】:How to use varargs with __stdcall without the compiler corrupting the stack如何在不破坏堆栈的编译器的情况下使用带有 __stdcall 的可变参数
【发布时间】:2015-01-08 03:56:45
【问题描述】:

我遇到了 MSVC 和 ICC 的问题:

我需要使用带有 stdcall 调用约定的可变参数,但编译器会忽略可变参数并破坏堆栈。

解决此问题的简单方法是将参数的数量作为参数之一并在其损坏之前偏移ESP,但在这种情况下,我不需要函数上下文的参数数量所以如果可能的话宁愿避免它。

有人知道有没有办法做到这一点?

【问题讨论】:

  • 默认情况下不能。当使用stdcall 时,callee 负责清理堆栈。由于 被调用者 不知道参数的数量或参数占用了多少堆栈空间,因此如果不提供其他信息,它就无法在逻辑上清理堆栈。你试图做的不是一个好主意,任何让它发挥作用的尝试都可能比它值得付出更多的努力。这听起来像是一个 XY 问题,你真的应该重新考虑你想要完成的工作。
  • @CaptainObvlious 这不是传统的功能。真正最好的解决方案是做我所要求的(如果可能的话)。但是请看我对约翰回答的回应;它解释得更多。

标签: c++ c visual-c++ icc


【解决方案1】:

根据documentation

被调用者清理堆栈,因此编译器生成可变参数函数__cdecl

鉴于此,我不确定您希望如何进行。如果stdcall 要求被调用者清理堆栈,但在可变参数函数中,被调用者在编译时无法知道堆栈中的内容,它会如何工作?您是否期望 stdarg va_list 宏来操纵调用框架?我不认为微软是这么看的,所以你问的似乎是不可能的,至少不是通过使用微软编译器编写 C。

【讨论】:

  • 在 99% 的情况下,尝试这样做是荒谬的,我同意。不幸的是,在我的函数中,它确实正确清理了堆栈,但我不能清理堆栈,因为不是我的代码在这样做。
  • @Nowayz 不要害羞,这 100% 的时间都很荒谬。
  • @CaptainObvlious 这次不是 :) 该函数是代理调用 WINAPI(stdcall) 自行清理堆栈,然后执行 jmp 回到缓存的 retn 指针,因为它必须被洗牌离开堆栈的顶部。这意味着堆栈有 100% 保证每次都被正确清理,但编译器仍然会尝试这样做。
  • @Nowayz:我不知道你为什么要与之抗争。您知道调用约定是什么以及它们需要什么。你所说的这个神奇的函数没有遵循任何约定,而是自己组成的,它不是 stdcall ......如果你想使用这个函数,你必须遵循它使用的任何约定,即使这意味着必须编写出你自己的序幕/尾声。
  • @Nowayz:Win32 API 对所有内容都使用__stdcall,除了需要__cdeclwsprintf()。您的代理也应该使用__stdcall。听起来您正试图让__cdecl 代理像​​__stdcall 一样行事,但这根本行不通。我同意 CaptainOblivious 的观点,这是一个 XY 问题。您正在寻找错误的解决方案。发布您遇到问题的代码,也许有人可以告诉您如何正确修复它。
猜你喜欢
  • 2013-08-15
  • 1970-01-01
  • 2021-01-25
  • 2014-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多