【问题标题】:MSVS 2010 C++ Compiler and Stack alignment issue?MSVS 2010 C++ 编译器和堆栈对齐问题?
【发布时间】:2012-07-01 00:07:31
【问题描述】:

我的问题是 MSVS 2010 C++ 编译器在从另一个 dll 的运行时解析的函数调用 (GetProcAddress+GetModuleHandle) 返回后以某种方式生成代码,然后编译器尝试以这种方式对齐堆栈:

   CALL DWORD PTR DS:[2000367C]             ;  apiresolvedinruntime.dll
   ADD ESP,12                               ;  <- this is the stack alignment

这当然是覆盖了返回地址,我的程序崩溃了,有人能解释一下为什么编译器在不应该这样做的时候对齐堆栈吗?

【问题讨论】:

  • 请贴出(a)模块中函数的声明,(b)如何通过GetProcAddress获取函数指针,以及(c)如何调用函数。
  • 听起来像是调用约定不匹配:__stdcall vs. __cdecl,也许。您是否使用与您正在调用的函数匹配的类型正确地注释了函数指针的类型?

标签: c++ visual-studio assembly calling-convention


【解决方案1】:

您没有使用正确的调用约定来调用运行时加载的函数。调用约定指定堆栈发生的默认处理。最有可能的是,DLL 是使用 __stdcall 调用约定(例如 Windows DLL 使用的)编译的,它指定被调用的函数应该清理堆栈,但调用代码是使用函数指针声明的__cdecl 调用约定(这是默认设置)。在__cdecl下,函数支持可变参数,所以调用者需要做堆栈的清理,因为被调用的函数不知道传递了多少参数。

您需要验证 DLL 和调用代码是使用相同的调用约定编译的。

【讨论】:

  • FWIW,这个问题在 x64 上被掩盖了,因为这两个调用约定在 Windows x64 ABI 中是相同的。
  • @Reuben:那是因为在 amd64 上有一个标准的调用约定(相当于 x86 上的__fastcall)。 x86 从来没有标准的调用约定。 (__fastcall 在 x64 处理器上更有用,因为可用的寄存器更多)
  • 是的,我知道 :) 我只是将这些信息留在这里作为问题的背景材料。 FWIW,虽然它本着 x86 上 __fastcall 的精神,但据我所知,它并不完全等同;堆栈对齐方式、可以放入寄存器的 args 数量、寄存器中 args 所需的溢出空间等似乎都不同。
  • 你说得对,使用第三方软件简直就是地狱,不同的调用约定是个问题,谢谢
  • @reuben:是的,它完全不一样——但它的工作方式是一样的。 (也就是说,很多参数是通过寄存器而不是堆栈传递的)不同之处在于长模式下的对齐要求和长模式下可用的寄存器更多。
猜你喜欢
  • 1970-01-01
  • 2022-10-17
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-29
  • 2015-01-08
相关资源
最近更新 更多