C++ DLL 导出:修饰/损坏的名称

发布于 2024-09-01 12:14:04 字数 1139 浏览 9 评论 0原文

使用模块定义文件 (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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

巴黎夜雨 2024-09-08 12:14:04

不使用 .def 文件,只需像这样插入pragma comment

#pragma comment(linker, "/EXPORT:SomeFunction=_SomeFunction@@@23mangledstuff#@@@@")

编辑:或者更简单:在函数体内使用

#pragma comment(linker, "/EXPORT:" __FUNCTION__"=" __FUNCDNAME__)

。 。 。如果您在查找修饰函数名称时遇到困难。最后一个编译指示可以通过简单的宏定义进一步减少。

Instead of using .def file just insert pragma comment like this

#pragma comment(linker, "/EXPORT:SomeFunction=_SomeFunction@@@23mangledstuff#@@@@")

Edit: Or even easier: Inside the body of the function use

#pragma comment(linker, "/EXPORT:" __FUNCTION__"=" __FUNCDNAME__)

. . . if you have troubles finding the decorated function name. This last pragma can be further reduced with a simple macro definition.

桃气十足 2024-09-08 12:14:04

您可以通过关闭调试信息生成来获得您想要的结果。项目 + 属性、链接器、调试、生成调试信息 = 否。

当然,您只想为发布版本执行此操作。该选项已经这样设置了。

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.

柏林苍穹下 2024-09-08 12:14:04

如果您不希望函数的名称被破坏,则必须将函数声明为 extern "C"

You have to declare the functions as extern "C" if you don't want their names to be mangled.

青巷忧颜 2024-09-08 12:14:04

根据经验,如果您在函数签名中使用 __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 the extern "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.

や莫失莫忘 2024-09-08 12:14:04

即使没有损坏,32 位和 64 位构建名称的导出也会有所不同,即使使用 extern“C”也是如此。使用 DEPENDS.EXE 检查一下。

对于任何使用 LoadLibrary+GetProcAdress 来访问您的函数的客户端来说,这可能意味着很大的麻烦。

因此,最重要的是使用模块定义文件,如下所示:

LIBRARY MYDLL
EXPORTS
myFunction=myFunction

是的,维护起来有点痛苦,但是您每天要编写多少个导出函数?

此外,我通常会更改如下所示的宏,因为我的 DLL 导出函数不是 C++ 类,并且我希望它们可以被大多数编程环境调用:

#ifdef WTS_EXPORTS
#define WTS_API(ReturnType) extern "C" __declspec(dllexport) ReturnType WINAPI
#else
#define WTS_API(ReturnType) extern "C" __declspec(dllimport) ReturnType WINAPI
#endif

WTS_API(int) fnWTS(void);

几年前最后一行用于混淆 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:

LIBRARY MYDLL
EXPORTS
myFunction=myFunction

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:

#ifdef WTS_EXPORTS
#define WTS_API(ReturnType) extern "C" __declspec(dllexport) ReturnType WINAPI
#else
#define WTS_API(ReturnType) extern "C" __declspec(dllimport) ReturnType WINAPI
#endif

WTS_API(int) fnWTS(void);

The last line used to confuse VisualAssistX a couple of years ago, I don't know if it properly digests it now :-)

情绪操控生活 2024-09-08 12:14:04

我知道有多少次我尝试使用代码和#pragma 强制函数名称。
我总是以完全相同的方式结束,最后使用模块定义文件 (*.def)。
原因是:

//---------------------------------------------------------------------------------------------------
// Test cases built using VC2010 - Win32 - Debug / Release << doesn't matter
//---------------------------------------------------------------------------------------------------
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = Yes (/DEBUG)
//  || (or, also doesn't matter)
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = No + delete PDB file!

extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> _SetCallback@4

__declspec(dllexport) void SetCallback(LPCALLBACK function);
> ?SetCallback@@YAXP6AXHPADPAX@Z@Z

__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> ?SetCallback@@YGXP6GXHPADPAX@Z@Z    

//---------------------------------------------------------------------------------------------------
// this also big is nonsense cause as soon you change your calling convention or add / remove
// extern "C" code won't link anymore.

// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback=SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=_SetCallback@4")
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YAXP6AXHPADPAX@Z@Z")
__declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YGXP6GXHPADPAX@Z@Z")
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);

