运行时字符串中的 MSVC C++ 名称重整
MSVC C++ Name Mangling From String On Runtime
首先,我将从 运行 时间需要名称修改的原因开始。
我需要在 dll 和它的包装器之间创建一个桥梁
namespace Wrapper
{
class __declspec(dllexport) Token
{
public:
virtual void release() {}
};
}
class __declspec(dllexport) Token
{
public:
virtual void release(){}
};
我们的想法是使用 dumpin 生成持有 class 令牌的 dll 的所有损坏名称,然后再对它们进行分解。
?release@Token@@UAEXXZ --> void Token::release(void)
之后我要转换的是匹配包装器,所以我需要更改函数名称
void Token::release(void) --> void Wrapper::Token::release(void)
然后我需要再次处理它,这样我就可以创建一个 def 文件,将旧函数定向到新函数。
?release@Token@@UAEXXZ = ?release@Token@Wrapper@@UAEXXZ
所有这些过程都需要在 运行 时间进行。
首先也是最简单的解决方案是找到一个破坏字符串的函数,但我找不到任何...
还有其他解决方案吗?
Clang 编译器与 MSVC ABI 兼容,包括名称重整。
底层基础设施是 LLVM 项目的一部分,我发现 llvm-undname 可以分解 MSVC 名称。也许您可以对其进行修改,将 Wrapper::
命名空间添加到符号中并重新处理。
您可以在 this test code 中找到关于改名的灵感。
如果您被允许更改 DLL,我通常会使用不同的方法,通过导出 extern "C" getter 函数(不会损坏,因此不需要 demangling)和使用虚拟接口访问 class(请注意,此时不需要 dllexported 虚拟接口)。反正你的Token接口好像是虚拟的。
类似的东西(未经测试,只是为了展示这个想法):
DLL 访问 header:
class Token // notice no dllexport!
{
protected:
// should not be used to delete directly (DLL vs EXE heap issues)
virtual ~Token() {}
virtual void destroyImpl() = 0; // pure virtual
public:
static inline void destroy(Token* token) {
// need to check for NULL otherwise virtual call would segfault
if (token) token->destroyImpl();
}
virtual void doSomething() = 0; // pure virtual
};
extern "C" __declspec(dllexport) Token * createToken();
DLL 实现:
class TokenImpl: public Token
{
public:
virtual void destroyImpl() {
delete this;
}
virtual void doSomething() {
// implement here
}
};
extern "C" __declspec(dllexport) Token * createToken()
{
return new TokenImpl;
}
用法:
// ideally wrap in RAII to be sure to always release
// (e.g. can use std::shared_ptr with custom deleter)
Token * token = createToken();
// use the token
token->doSomething();
// destroy
Token::destroy(token);
与shared::ptr(也可以在Token接口中创建一个typedef/static内联便利创建函数):
std::shared_ptr<Token> token(createToken(),
// Use the custom destroy function
&Token::destroy);
token->doSomething()
// token->destroy() called automatically when last shared ptr reference removed
这样你只需要导出 extern-C creator 函数(和 release 函数,如果不是接口的一部分),它不会被破坏,因此通过运行时加载很容易使用。
首先,我将从 运行 时间需要名称修改的原因开始。
我需要在 dll 和它的包装器之间创建一个桥梁
namespace Wrapper
{
class __declspec(dllexport) Token
{
public:
virtual void release() {}
};
}
class __declspec(dllexport) Token
{
public:
virtual void release(){}
};
我们的想法是使用 dumpin 生成持有 class 令牌的 dll 的所有损坏名称,然后再对它们进行分解。
?release@Token@@UAEXXZ --> void Token::release(void)
之后我要转换的是匹配包装器,所以我需要更改函数名称
void Token::release(void) --> void Wrapper::Token::release(void)
然后我需要再次处理它,这样我就可以创建一个 def 文件,将旧函数定向到新函数。
?release@Token@@UAEXXZ = ?release@Token@Wrapper@@UAEXXZ
所有这些过程都需要在 运行 时间进行。
首先也是最简单的解决方案是找到一个破坏字符串的函数,但我找不到任何...
还有其他解决方案吗?
Clang 编译器与 MSVC ABI 兼容,包括名称重整。
底层基础设施是 LLVM 项目的一部分,我发现 llvm-undname 可以分解 MSVC 名称。也许您可以对其进行修改,将 Wrapper::
命名空间添加到符号中并重新处理。
您可以在 this test code 中找到关于改名的灵感。
如果您被允许更改 DLL,我通常会使用不同的方法,通过导出 extern "C" getter 函数(不会损坏,因此不需要 demangling)和使用虚拟接口访问 class(请注意,此时不需要 dllexported 虚拟接口)。反正你的Token接口好像是虚拟的。
类似的东西(未经测试,只是为了展示这个想法):
DLL 访问 header:
class Token // notice no dllexport!
{
protected:
// should not be used to delete directly (DLL vs EXE heap issues)
virtual ~Token() {}
virtual void destroyImpl() = 0; // pure virtual
public:
static inline void destroy(Token* token) {
// need to check for NULL otherwise virtual call would segfault
if (token) token->destroyImpl();
}
virtual void doSomething() = 0; // pure virtual
};
extern "C" __declspec(dllexport) Token * createToken();
DLL 实现:
class TokenImpl: public Token
{
public:
virtual void destroyImpl() {
delete this;
}
virtual void doSomething() {
// implement here
}
};
extern "C" __declspec(dllexport) Token * createToken()
{
return new TokenImpl;
}
用法:
// ideally wrap in RAII to be sure to always release
// (e.g. can use std::shared_ptr with custom deleter)
Token * token = createToken();
// use the token
token->doSomething();
// destroy
Token::destroy(token);
与shared::ptr(也可以在Token接口中创建一个typedef/static内联便利创建函数):
std::shared_ptr<Token> token(createToken(),
// Use the custom destroy function
&Token::destroy);
token->doSomething()
// token->destroy() called automatically when last shared ptr reference removed
这样你只需要导出 extern-C creator 函数(和 release 函数,如果不是接口的一部分),它不会被破坏,因此通过运行时加载很容易使用。