在Linux中加载Mono库时如何处理未定义的符号



我正在将我的Windows Mono应用程序移植到Linux,一步一个脚印,首先移植到Windows 10下的WSL Linux,然后希望移植到Real Ubuntu。这里描述的所有内容在WSL和Ubuntu 20.04下的行为都是相同的。

我的应用程序加载/usr/lib/libmono-2.0.so共享库,但在这样做时,加载程序抛出一个异常:undefined symbol: _ZTIPi。一些研究表明,这个符号是在libstdc++中定义的;预加载的";同样。这没有任何效果。

与此同时,我在仔细阅读mono代码库时发现了这个代码片段。它将是mono\mini\mini-llvm.c:(https://github.com/mono/mono/blob/main/mono/mini/mini-llvm.c)

/* Add a reference to the c++ exception we throw/catch */
{
LLVMTypeRef exc = LLVMPointerType (LLVMInt8Type (), 0);
module->sentinel_exception = LLVMAddGlobal (module->lmodule, exc, "_ZTIPi");
LLVMSetLinkage (module->sentinel_exception, LLVMExternalLinkage);
mono_llvm_set_is_constant (module->sentinel_exception);
}

这里到底发生了什么?要成功加载此库,我需要了解什么?

到目前为止的解决方案是在默认版本之外构建和安装Mono。

请参阅https://www.mono-project.com/docs/compiling-mono/linux/

然后一站式商店构建脚本(Debian(

如果您按照说明进行操作,您的备用Mono安装将在/usr/local

这表明Mono版本在某种程度上被错误地编译了。

因此,在遇到同样的问题后发现了这一点,感谢您在问答中提供的信息,它帮助我找到了解决问题的方法。然而,您的解决方案并不能回答您的"这里到底发生了什么&";,我将尽力解释。

让我们从_ZTIPi符号开始,当运行c++filt时,它显示为:typeinfo for int*

它确实是C++标准库的一部分。它在libmono的默认安装中被列为未定义,但在我从源代码编译的安装中根本没有列出。你可以用类似的东西来检查:

$ readelf --all /usr/lib/libmono-2.0.so | grep _ZTIPi

然而,在这两种情况下,libstdc++.so都没有被列为所需的库。你可以用类似的东西来检查:

$ readelf --all /usr/lib/libmono-2.0.so | grep NEEDED

这一切都意味着,当你试图在libmono中加载时,动态链接器将试图通过查找libmono列出的库(在它找不到的地方(和进程的全局符号表(可能有也可能没有(来解析_ZTIPi符号。

如果在编译时链接到libmono,那么解决方案是在编译时也链接到libstdc++。这样,您的可执行文件将根据需要列出libstdc++库,从而使动态链接器将其符号加载到全局符号表中。当加载libmono时,动态链接器可以找到合适的符号。

如果您在运行时动态加载libmono,则必须首先在libstdc++中加载,使用以下内容:

void * cxxlib = dlopen("libstdc++.so.6", RTLD_LAZY | RTLD_GLOBAL);

这里的关键是RTLD_GLOBAL标志,它将把所有符号添加到全局表中,这样当您试图加载libmono时就可以找到它们。

当然,另一种选择是自己构建mono,这应该会让你得到一个不会被微妙破坏的libmono。在这种情况下,请确保对mono_set_dirs进行调用,如下所示:

mono_set_dirs("/opt/mono/lib", "/opt/mono/etc");

最新更新