@@ -7,7 +7,7 @@ static class DynamicLinkingLinux
77 {
88 public const int RTLD_NOW = 2 ;
99
10- // Try libdl first (glibc systems), fall back to libc (musl/Alpine )
10+ // libdl (works on most .NET Core Linux systems )
1111 [ DllImport ( "libdl" , EntryPoint = "dlopen" ) ]
1212 private static extern IntPtr dlopen_libdl ( string path , int flags ) ;
1313 [ DllImport ( "libdl" , EntryPoint = "dlclose" ) ]
@@ -17,7 +17,27 @@ static class DynamicLinkingLinux
1717 [ DllImport ( "libdl" , EntryPoint = "dlsym" ) ]
1818 private static extern IntPtr dlsym_libdl ( IntPtr handle , string name ) ;
1919
20- // On musl-based systems (Alpine), dlopen is in libc
20+ // libdl.so.2 (required for Mono on some glibc systems)
21+ [ DllImport ( "libdl.so.2" , EntryPoint = "dlopen" ) ]
22+ private static extern IntPtr dlopen_libdl2 ( string path , int flags ) ;
23+ [ DllImport ( "libdl.so.2" , EntryPoint = "dlclose" ) ]
24+ private static extern int dlclose_libdl2 ( IntPtr handle ) ;
25+ [ DllImport ( "libdl.so.2" , EntryPoint = "dlerror" ) ]
26+ private static extern IntPtr dlerror_libdl2 ( ) ;
27+ [ DllImport ( "libdl.so.2" , EntryPoint = "dlsym" ) ]
28+ private static extern IntPtr dlsym_libdl2 ( IntPtr handle , string name ) ;
29+
30+ // libc.so.6 (fallback for glibc systems where dlopen moved to libc)
31+ [ DllImport ( "libc.so.6" , EntryPoint = "dlopen" ) ]
32+ private static extern IntPtr dlopen_libc6 ( string path , int flags ) ;
33+ [ DllImport ( "libc.so.6" , EntryPoint = "dlclose" ) ]
34+ private static extern int dlclose_libc6 ( IntPtr handle ) ;
35+ [ DllImport ( "libc.so.6" , EntryPoint = "dlerror" ) ]
36+ private static extern IntPtr dlerror_libc6 ( ) ;
37+ [ DllImport ( "libc.so.6" , EntryPoint = "dlsym" ) ]
38+ private static extern IntPtr dlsym_libc6 ( IntPtr handle , string name ) ;
39+
40+ // libc (musl/Alpine systems)
2141 [ DllImport ( "libc" , EntryPoint = "dlopen" ) ]
2242 private static extern IntPtr dlopen_libc ( string path , int flags ) ;
2343 [ DllImport ( "libc" , EntryPoint = "dlclose" ) ]
@@ -27,36 +47,84 @@ static class DynamicLinkingLinux
2747 [ DllImport ( "libc" , EntryPoint = "dlsym" ) ]
2848 private static extern IntPtr dlsym_libc ( IntPtr handle , string name ) ;
2949
30- private static readonly bool UseLibdl = ProbeLibdl ( ) ;
50+ private enum DlLibrary { Libdl , Libdl2 , Libc6 , Libc }
51+ private static readonly DlLibrary ActiveLibrary = ProbeLibrary ( ) ;
3152
32- private static bool ProbeLibdl ( )
53+ private static DlLibrary ProbeLibrary ( )
3354 {
55+ // Try libdl (most .NET Core systems)
3456 try
3557 {
3658 dlopen_libdl ( null , RTLD_NOW ) ;
37- return true ;
59+ return DlLibrary . Libdl ;
3860 }
39- catch ( DllNotFoundException )
61+ catch ( DllNotFoundException ) { }
62+ catch ( EntryPointNotFoundException ) { }
63+
64+ // Try libdl.so.2 (Mono on glibc)
65+ try
4066 {
41- return false ;
67+ dlopen_libdl2 ( null , RTLD_NOW ) ;
68+ return DlLibrary . Libdl2 ;
4269 }
43- catch ( EntryPointNotFoundException )
70+ catch ( DllNotFoundException ) { }
71+ catch ( EntryPointNotFoundException ) { }
72+
73+ // Try libc.so.6 (newer glibc where dlopen moved to libc)
74+ try
4475 {
45- // On some 32-bit Linux systems, libdl exists but dlopen is only in libc
46- return false ;
76+ dlopen_libc6 ( null , RTLD_NOW ) ;
77+ return DlLibrary . Libc6 ;
4778 }
79+ catch ( DllNotFoundException ) { }
80+ catch ( EntryPointNotFoundException ) { }
81+
82+ // Fall back to libc (musl/Alpine)
83+ return DlLibrary . Libc ;
4884 }
4985
50- public static IntPtr dlopen ( string path , int flags ) =>
51- UseLibdl ? dlopen_libdl ( path , flags ) : dlopen_libc ( path , flags ) ;
86+ public static IntPtr dlopen ( string path , int flags )
87+ {
88+ switch ( ActiveLibrary )
89+ {
90+ case DlLibrary . Libdl : return dlopen_libdl ( path , flags ) ;
91+ case DlLibrary . Libdl2 : return dlopen_libdl2 ( path , flags ) ;
92+ case DlLibrary . Libc6 : return dlopen_libc6 ( path , flags ) ;
93+ default : return dlopen_libc ( path , flags ) ;
94+ }
95+ }
5296
53- public static int dlclose ( IntPtr handle ) =>
54- UseLibdl ? dlclose_libdl ( handle ) : dlclose_libc ( handle ) ;
97+ public static int dlclose ( IntPtr handle )
98+ {
99+ switch ( ActiveLibrary )
100+ {
101+ case DlLibrary . Libdl : return dlclose_libdl ( handle ) ;
102+ case DlLibrary . Libdl2 : return dlclose_libdl2 ( handle ) ;
103+ case DlLibrary . Libc6 : return dlclose_libc6 ( handle ) ;
104+ default : return dlclose_libc ( handle ) ;
105+ }
106+ }
55107
56- public static IntPtr dlerror ( ) =>
57- UseLibdl ? dlerror_libdl ( ) : dlerror_libc ( ) ;
108+ public static IntPtr dlerror ( )
109+ {
110+ switch ( ActiveLibrary )
111+ {
112+ case DlLibrary . Libdl : return dlerror_libdl ( ) ;
113+ case DlLibrary . Libdl2 : return dlerror_libdl2 ( ) ;
114+ case DlLibrary . Libc6 : return dlerror_libc6 ( ) ;
115+ default : return dlerror_libc ( ) ;
116+ }
117+ }
58118
59- public static IntPtr dlsym ( IntPtr handle , string name ) =>
60- UseLibdl ? dlsym_libdl ( handle , name ) : dlsym_libc ( handle , name ) ;
119+ public static IntPtr dlsym ( IntPtr handle , string name )
120+ {
121+ switch ( ActiveLibrary )
122+ {
123+ case DlLibrary . Libdl : return dlsym_libdl ( handle , name ) ;
124+ case DlLibrary . Libdl2 : return dlsym_libdl2 ( handle , name ) ;
125+ case DlLibrary . Libc6 : return dlsym_libc6 ( handle , name ) ;
126+ default : return dlsym_libc ( handle , name ) ;
127+ }
128+ }
61129 }
62130}
0 commit comments