chr
2026-04-05 fe750b791d5b517cc4e9bc8e99a9a75139a0cfba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
using System;
using System.Runtime.InteropServices;
 
/// <summary>
///  This class uses and resolves libdl, which dependning on the OS comes in a libdl.so or libdl.so.2 flavor.
/// </summary>
static class LibDl
{
    static IntPtr load(string name) => libDl.dlopen(name, rtld_now);
    static void close(IntPtr ptr) => libDl.dlclose(ptr);
 
    /// <summary> Gets most recent load error. </summary>
    public static string GetError()
    {
        var error = libDl.dlerror();
        if (IntPtr.Zero == error) return null;
        return Marshal.PtrToStringAuto(error);
    }
    
    static void clearError() => libDl.dlerror();
 
    const int rtld_now = 2;
 
    interface ILibDL
    {
        IntPtr dlopen(string filename, int flags);
        int dlclose(IntPtr handle);
        IntPtr dlerror();
        IntPtr dlsym(IntPtr handle, string symbol);
    }
 
    /// <summary>
    /// libc5 (shipped with Ubuntu 20.04 and older) and older contains this libdl version, but it is not shipped with libc6
    /// </summary>
    class libdl1 : ILibDL
    {
        private const string libName = "libdl.so";
        [DllImport(libName)]
        static extern IntPtr dlopen(string fileName, int flags);
        [DllImport(libName)]
        static extern int dlclose(IntPtr handle);
        [DllImport(libName)]
        static extern IntPtr dlerror();
        [DllImport(libName)]
        static extern IntPtr dlsym(IntPtr handle, string symbol);
 
 
        IntPtr ILibDL.dlopen(string fileName, int flags) => dlopen(fileName, flags);
        int ILibDL.dlclose(IntPtr handle) => dlclose(handle);
        IntPtr ILibDL.dlerror() => dlerror();
        IntPtr ILibDL.dlsym(IntPtr handle, string symbol) => dlsym(handle, symbol);
    }
 
    /// <summary>
    /// libc6 (shipped with Ubuntu 22.04) only ships libdl.so.2. This seems to be the only way to resolve it.
    /// Trying "libdl" or just "dl" also does not seem to resolve to libdl.so.2. 
    /// </summary>
    class libdl2 : ILibDL
    {
        private const string libName = "libdl.so.2";
        [DllImport(libName)]
        static extern IntPtr dlopen(string fileName, int flags);
        [DllImport(libName)]
        static extern int dlclose(IntPtr handle);
        [DllImport(libName)]
        static extern IntPtr dlerror();
        [DllImport(libName)]
        static extern IntPtr dlsym(IntPtr handle, string symbol);
        
        IntPtr ILibDL.dlopen(string fileName, int flags) => dlopen(fileName, flags);
        int ILibDL.dlclose(IntPtr handle) => dlclose(handle);
        IntPtr ILibDL.dlerror() => dlerror();
        IntPtr ILibDL.dlsym(IntPtr handle, string symbol) => dlsym(handle, symbol);
    }
    
    /// <summary>
    /// MacOS calls it libdl
    /// </summary>
    class libdlMac : ILibDL
    {
        private const string libName = "libdl";
        [DllImport(libName)]
        static extern IntPtr dlopen(string fileName, int flags);
        [DllImport(libName)]
        static extern int dlclose(IntPtr handle);
        [DllImport(libName)]
        static extern IntPtr dlerror();
        [DllImport(libName)]
        static extern IntPtr dlsym(IntPtr handle, string symbol);
        
        IntPtr ILibDL.dlopen(string fileName, int flags) => dlopen(fileName, flags);
        int ILibDL.dlclose(IntPtr handle) => dlclose(handle);
        IntPtr ILibDL.dlerror() => dlerror();
        IntPtr ILibDL.dlsym(IntPtr handle, string symbol) => dlsym(handle, symbol);
    }
    
    static readonly ILibDL libDl;
 
    static LibDl()
    {
        if (OpenTap.OperatingSystem.Current == OpenTap.OperatingSystem.MacOS)
        {
            libDl = new libdlMac();
        }
        else 
        {
            try
            {
                libDl = new libdl2();
                // call dlerror to ensure library is resolved
                libDl.dlerror();
            }
            catch (DllNotFoundException)
            {
                libDl = new libdl1();
            }
        }
    }
 
    public static IntPtr Sym(IntPtr lib, string name) => libDl.dlsym(lib, name);
 
    public static IntPtr Load(string name)
    {
        clearError();
        return load(name);
    }
 
    public static void Unload(IntPtr lib)
    {
        if (lib == IntPtr.Zero)
            throw new NullReferenceException();
        close(lib);
    }
}