//---------------------------------------------------------------------------------------------------
// So far only repetable case is using Module-Definition File (*.def) in all possible cases:
EXPORTS
  SetCallback

extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback

__declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback

// And by far this is most acceptable as it will reproduce exactly same exported function name 
// using most common compilers. Header is dictating calling convention so not much trouble for
// other sw/ppl trying to build Interop or similar.

我想知道为什么没有人这样做,我只花了 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:

//---------------------------------------------------------------------------------------------------
// Test cases built using VC2010 - Win32 - Debug / Release << doesn't matter
//---------------------------------------------------------------------------------------------------
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = Yes (/DEBUG)
//  || (or, also doesn't matter)
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = No + delete PDB file!

extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> _SetCallback@4

__declspec(dllexport) void SetCallback(LPCALLBACK function);
> ?SetCallback@@YAXP6AXHPADPAX@Z@Z

__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> ?SetCallback@@YGXP6GXHPADPAX@Z@Z    

//---------------------------------------------------------------------------------------------------
// this also big is nonsense cause as soon you change your calling convention or add / remove
// extern "C" code won't link anymore.

// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback=SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=_SetCallback@4")
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YAXP6AXHPADPAX@Z@Z")
__declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YGXP6GXHPADPAX@Z@Z")
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);

//---------------------------------------------------------------------------------------------------
// So far only repetable case is using Module-Definition File (*.def) in all possible cases:
EXPORTS
  SetCallback

extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback

__declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback

// And by far this is most acceptable as it will reproduce exactly same exported function name 
// using most common compilers. Header is dictating calling convention so not much trouble for
// other sw/ppl trying to build Interop or similar.

I wonder why no one did this, it took me only 10 mins to test all cases.

耶耶耶 2024-09-08 12:14:04

很抱歉回复旧线程,但标记为答案的内容对我不起作用。

正如许多人指出的那样,外部“C”装饰很重要。更改“项目/属性/链接器/调试/生成调试信息”设置对于在调试或发布构建模式下为我生成的损坏名称完全没有影响。

设置:VS2005 编译 Visual C++ 类库项目。我正在使用 Microsoft 的 Dependency Walker 工具检查编译后的 .dll 输出。

这是一个对我有用的示例配方...

在project.h中:

#define DllExport extern "C" __declspec( dllexport )

DllExport bool API_Init();
DllExport bool API_Shutdown();

在project.cpp中:

#include "project.h"

bool API_Init()
{
  return true;
}

bool API_Shutdown()
{
  return true;
}

然后从C#托管代码中调用,class.cs:

using System.Runtime.Interopservices;
namespace Foo
{
    public class Project
    {
        [DllImport("project.dll")]
        public static extern bool API_Init();

        [DllImport("project.dll")]
        public static extern bool API_Shutdown();
    }
}

执行上述操作可以防止在调试和发布模式下出现损坏的名称,无论生成调试信息设置。祝你好运。

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:

#define DllExport extern "C" __declspec( dllexport )

DllExport bool API_Init();
DllExport bool API_Shutdown();

In project.cpp:

#include "project.h"

bool API_Init()
{
  return true;
}

bool API_Shutdown()
{
  return true;
}

Then being called from C# managed code, class.cs:

using System.Runtime.Interopservices;
namespace Foo
{
    public class Project
    {
        [DllImport("project.dll")]
        public static extern bool API_Init();

        [DllImport("project.dll")]
        public static extern bool API_Shutdown();
    }
}

Doing the above prevented the mangled names in both Debug and Release mode, regardless of the Generate debug info setting. Good luck.

烟─花易冷 2024-09-08 12:14:04

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.

谜泪 2024-09-08 12:14:04

基本上,当您在 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.

白况 2024-09-08 12:14:04

以防万一,从数百行关于受损出口问题的华夫饼中还不清楚。这是我的 2c 值:)

