【问题标题】:Is it possible to have an exported function in __stdcall and the name unmangled?是否可以在 __stdcall 中有一个导出的函数并且名称未损坏?
【发布时间】:2014-08-15 19:26:05
【问题描述】:

我正在开发一个项目来生成一个用于离线测试的虚拟 DLL。我们有真正的 DLL 及其头文件,尽管它们看起来不兼容。 DLL 中的名称未被破坏,但函数前向声明声明被调用为__stdcall:

example.h

DWORD __stdcall DoSomething(byte aByte);

Dependency Walker 中的example.dll:

2 (0x0002)   2 (0x0002)   DoSomething   0x000831C0

据我所知,如果可以在__stdcall 约定中导出一个函数,那么它的名称应该在dependency walker 中读取为:

2 (0x0002)   2 (0x0002)   _DoSomething@1   0x000831C0

这是否意味着我们的头文件与编译后的 DLL 不对应,还是我遗漏了什么?

最终,我如何形成虚拟函数的导出,使其行为方式与我正在模拟的真实 DLL 相同?

【问题讨论】:

    标签: c++ dll dllexport stdcall cdecl


    【解决方案1】:

    只有两种方式不获取__stdcall名称修饰:

    • 您必须使用 .def 文件来重命名导出。不使用就领先一步。

    • 您将代码构建为面向 x64。由于它只有一个调用约定,编译器将忽略您的 __stdcall 属性并且不会修饰名称。现在您需要一个 .def 文件来重命名导出。永远不要这样做,没有人会期望在 64 位代码中使用装饰。

    请注意,如果经过修饰,导出的名称将为 _DoSomething@4。名称的 @ 部分表示堆栈激活帧的大小。换句话说,在函数返回之前需要从堆栈中弹出的字节数。对于 32 位代码,它永远不能是 1,它始终是 4 的倍数。这种名称修饰存在是因为 __stdcall 非常危险,函数弹出的堆栈比预期的多或少会导致很难诊断堆栈不平衡。链接器捕获函数原型声明错误。

    【讨论】:

    • 感谢@Hans,事实证明我们使用的方法可能在所有方面都等于您的选项1,即使用#pragma 重命名导出#pragma comment(linker, "/export:DoSomething=_DoSomething@4")。感谢您对标准字节计数乘数(32 位为 4,64 位为 8)的提示,我看到的所有数字都是 4 的倍数,这似乎是一种趋势,只是假设是巧合。
    • 另外请注意,我完全不喜欢使用它,我们只是想复制专有 DLL 的功能。
    • 嗯,我想我必须编辑我的答案才能更改为 三个。我会跳过,这不是 /EXPORT 的记录功能。
    【解决方案2】:

    用于停止更改您之前使用 __stdcall 的过程名称: 如果您使用 gnu c++ 编译器,请在链接器中添加“-Wl,--kill-at”参数。

    如果你使用代码块:

    "Settings" -> "Compiler..."
    "Global compiler settings"
    "Linker settings"
    "Other linker options":
    add: "-Wl,--kill-at"
    

    如果你使用 devc++

    project->project options
    Parameters
    add "-Wl,--kill-at" to linker
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-23
      • 2012-05-07
      • 2015-09-21
      • 2017-02-13
      • 1970-01-01
      • 2016-03-18
      • 2017-04-09
      • 2019-08-09
      相关资源
      最近更新 更多