dlsym returns NULL 其中 GetProcAddress returns 有效 IntPtr
dlsym returns NULL where GetProcAddress returns valid IntPtr
在制作跨平台游戏时,我发现需要一个跨平台 DLL 链接器,我的 DLL 链接器 class 似乎“符合标准”,但它只适用于 Windows机器,而它被设计为在 Window 和 Linux 机器上工作。
这是由于 dlsym( IntPtr handle, string symbol )
返回 IntPtr.Zero
而 GetProcAddress( IntPtr hModule, string lpProcName )
returns 指向所需符号的有效 IntPtr
。
代码
public static class DLL
{
#region DllImport
[DllImport( "kernel32.dll" )]
private static extern IntPtr LoadLibrary( string filename );
[DllImport( "kernel32.dll" )]
private static extern IntPtr GetProcAddress( IntPtr hModule, string procname );
[DllImport( "libdl.so" )]
private static extern IntPtr dlopen( string filename, int flags );
[DllImport( "libdl.so" )]
private static extern IntPtr dlsym( IntPtr handle, string symbol );
const int RTLD_NOW = 2;
#endregion
#region Abstracted
public static bool __linux__
{
get
{
int p = (int)Environment.OSVersion.Platform;
return ( p == 4 ) || ( p == 6 ) || ( p == 128 );
}
}
#endregion
#region Fields
private static Type _delegateType = typeof( MulticastDelegate );
#endregion
#region Methods
public static IntPtr Load( string filename )
{
IntPtr mHnd;
if ( __linux__ )
mHnd = dlopen( filename, RTLD_NOW );
else
mHnd = LoadLibrary( filename );
return mHnd;
}
public static IntPtr Symbol( IntPtr mHnd, string symbol )
{
IntPtr symPtr;
if ( __linux__ )
symPtr = dlsym( mHnd, symbol );
else
symPtr = GetProcAddress( mHnd, symbol );
return symPtr;
}
public static Delegate Delegate( Type delegateType, IntPtr mHnd, string symbol )
{
IntPtr ptrSym = Symbol( mHnd, symbol );
return Marshal.GetDelegateForFunctionPointer( ptrSym, delegateType );
}
public static void LinkAllDelegates( Type ofType, IntPtr mHnd )
{
FieldInfo[] fields = ofType.GetFields( BindingFlags.Public | BindingFlags.Static );
foreach ( FieldInfo fi in fields )
{
if ( fi.FieldType.BaseType == _delegateType )
{
fi.SetValue( null, Marshal.GetDelegateForFunctionPointer( Symbol( mHnd, fi.Name ), fi.FieldType ) );
}
}
}
#endregion
}
我使用这个自定义 class 来(部分)加载 LZ4:
public static class LZ4
{
private static string _lib = "lz4.dll";
private static IntPtr _dllHnd;
#region Delegates
public delegate int PFNLZ4_COMPRESS_DEFAULTPROC( IntPtr source, IntPtr dest, int sourceSize, int maxDestSize );
public delegate int PFNLZ4_COMPRESS_FASTPROC( IntPtr source, IntPtr dest, int sourceSize, int maxDestSize, int acceleration );
public delegate int PFNLZ4_COMPRESS_HCPROC( IntPtr src, IntPtr dst, int srcSize, int dstCapacity, int compressionLevel );
public delegate int PFNLZ4_DECOMPRESS_FASTPROC( IntPtr source, IntPtr dest, int originalSize );
public delegate int PFNLZ4_COMPRESSBOUNDPROC( int inputSize );
#endregion
#region Methods
public static void LZ4_Link()
{
if ( DLL.__linux__ )
_lib = "./liblz4.so";
_dllHnd = DLL.Load( _lib );
Console.WriteLine( "LZ4_Link: OS is {0}", DLL.__linux__ ? "Linux" : "Windows" );
Console.WriteLine( "LZ4_Link: Linked {0}", _lib );
Console.WriteLine( "LZ4_Link: _dllHnd -> 0x{0}", _dllHnd.ToString( "X" ) );
DLL.LinkAllDelegates( typeof( LZ4 ), _dllHnd );
}
public static PFNLZ4_COMPRESS_DEFAULTPROC LZ4_compress_default;
public static PFNLZ4_COMPRESS_FASTPROC LZ4_compress_fast;
public static PFNLZ4_COMPRESS_HCPROC LZ4_compress_HC;
public static PFNLZ4_DECOMPRESS_FASTPROC LZ4_decompress_fast;
public static PFNLZ4_COMPRESSBOUNDPROC LZ4_compressBound;
#endregion
}
如前所述,每个 dlsym
调用 returns IntPtr.Zero
(NULL
),而 Windows “等效”工作正常。
似乎名称 mangling/release 差异是问题所在。
lz4.dll
导出 LZ4_decompress_default
,而 liblz4.so
导出 LZ4_decompress
。
在制作跨平台游戏时,我发现需要一个跨平台 DLL 链接器,我的 DLL 链接器 class 似乎“符合标准”,但它只适用于 Windows机器,而它被设计为在 Window 和 Linux 机器上工作。
这是由于 dlsym( IntPtr handle, string symbol )
返回 IntPtr.Zero
而 GetProcAddress( IntPtr hModule, string lpProcName )
returns 指向所需符号的有效 IntPtr
。
代码
public static class DLL
{
#region DllImport
[DllImport( "kernel32.dll" )]
private static extern IntPtr LoadLibrary( string filename );
[DllImport( "kernel32.dll" )]
private static extern IntPtr GetProcAddress( IntPtr hModule, string procname );
[DllImport( "libdl.so" )]
private static extern IntPtr dlopen( string filename, int flags );
[DllImport( "libdl.so" )]
private static extern IntPtr dlsym( IntPtr handle, string symbol );
const int RTLD_NOW = 2;
#endregion
#region Abstracted
public static bool __linux__
{
get
{
int p = (int)Environment.OSVersion.Platform;
return ( p == 4 ) || ( p == 6 ) || ( p == 128 );
}
}
#endregion
#region Fields
private static Type _delegateType = typeof( MulticastDelegate );
#endregion
#region Methods
public static IntPtr Load( string filename )
{
IntPtr mHnd;
if ( __linux__ )
mHnd = dlopen( filename, RTLD_NOW );
else
mHnd = LoadLibrary( filename );
return mHnd;
}
public static IntPtr Symbol( IntPtr mHnd, string symbol )
{
IntPtr symPtr;
if ( __linux__ )
symPtr = dlsym( mHnd, symbol );
else
symPtr = GetProcAddress( mHnd, symbol );
return symPtr;
}
public static Delegate Delegate( Type delegateType, IntPtr mHnd, string symbol )
{
IntPtr ptrSym = Symbol( mHnd, symbol );
return Marshal.GetDelegateForFunctionPointer( ptrSym, delegateType );
}
public static void LinkAllDelegates( Type ofType, IntPtr mHnd )
{
FieldInfo[] fields = ofType.GetFields( BindingFlags.Public | BindingFlags.Static );
foreach ( FieldInfo fi in fields )
{
if ( fi.FieldType.BaseType == _delegateType )
{
fi.SetValue( null, Marshal.GetDelegateForFunctionPointer( Symbol( mHnd, fi.Name ), fi.FieldType ) );
}
}
}
#endregion
}
我使用这个自定义 class 来(部分)加载 LZ4:
public static class LZ4
{
private static string _lib = "lz4.dll";
private static IntPtr _dllHnd;
#region Delegates
public delegate int PFNLZ4_COMPRESS_DEFAULTPROC( IntPtr source, IntPtr dest, int sourceSize, int maxDestSize );
public delegate int PFNLZ4_COMPRESS_FASTPROC( IntPtr source, IntPtr dest, int sourceSize, int maxDestSize, int acceleration );
public delegate int PFNLZ4_COMPRESS_HCPROC( IntPtr src, IntPtr dst, int srcSize, int dstCapacity, int compressionLevel );
public delegate int PFNLZ4_DECOMPRESS_FASTPROC( IntPtr source, IntPtr dest, int originalSize );
public delegate int PFNLZ4_COMPRESSBOUNDPROC( int inputSize );
#endregion
#region Methods
public static void LZ4_Link()
{
if ( DLL.__linux__ )
_lib = "./liblz4.so";
_dllHnd = DLL.Load( _lib );
Console.WriteLine( "LZ4_Link: OS is {0}", DLL.__linux__ ? "Linux" : "Windows" );
Console.WriteLine( "LZ4_Link: Linked {0}", _lib );
Console.WriteLine( "LZ4_Link: _dllHnd -> 0x{0}", _dllHnd.ToString( "X" ) );
DLL.LinkAllDelegates( typeof( LZ4 ), _dllHnd );
}
public static PFNLZ4_COMPRESS_DEFAULTPROC LZ4_compress_default;
public static PFNLZ4_COMPRESS_FASTPROC LZ4_compress_fast;
public static PFNLZ4_COMPRESS_HCPROC LZ4_compress_HC;
public static PFNLZ4_DECOMPRESS_FASTPROC LZ4_decompress_fast;
public static PFNLZ4_COMPRESSBOUNDPROC LZ4_compressBound;
#endregion
}
如前所述,每个 dlsym
调用 returns IntPtr.Zero
(NULL
),而 Windows “等效”工作正常。
似乎名称 mangling/release 差异是问题所在。
lz4.dll
导出 LZ4_decompress_default
,而 liblz4.so
导出 LZ4_decompress
。