使用 VS 2012 创建一个名为 Win32Project2 的项目并在向导中选择导出所有符号后。您应该有 2 个名为 Win32Project2.cpp 和 Win32project2.h 的文件,

这两个文件都将引用示例可导出变量和示例导出函数。

在 Win32Project2.h 中,您将拥有以下内容:

#ifdef WIN32PROJECT2_EXPORTS
#define WIN32PROJECT2_API __declspec(dllexport)
#else
#define WIN32PROJECT2_API __declspec(dllimport)
#endif

extern WIN32PROJECT2_API int nWin32Project2;
WIN32PROJECT2_API int fnWin32Project2(void);

要取消修改,请将最后两行更改为 extern "C" 声明:

extern "C" WIN32PROJECT2_API int nWin32Project2;
extern "C" WIN32PROJECT2_API int fnWin32Project2(void);

在 Win32Project2.cpp 中,您还将拥有以下默认定义:

// This is an example of an exported variable
WIN32PROJECT2_API int nWin32Project2=0;

// This is an example of an exported function.
WIN32PROJECT2_API int fnWin32Project2(void)
{
    return 42;
}

要取消修改,请将这些更改为:

// This is an example of an exported variable
extern "C" WIN32PROJECT2_API int nWin32Project2=0;

// This is an example of an exported function.
extern "C" WIN32PROJECT2_API int fnWin32Project2(void)
{
    return 42;
}

本质上您必须在声明前面使用 extern“C” 前缀,以强制链接器生成未损坏的类似 C 的名称。

如果您更喜欢使用损坏的名称来进行额外的混淆(如果损坏信息对有人以某种方式)使用 VC 命令行中的“dumpbin /exports Win32Project2.dll”来查找实际的引用名称。它的形式为“?fnWind32Project2@[param bytes]@[other info]”。如果运行 VC 命令 shell 无法让您满意,还有其他 DLL 查看工具。

这正是 MS 不默认采用此约定的原因实际的重整信息意味着一些可能对验证和调试有用的信息(例如以字节为单位的参数大小等),但

将上面的 DLL 函数导入 C# 项目(在本例中是基本的 C# Windows 应用程序)。上面有一个包含按钮“button1”的表单)这里有一些示例代码:

using System.Runtime.InteropServices;



    namespace AudioRecApp
    {

      public partial class Form1 : Form
      {
        [ DllImport("c:\\Projects\test\Debug\Win32Projects2.dll")] 
        public static extern int fnWin32Project2();

        public Form1()
        {
          InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
          int value;

          value = fnWin32Project2();
        }
      }
    }

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:

#ifdef WIN32PROJECT2_EXPORTS
#define WIN32PROJECT2_API __declspec(dllexport)
#else
#define WIN32PROJECT2_API __declspec(dllimport)
#endif

extern WIN32PROJECT2_API int nWin32Project2;
WIN32PROJECT2_API int fnWin32Project2(void);

To unmangle CHANGE the last two lines to extern "C" declarations to:

extern "C" WIN32PROJECT2_API int nWin32Project2;
extern "C" WIN32PROJECT2_API int fnWin32Project2(void);

In Win32Project2.cpp you will also have the following default definitions:

// This is an example of an exported variable
WIN32PROJECT2_API int nWin32Project2=0;

// This is an example of an exported function.
WIN32PROJECT2_API int fnWin32Project2(void)
{
    return 42;
}

To unmangle CHANGE THESE TO:

// This is an example of an exported variable
extern "C" WIN32PROJECT2_API int nWin32Project2=0;

// This is an example of an exported function.
extern "C" WIN32PROJECT2_API int fnWin32Project2(void)
{
    return 42;
}

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:

using System.Runtime.InteropServices;



    namespace AudioRecApp
    {

      public partial class Form1 : Form
      {
        [ DllImport("c:\\Projects\test\Debug\Win32Projects2.dll")] 
        public static extern int fnWin32Project2();

        public Form1()
        {
          InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
          int value;

          value = fnWin32Project2();
        }
      }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文