Linux下Mono加载PE32 Win32 DLL报无效ELF头如何解决
问题描述
我尝试在Linux主机上使用mcs(Mono编译器)构建原生Win32应用。
我有一个名为CoolLib.dll的库,其中包含如下代码行:
[global::System.Runtime.InteropServices.DllImport("MyLib.dll", EntryPoint="...")]
该库使用mcs编译,通过file命令查看文件格式结果如下:
$ file CoolLib.dll PE32+ executable (DLL) (console) x86-64 Mono/.Net assembly, for MS Windows
此外MyLib.dll同样为自行开发,在同一主机上使用mingw-g++编译得到,file命令查看其格式结果如下:
$ file MyLib.dll MyLib.dll: PE32+ executable (DLL) (console) x86-64, for MS Windows
随后我编译引用了CoolLib.dll的Hello World可执行程序,执行命令如下:
mcs /reference:CoolLib.dll /out:main.exe /target:x64 main.cs MONO_LOG_LEVEL=debug mono main.exe
但程序运行时抛出System.DllNotFoundException异常。
核心疑问:为何报错提示MyLib.dll不是合法ELF文件
Mono: DllImport error loading library '/bindings_test/MyLib.dll': '/bindings_test/MyLib.dll: invalid ELF header'.
该文件本就应为Win32库,为何Mono会期望它是ELF格式?
原因说明
这是典型的运行环境与二进制格式不匹配问题:
- 你在Linux上直接执行
mono main.exe时,Mono本身是运行在Linux上的原生进程,它自己实现了.NET程序集的PE格式解析逻辑,所以哪怕mcs输出的是.dll/.exe后缀的PE格式.NET程序集,Mono也能自主加载运行。 - 但
DllImport加载的是非托管原生库,这部分Mono不会做跨格式兼容,直接调用Linux系统自带的动态链接器加载目标文件。Linux动态链接器只识别ELF格式的二进制文件,你用mingw编译出的MyLib.dll是纯Windows PE格式原生库,动态链接器读文件头发现不是ELF格式,自然抛出invalid ELF header的错误。 - 本质上就是拿Windows平台专用的原生二进制,往Linux运行时的加载逻辑里硬套,两边格式标准完全对不上,加载必然失败。
解决方案
根据你的实际目标场景二选一即可:
- 如果程序最终要在Linux环境运行:把
MyLib用Linux原生g++编译成.so后缀的ELF动态库,要么直接修改DllImport的库名指向编译好的so文件,要么编写Mono的DllMap配置,把代码里对MyLib.dll的引用映射到对应的so文件,就能正常加载。 - 如果你的目标就是编译纯Windows平台可用的程序:编译完成后把所有exe、dll拷贝到Windows环境运行测试即可,不要在Linux下直接用原生Mono启动。Mono没有内置Windows PE原生库的加载兼容层,如果非要在Linux上测试Windows版本,可以用Wine启动整个程序。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

