C++ DLL 导出:修饰/损坏的名称
使用模块定义文件 (MyDLL.def) 创建基本的 C++ DLL 并导出名称。 编译后,我使用 dumpbin.exe 检查导出的函数名称 我期望看到:
SomeFunction
但我看到的是:
SomeFunction = SomeFunction@@@23mangledstuff#@@@@
为什么?
导出的函数看起来未修饰(特别是与不使用 Module Def 文件相比),但其他内容又如何呢?
如果我对任何商业应用程序中的 DLL 使用 dumpbin.exe
,您会得到干净的:
SomeFunction
并且没有其他内容...
我还尝试删除模块定义并使用“C”样式导出名称导出,即:(
extern "C" void __declspec(dllexport) SomeFunction();
仅使用“extern”C”没有创建导出函数)
但是,这仍然会创建相同的输出,即:
SomeFunction = SomeFunction@@@23mangledstuff#@@@@
我还尝试了 #define dllexport __declspec(dllexport)
选项和创建一个 LIB 没有问题。但是,我不想向在 C# 应用程序中使用该 DLL 的人提供 LIB 文件。
它是一个普通的 C++ DLL(非托管代码),只用 C++ 编译,只是一个简单的标头。和代码。如果没有 Module Def,我会得到损坏的导出函数(我可以创建静态库并使用 LIB,没有问题。我试图避免这种情况)。 code> OR 模块定义 我得到的似乎是未修饰的函数名称...唯一的问题是它后面跟着一个“=”以及看起来像是该函数的修饰版本。我想去掉“=”之后的东西 - 或者至少理解它为什么在那里。
就目前情况而言,我非常确定我可以使用 P/Invoke 从 C# 调用该函数...我只是想避免“=”末尾的垃圾。
我愿意接受有关如何更改项目/编译器设置的建议,但我只是使用标准 Visual Studio DLL 模板 - 没什么特别的。
Created basic C++ DLL and exported names using Module Definition file (MyDLL.def).
After compilation I check the exported function names using dumpbin.exe
I expect to see:
SomeFunction
but I see this instead:
SomeFunction = SomeFunction@@@23mangledstuff#@@@@
Why?
The exported function appears undecorated (especially compared to not using the Module Def file), but what's up with the other stuff?
If I use dumpbin.exe
against a DLL from any commercial application, you get the clean:
SomeFunction
and nothing else...
I also tried removing the Module Definition and exporting the names using the "C" style of export, namely:
extern "C" void __declspec(dllexport) SomeFunction();
(Simply using "extern "C" did not create an exported function)
However, this still creates the same output, namely:
SomeFunction = SomeFunction@@@23mangledstuff#@@@@
I also tried the #define dllexport __declspec(dllexport)
option and created a LIB with no problem. However, I don't want to have to provide a LIB file to people using the DLL in their C# application.
It's a plain vanilla C++ DLL (unmanaged code), compiled with C++ nothing but a simple header and code. Without Module Def I get mangled exported functions (I can create a static library and use the LIB no problem. I'm trying to avoid that). If I use extern "C" __declspec(dllexport)
OR a Module Definition I get what appears to be an undecorated function name... the only problem is that it is followed by an "=" and what looks like a decorated version of the function. I want to get rid of the stuff after the "=" - or at least understand why it is there.
As it stands, I'm pretty certain that I can call the function from C# using a P/Invoke... I just want to avoid that junk at the end of the "=".
I'm open to suggestions on how to change the project/compiler settings, but I just used the standard Visual Studio DLL template - nothing special.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
不使用 .def 文件,只需像这样插入
pragma comment
编辑:或者更简单:在函数体内使用
。 。 。如果您在查找修饰函数名称时遇到困难。最后一个编译指示可以通过简单的宏定义进一步减少。
Instead of using .def file just insert
pragma comment
like thisEdit: Or even easier: Inside the body of the function use
. . . if you have troubles finding the decorated function name. This last pragma can be further reduced with a simple macro definition.
您可以通过关闭调试信息生成来获得您想要的结果。项目 + 属性、链接器、调试、生成调试信息 = 否。
当然,您只想为发布版本执行此操作。该选项已经这样设置了。
You can get what you want by turning off debug info generation. Project + Properties, Linker, Debugging, Generate Debug Info = No.
Naturally, you only want to do this for the Release build. Where the option is already set that way.
如果您不希望函数的名称被破坏,则必须将函数声明为
extern "C"
。You have to declare the functions as
extern "C"
if you don't want their names to be mangled.根据经验,如果您在函数签名中使用
__stdcall
,请务必小心。使用__stdcall
,名称将在某种程度上保持混乱(您很快就会发现)。显然,有两个级别的重整,一个是extern "C"
在 C++ 级别处理,但它不处理由__stdcall
引起的另一级别的名称重整。额外的损坏显然与超载有关——但我不确定这一点。From experience, be careful if you use
__stdcall
in your function signature. With__stdcall
, the name will remain mangled to some extent (you will find out quickly enough). Apparently, there are two levels of mangling, one theextern "C"
deals with at the C++ level, but it does not deal with another level of name mangling caused by__stdcall
. The extra mangling is apparently relevant to overloading -- but I am not certain of that.即使没有损坏,32 位和 64 位构建名称的导出也会有所不同,即使使用 extern“C”也是如此。使用 DEPENDS.EXE 检查一下。
对于任何使用 LoadLibrary+GetProcAdress 来访问您的函数的客户端来说,这可能意味着很大的麻烦。
因此,最重要的是使用模块定义文件,如下所示:
是的,维护起来有点痛苦,但是您每天要编写多少个导出函数?
此外,我通常会更改如下所示的宏,因为我的 DLL 导出函数不是 C++ 类,并且我希望它们可以被大多数编程环境调用:
几年前最后一行用于混淆 VisualAssistX,我不知道是否它现在可以正确消化它:-)
Even without the mangling, the 32-bit and 64-bit builds name exports differently, even with extern "C". Check it out with DEPENDS.EXE.
This can mean BIG trouble to any client that does a LoadLibrary+GetProcAdress to access your function.
So, on top of all the others use a Module Definition File as follows:
Yeap, it's a bit of a pain to maintain, but then how many exported functions do you write a day?
Moreover, I usually change the macros like shown below, since my DLLs export functions not C++ classes and I want them to be callable by most programming environments:
The last line used to confuse VisualAssistX a couple of years ago, I don't know if it properly digests it now :-)
我知道有多少次我尝试使用代码和#pragma 强制函数名称。
我总是以完全相同的方式结束,最后使用模块定义文件 (*.def)。
原因是:
我想知道为什么没有人这样做,我只花了 10 分钟就测试了所有案例。
I know how many times I've tried forcing function names using code and #pragma's.
And I always end with exactly same thing, using Module-Definition File (*.def) at the end.
And here is the reason:
I wonder why no one did this, it took me only 10 mins to test all cases.
很抱歉回复旧线程,但标记为答案的内容对我不起作用。
正如许多人指出的那样,外部“C”装饰很重要。更改“项目/属性/链接器/调试/生成调试信息”设置对于在调试或发布构建模式下为我生成的损坏名称完全没有影响。
设置:VS2005 编译 Visual C++ 类库项目。我正在使用 Microsoft 的 Dependency Walker 工具检查编译后的 .dll 输出。
这是一个对我有用的示例配方...
在project.h中:
在project.cpp中:
然后从C#托管代码中调用,class.cs:
执行上述操作可以防止在调试和发布模式下出现损坏的名称,无论生成调试信息设置。祝你好运。
Sorry for replying to an old thread, but what has been marked as the answer did not work for me.
As a number of people have pointed out, the extern "C" decoration is important. Changing the "Project / Properties / Linker / Debugging / Generate debug info" setting made absolutely no difference to the mangled names being generated for me in either Debug or Release build mode.
Setup: VS2005 compiling a Visual C++ Class Library project. I was checking the compiled .dll output with Microsoft's Dependency Walker tool.
Here is an example recipe that worked for me...
In project.h:
In project.cpp:
Then being called from C# managed code, class.cs:
Doing the above prevented the mangled names in both Debug and Release mode, regardless of the Generate debug info setting. Good luck.
SomeFunction@@@23mangledstuff#@@@@ 被破坏以给出 C++ 函数的类型和类。简单导出是可以从 C 调用的函数,即用 C 编写的函数,或者在 C++ 代码中声明为 extern“C”。如果您想要一个简单的接口,则必须使导出的函数仅使用 C 类型并使其成为全局命名空间中的非成员函数。
the SomeFunction@@@23mangledstuff#@@@@ is mangled to give the types and class of the C++ function. The simple exports are functions that are callable from C i.e. are written in C or else are declared extern "C' in C++ code. If is you want a simple interface you have to make the functions you export be use just C types and make them non member functions in the global namespace.
基本上,当您在 C++ 中使用函数时,它们的部分名称现在包含它们的签名等,以方便重载等语言功能。
如果您使用 __declspec(dllexport) 编写 DLL,那么它也应该生成一个 lib。链接到该库,您将自动被链接,并且 CRT 在启动时注册的函数(如果您记得将所有导入更改为导出)。如果您使用此系统,则无需了解名称修改。
Basically, when you use functions in C++, parts of their names now include their signature and suchlike, in order to facilitate language features like overloading.
If you write a DLL using __declspec(dllexport), then it should also produce a lib. Link to that lib, and you will automatically be linked and the functions registered by the CRT at start-up time (if you remembered to change all your imports to exports). You don't need to know about name mangling if you use this system.
以防万一,从数百行关于受损出口问题的华夫饼中还不清楚。这是我的 2c 值:)
使用 VS 2012 创建一个名为 Win32Project2 的项目并在向导中选择导出所有符号后。您应该有 2 个名为 Win32Project2.cpp 和 Win32project2.h 的文件,
这两个文件都将引用示例可导出变量和示例导出函数。
在 Win32Project2.h 中,您将拥有以下内容:
要取消修改,请将最后两行更改为 extern "C" 声明:
在 Win32Project2.cpp 中,您还将拥有以下默认定义:
要取消修改,请将这些更改为:
本质上您必须在声明前面使用 extern“C” 前缀,以强制链接器生成未损坏的类似 C 的名称。
如果您更喜欢使用损坏的名称来进行额外的混淆(如果损坏信息对有人以某种方式)使用 VC 命令行中的“dumpbin /exports Win32Project2.dll”来查找实际的引用名称。它的形式为“?fnWind32Project2@[param bytes]@[other info]”。如果运行 VC 命令 shell 无法让您满意,还有其他 DLL 查看工具。
这正是 MS 不默认采用此约定的原因实际的重整信息意味着一些可能对验证和调试有用的信息(例如以字节为单位的参数大小等),但
将上面的 DLL 函数导入 C# 项目(在本例中是基本的 C# Windows 应用程序)。上面有一个包含按钮“button1”的表单)这里有一些示例代码:
In case it wasn't clear from the hundreds of lines of waffle on the subject of mangled exports. Here's my 2c worth :)
After creating a project called Win32Project2 using VS 2012 and choosing export all symbols in the wizard. You should have 2 files called Win32Project2.cpp and Win32project2.h
Both of those will reference an example exportable variable and an example exported function.
In Win32Project2.h you will have the following:
To unmangle CHANGE the last two lines to extern "C" declarations to:
In Win32Project2.cpp you will also have the following default definitions:
To unmangle CHANGE THESE TO:
Essentially you must use the extern "C" prefix in front of declarations in order to force the linker to produce unmangled C like names.
If you prefer to use mangled names for that bit of extra obfuscation (in case the mangling info is useful to someone somehow) use "dumpbin /exports Win32Project2.dll" from a VC command line to lookup the actual reference names. It will have the form "?fnWind32Project2@[param bytes]@[other info] . There are also other DLL viewing tools around if running a VC command shell doesn't float your boat.
Exactly why MS doesn't default to this convention is a mystery. The actual mangling information means something (like parameter size in bytes and more) which might be useful for validation and debugging but is otherwise guff.
To import the DLL function above into C# project (in this case a basic C# windows application with a form on it containing the button "button1") here's some sample code: