dlsym returns NULL where GetProcAddress returns valid IntPtr

这一生的挚爱 提交于 2019-12-25 10:46:32

问题


While making a cross-platform game I found the need for a cross-platform DLL linker, my DLL linker class seems to be "up to standards" but it only works on Windows machines, while it is designed to work on both Window and Linux machines.

This is due to dlsym( IntPtr handle, string symbol ) returning IntPtr.Zero whereas GetProcAddress( IntPtr hModule, string lpProcName ) returns a valid IntPtr pointing to the desired symbol.

Code

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
}

I used this custom class to (partially) load LZ4 as such:

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
}

As said, every dlsym call returns IntPtr.Zero (NULL), whereas the Windows "equivalent" works just fine.


回答1:


Seems like name mangling/release differences were the issue. lz4.dll exported LZ4_decompress_default, whereas liblz4.so exported LZ4_decompress.



来源:https://stackoverflow.com/questions/44765486/dlsym-returns-null-where-getprocaddress-returns-valid-intptr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!