2 #include "mono/metadata/assembly-internals.h"
3 #include "mono/metadata/class-internals.h"
4 #include "mono/metadata/icall-decl.h"
5 #include "mono/metadata/loader-internals.h"
6 #include "mono/metadata/loader.h"
7 #include "mono/metadata/object-internals.h"
8 #include "mono/metadata/reflection-internals.h"
9 #include "mono/utils/checked-build.h"
10 #include "mono/utils/mono-compiler.h"
11 #include "mono/utils/mono-logger-internals.h"
12 #include "mono/utils/mono-path.h"
13 #include "mono/metadata/native-library.h"
14 #include "mono/metadata/custom-attrs-internals.h"
17 static int pinvoke_search_directories_count
;
18 static char **pinvoke_search_directories
;
20 // sync with src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/DllImportSearchPath.cs
23 DLLIMPORTSEARCHPATH_LEGACY_BEHAVIOR
= 0x0, // when no other flags are present, search the application directory and then call LoadLibraryEx with LOAD_WITH_ALTERED_SEARCH_PATH
24 DLLIMPORTSEARCHPATH_USE_DLL_DIRECTORY_FOR_DEPENDENCIES
= 0x100,
25 DLLIMPORTSEARCHPATH_APPLICATION_DIRECTORY
= 0x200,
26 DLLIMPORTSEARCHPATH_USER_DIRECTORIES
= 0x400,
27 DLLIMPORTSEARCHPATH_SYSTEM32
= 0x800,
28 DLLIMPORTSEARCHPATH_SAFE_DIRECTORIES
= 0x1000,
29 DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY
= 0x2, // search the assembly directory first regardless of platform, not passed on to LoadLibraryEx
30 } DllImportSearchPath
;
32 static const int DLLIMPORTSEARCHPATH_LOADLIBRARY_FLAG_MASK
= DLLIMPORTSEARCHPATH_USE_DLL_DIRECTORY_FOR_DEPENDENCIES
| DLLIMPORTSEARCHPATH_APPLICATION_DIRECTORY
|
33 DLLIMPORTSEARCHPATH_USER_DIRECTORIES
| DLLIMPORTSEARCHPATH_SYSTEM32
| DLLIMPORTSEARCHPATH_SAFE_DIRECTORIES
;
36 // This lock may be taken within an ALC lock, and should never be the other way around.
37 static MonoCoopMutex native_library_module_lock
;
38 static GHashTable
*native_library_module_map
;
40 * This blocklist is used as a set for cache invalidation purposes with netcore pinvokes.
41 * When pinvokes are resolved with anything other than the last-chance managed event,
42 * the results of that lookup are added to an ALC-level cache. However, if a library is then
43 * unloaded with NativeLibrary.Free(), this cache should be invalidated so that a newly called
44 * pinvoke will not attempt to use it, hence the blocklist. This design means that if another
45 * library is loaded at the same address, it will function with a perf hit, as the entry will
46 * repeatedly be added and removed from the cache due to its presence in the blocklist.
47 * This is a rare scenario and considered a worthwhile tradeoff.
49 static GHashTable
*native_library_module_blocklist
;
52 #ifndef DISABLE_DLLMAP
53 static MonoDllMap
*global_dll_map
;
56 static GHashTable
*global_module_map
; // should only be accessed with the global loader data lock
58 static MonoDl
*internal_module
; // used when pinvoking `__Internal`
60 // Did we initialize the temporary directory for dynamic libraries
61 // FIXME: this is racy
62 static gboolean bundle_save_library_initialized
;
64 // List of bundled libraries we unpacked
65 static GSList
*bundle_library_paths
;
67 // Directory where we unpacked dynamic libraries
68 static char *bundled_dylibrary_directory
;
70 /* Class lazy loading functions */
71 GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception
, "System", "AppDomainUnloadedException")
72 GENERATE_TRY_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception
, "System", "AppDomainUnloadedException")
74 GENERATE_GET_CLASS_WITH_CACHE (native_library
, "System.Runtime.InteropServices", "NativeLibrary");
75 static GENERATE_TRY_GET_CLASS_WITH_CACHE (dllimportsearchpath_attribute
, "System.Runtime.InteropServices", "DefaultDllImportSearchPathsAttribute");
78 #ifndef DISABLE_DLLMAP
80 * LOCKING: Assumes the relevant lock is held.
81 * For the global DllMap, this is `global_loader_data_mutex`, and for images it's their internal lock.
84 mono_dllmap_lookup_list (MonoDllMap
*dll_map
, const char *dll
, const char* func
, const char **rdll
, const char **rfunc
) {
94 * we use the first entry we find that matches, since entries from
95 * the config file are prepended to the list and we document that the
98 for (; dll_map
; dll_map
= dll_map
->next
) {
99 // Check case-insensitively when the dll name is prefixed with 'i:'
100 gboolean case_insensitive_match
= strncmp (dll_map
->dll
, "i:", 2) == 0 && g_ascii_strcasecmp (dll_map
->dll
+ 2, dll
) == 0;
101 gboolean case_sensitive_match
= strcmp (dll_map
->dll
, dll
) == 0;
102 if (!(case_insensitive_match
|| case_sensitive_match
))
105 if (!found
&& dll_map
->target
) {
106 *rdll
= dll_map
->target
;
108 /* we don't quit here, because we could find a full
109 * entry that also matches the function, which takes priority.
112 if (dll_map
->func
&& strcmp (dll_map
->func
, func
) == 0) {
113 *rdll
= dll_map
->target
;
114 *rfunc
= dll_map
->target_func
;
120 *rdll
= g_strdup (*rdll
);
121 *rfunc
= g_strdup (*rfunc
);
126 * The locking and GC state transitions here are wonky due to the fact the image lock is a coop lock
127 * and the global loader data lock is an OS lock.
130 mono_dllmap_lookup (MonoImage
*assembly
, const char *dll
, const char* func
, const char **rdll
, const char **rfunc
)
134 MONO_REQ_GC_UNSAFE_MODE
;
136 if (assembly
&& assembly
->dll_map
) {
137 mono_image_lock (assembly
);
138 res
= mono_dllmap_lookup_list (assembly
->dll_map
, dll
, func
, rdll
, rfunc
);
139 mono_image_unlock (assembly
);
146 mono_global_loader_data_lock ();
147 res
= mono_dllmap_lookup_list (global_dll_map
, dll
, func
, rdll
, rfunc
);
148 mono_global_loader_data_unlock ();
156 dllmap_insert_global (const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
160 entry
= (MonoDllMap
*)g_malloc0 (sizeof (MonoDllMap
));
161 entry
->dll
= dll
? g_strdup (dll
): NULL
;
162 entry
->target
= tdll
? g_strdup (tdll
): NULL
;
163 entry
->func
= func
? g_strdup (func
): NULL
;
164 entry
->target_func
= tfunc
? g_strdup (tfunc
): (func
? g_strdup (func
): NULL
);
166 // No transition here because this is early in startup
167 mono_global_loader_data_lock ();
168 entry
->next
= global_dll_map
;
169 global_dll_map
= entry
;
170 mono_global_loader_data_unlock ();
175 dllmap_insert_image (MonoImage
*assembly
, const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
178 g_assert (assembly
!= NULL
);
180 MONO_REQ_GC_UNSAFE_MODE
;
182 entry
= (MonoDllMap
*)mono_image_alloc0 (assembly
, sizeof (MonoDllMap
));
183 entry
->dll
= dll
? mono_image_strdup (assembly
, dll
): NULL
;
184 entry
->target
= tdll
? mono_image_strdup (assembly
, tdll
): NULL
;
185 entry
->func
= func
? mono_image_strdup (assembly
, func
): NULL
;
186 entry
->target_func
= tfunc
? mono_image_strdup (assembly
, tfunc
): (func
? mono_image_strdup (assembly
, func
): NULL
);
188 mono_image_lock (assembly
);
189 entry
->next
= assembly
->dll_map
;
190 assembly
->dll_map
= entry
;
191 mono_image_unlock (assembly
);
195 * LOCKING: Assumes the relevant lock is held.
196 * For the global DllMap, this is `global_loader_data_mutex`, and for images it's their internal lock.
199 free_dllmap (MonoDllMap
*map
)
202 MonoDllMap
*next
= map
->next
;
205 g_free (map
->target
);
207 g_free (map
->target_func
);
214 mono_dllmap_insert_internal (MonoImage
*assembly
, const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
217 // The locking in here is _really_ wonky, and I'm not convinced this function should exist.
218 // I've split it into an internal version to offer flexibility in the future.
220 dllmap_insert_global (dll
, func
, tdll
, tfunc
);
222 dllmap_insert_image (assembly
, dll
, func
, tdll
, tfunc
);
226 mono_global_dllmap_cleanup (void)
228 // No need for a transition here since the thread is already detached from the runtime
229 mono_global_loader_data_lock ();
231 free_dllmap (global_dll_map
);
232 global_dll_map
= NULL
;
234 // We don't care about freeing native_library_module_map on netcore because of the expedited shutdown.
236 mono_global_loader_data_unlock ();
241 * mono_dllmap_insert:
242 * \param assembly if NULL, this is a global mapping, otherwise the remapping of the dynamic library will only apply to the specified assembly
243 * \param dll The name of the external library, as it would be found in the \c DllImport declaration. If prefixed with <code>i:</code> the matching of the library name is done without case sensitivity
244 * \param func if not null, the mapping will only applied to the named function (the value of <code>EntryPoint</code>)
245 * \param tdll The name of the library to map the specified \p dll if it matches.
246 * \param tfunc The name of the function that replaces the invocation. If NULL, it is replaced with a copy of \p func.
248 * LOCKING: Acquires the image lock, or the loader data lock if an image is not passed.
250 * This function is used to programatically add \c DllImport remapping in either
251 * a specific assembly, or as a global remapping. This is done by remapping
252 * references in a \c DllImport attribute from the \p dll library name into the \p tdll
253 * name. If the \p dll name contains the prefix <code>i:</code>, the comparison of the
254 * library name is done without case sensitivity.
256 * If you pass \p func, this is the name of the \c EntryPoint in a \c DllImport if specified
257 * or the name of the function as determined by \c DllImport. If you pass \p func, you
258 * must also pass \p tfunc which is the name of the target function to invoke on a match.
262 * <code>mono_dllmap_insert (NULL, "i:libdemo.dll", NULL, relocated_demo_path, NULL);</code>
264 * The above will remap \c DllImport statements for \c libdemo.dll and \c LIBDEMO.DLL to
265 * the contents of \c relocated_demo_path for all assemblies in the Mono process.
267 * NOTE: This can be called before the runtime is initialized, for example from
268 * \c mono_config_parse.
271 mono_dllmap_insert (MonoImage
*assembly
, const char *dll
, const char *func
, const char *tdll
, const char *tfunc
)
273 #ifndef DISABLE_DLLMAP
274 mono_dllmap_insert_internal (assembly
, dll
, func
, tdll
, tfunc
);
276 g_assert_not_reached ();
281 mono_loader_register_module (const char *name
, MonoDl
*module
)
285 // No transition here because this is early in startup
286 mono_global_loader_data_lock ();
288 g_hash_table_insert (global_module_map
, g_strdup (name
), module
);
290 mono_global_loader_data_unlock ();
293 #ifdef ENABLE_NETCORE
295 mono_loader_register_module_locking (const char *name
, MonoDl
*module
)
297 MonoDl
*result
= NULL
;
300 mono_global_loader_data_lock ();
303 result
= (MonoDl
*)g_hash_table_lookup (global_module_map
, name
);
305 g_free (module
->full_name
);
310 g_hash_table_insert (global_module_map
, g_strdup (name
), module
);
315 mono_global_loader_data_unlock ();
323 remove_cached_module (gpointer key
, gpointer value
, gpointer user_data
)
325 mono_dl_close((MonoDl
*)value
);
329 mono_global_loader_cache_init (void)
331 if (!global_module_map
)
332 global_module_map
= g_hash_table_new (g_str_hash
, g_str_equal
);
334 #ifdef ENABLE_NETCORE
335 if (!native_library_module_map
)
336 native_library_module_map
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
337 if (!native_library_module_blocklist
)
338 native_library_module_blocklist
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
339 mono_coop_mutex_init (&native_library_module_lock
);
344 mono_global_loader_cache_cleanup (void)
346 if (global_module_map
!= NULL
) {
347 g_hash_table_foreach(global_module_map
, remove_cached_module
, NULL
);
349 g_hash_table_destroy(global_module_map
);
350 global_module_map
= NULL
;
353 // No need to clean up the native library hash tables since they're netcore-only, where this is never called
357 is_absolute_path (const char *path
)
359 // FIXME: other platforms have similar prefixes, such as $ORIGIN
361 if (!strncmp (path
, "@executable_path/", 17) || !strncmp (path
, "@loader_path/", 13) || !strncmp (path
, "@rpath/", 7))
364 return g_path_is_absolute (path
);
368 lookup_pinvoke_call_impl (MonoMethod
*method
, MonoLookupPInvokeStatus
*status_out
);
371 pinvoke_probe_for_symbol (MonoDl
*module
, MonoMethodPInvoke
*piinfo
, const char *import
, char **error_msg_out
);
374 pinvoke_probe_convert_status_for_api (MonoLookupPInvokeStatus
*status
, const char **exc_class
, const char **exc_arg
)
378 switch (status
->err_code
) {
379 case LOOKUP_PINVOKE_ERR_OK
:
383 case LOOKUP_PINVOKE_ERR_NO_LIB
:
384 *exc_class
= "DllNotFoundException";
385 *exc_arg
= status
->err_arg
;
386 status
->err_arg
= NULL
;
388 case LOOKUP_PINVOKE_ERR_NO_SYM
:
389 *exc_class
= "EntryPointNotFoundException";
390 *exc_arg
= status
->err_arg
;
391 status
->err_arg
= NULL
;
394 g_assert_not_reached ();
399 pinvoke_probe_convert_status_to_error (MonoLookupPInvokeStatus
*status
, MonoError
*error
)
401 /* Note: this has to return a MONO_ERROR_GENERIC because mono_mb_emit_exception_for_error only knows how to decode generic errors. */
402 switch (status
->err_code
) {
403 case LOOKUP_PINVOKE_ERR_OK
:
405 case LOOKUP_PINVOKE_ERR_NO_LIB
:
406 mono_error_set_generic_error (error
, "System", "DllNotFoundException", "%s", status
->err_arg
);
407 g_free (status
->err_arg
);
408 status
->err_arg
= NULL
;
410 case LOOKUP_PINVOKE_ERR_NO_SYM
:
411 mono_error_set_generic_error (error
, "System", "EntryPointNotFoundException", "%s", status
->err_arg
);
412 g_free (status
->err_arg
);
413 status
->err_arg
= NULL
;
416 g_assert_not_reached ();
421 * mono_lookup_pinvoke_call:
424 mono_lookup_pinvoke_call (MonoMethod
*method
, const char **exc_class
, const char **exc_arg
)
427 MONO_ENTER_GC_UNSAFE
;
428 MonoLookupPInvokeStatus status
;
429 memset (&status
, 0, sizeof (status
));
430 result
= lookup_pinvoke_call_impl (method
, &status
);
431 pinvoke_probe_convert_status_for_api (&status
, exc_class
, exc_arg
);
437 mono_lookup_pinvoke_call_internal (MonoMethod
*method
, MonoError
*error
)
440 MonoLookupPInvokeStatus status
;
441 memset (&status
, 0, sizeof (status
));
442 result
= lookup_pinvoke_call_impl (method
, &status
);
444 pinvoke_probe_convert_status_to_error (&status
, error
);
448 #ifdef ENABLE_NETCORE
450 mono_set_pinvoke_search_directories (int dir_count
, char **dirs
)
452 pinvoke_search_directories_count
= dir_count
;
453 g_strfreev (pinvoke_search_directories
);
454 pinvoke_search_directories
= dirs
;
458 native_library_lock (void)
460 mono_coop_mutex_lock (&native_library_module_lock
);
464 native_library_unlock (void)
466 mono_coop_mutex_unlock (&native_library_module_lock
);
470 alc_pinvoke_lock (MonoAssemblyLoadContext
*alc
)
472 mono_coop_mutex_lock (&alc
->pinvoke_lock
);
476 alc_pinvoke_unlock (MonoAssemblyLoadContext
*alc
)
478 mono_coop_mutex_unlock (&alc
->pinvoke_lock
);
481 // LOCKING: expects you to hold native_library_module_lock
483 netcore_handle_lookup (gpointer handle
)
485 return (MonoDl
*)g_hash_table_lookup (native_library_module_map
, handle
);
488 // LOCKING: expects you to hold native_library_module_lock
490 netcore_check_blocklist (MonoDl
*module
)
492 return g_hash_table_contains (native_library_module_blocklist
, module
);
496 convert_dllimport_flags (int flags
)
499 return flags
& DLLIMPORTSEARCHPATH_LOADLIBRARY_FLAG_MASK
;
501 // DllImportSearchPath is Windows-only, other than DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY
507 netcore_probe_for_module_variations (const char *mdirname
, const char *file_name
, int raw_flags
)
511 MonoDl
*module
= NULL
;
513 // FIXME: this appears to search *.dylib twice for some reason
514 while ((full_name
= mono_dl_build_path (mdirname
, file_name
, &iter
)) && module
== NULL
) {
516 module
= mono_dl_open_full (full_name
, MONO_DL_LAZY
, raw_flags
, &error_msg
);
518 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '%s': '%s'.", full_name
, error_msg
);
529 netcore_probe_for_module (MonoImage
*image
, const char *file_name
, int flags
)
531 MonoDl
*module
= NULL
;
532 int lflags
= convert_dllimport_flags (flags
);
534 // TODO: this algorithm doesn't quite match CoreCLR, so respecting DLLIMPORTSEARCHPATH_LEGACY_BEHAVIOR makes little sense
535 // If the difference becomes a problem, overhaul this algorithm to match theirs exactly
537 // Try without any path additions
538 module
= netcore_probe_for_module_variations (NULL
, file_name
, lflags
);
540 // Check the NATIVE_DLL_SEARCH_DIRECTORIES
541 for (int i
= 0; i
< pinvoke_search_directories_count
&& module
== NULL
; ++i
)
542 module
= netcore_probe_for_module_variations (pinvoke_search_directories
[i
], file_name
, lflags
);
544 // Check the assembly directory if the search flag is set and the image exists
545 if (flags
& DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY
&& image
!= NULL
&& module
== NULL
) {
546 char *mdirname
= g_path_get_dirname (image
->filename
);
548 module
= netcore_probe_for_module_variations (mdirname
, file_name
, lflags
);
552 // TODO: Pass remaining flags on to LoadLibraryEx on Windows where appropriate, see https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.dllimportsearchpath?view=netcore-3.1
558 netcore_resolve_with_dll_import_resolver (MonoAssemblyLoadContext
*alc
, MonoAssembly
*assembly
, const char *scope
, guint32 flags
, MonoError
*error
)
560 MonoDl
*result
= NULL
;
562 MonoDomain
*domain
= mono_alc_domain (alc
);
564 MONO_STATIC_POINTER_INIT (MonoMethod
, resolve
)
566 ERROR_DECL (local_error
);
567 MonoClass
*native_lib_class
= mono_class_get_native_library_class ();
568 g_assert (native_lib_class
);
569 resolve
= mono_class_get_method_from_name_checked (native_lib_class
, "MonoLoadLibraryCallbackStub", -1, 0, local_error
);
570 mono_error_assert_ok (local_error
);
572 MONO_STATIC_POINTER_INIT_END (MonoMethod
, resolve
)
575 if (mono_runtime_get_no_exec ())
578 HANDLE_FUNCTION_ENTER ();
580 MonoStringHandle scope_handle
;
581 scope_handle
= mono_string_new_handle (domain
, scope
, error
);
582 goto_if_nok (error
, leave
);
584 MonoReflectionAssemblyHandle assembly_handle
;
585 assembly_handle
= mono_assembly_get_object_handle (domain
, assembly
, error
);
586 goto_if_nok (error
, leave
);
588 gboolean has_search_flags
;
589 has_search_flags
= flags
!= 0 ? TRUE
: FALSE
;
591 args
[0] = MONO_HANDLE_RAW (scope_handle
);
592 args
[1] = MONO_HANDLE_RAW (assembly_handle
);
593 args
[2] = &has_search_flags
;
596 mono_runtime_invoke_checked (resolve
, NULL
, args
, error
);
597 goto_if_nok (error
, leave
);
599 native_library_lock ();
600 result
= netcore_handle_lookup (lib
);
601 native_library_unlock ();
604 HANDLE_FUNCTION_RETURN_VAL (result
);
608 netcore_resolve_with_dll_import_resolver_nofail (MonoAssemblyLoadContext
*alc
, MonoAssembly
*assembly
, const char *scope
, guint32 flags
)
610 MonoDl
*result
= NULL
;
613 result
= netcore_resolve_with_dll_import_resolver (alc
, assembly
, scope
, flags
, error
);
615 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Error while invoking ALC DllImportResolver(\"%s\") delegate: '%s'", scope
, mono_error_get_message (error
));
617 mono_error_cleanup (error
);
623 netcore_resolve_with_load (MonoAssemblyLoadContext
*alc
, const char *scope
, MonoError
*error
)
625 MonoDl
*result
= NULL
;
628 MONO_STATIC_POINTER_INIT (MonoMethod
, resolve
)
630 ERROR_DECL (local_error
);
631 MonoClass
*alc_class
= mono_class_get_assembly_load_context_class ();
632 g_assert (alc_class
);
633 resolve
= mono_class_get_method_from_name_checked (alc_class
, "MonoResolveUnmanagedDll", -1, 0, local_error
);
634 mono_error_assert_ok (local_error
);
636 MONO_STATIC_POINTER_INIT_END (MonoMethod
, resolve
)
639 if (mono_runtime_get_no_exec ())
642 HANDLE_FUNCTION_ENTER ();
644 MonoStringHandle scope_handle
;
645 scope_handle
= mono_string_new_handle (mono_alc_domain (alc
), scope
, error
);
646 goto_if_nok (error
, leave
);
649 gchandle
= GUINT_TO_POINTER (alc
->gchandle
);
651 args
[0] = MONO_HANDLE_RAW (scope_handle
);
652 args
[1] = &gchandle
;
654 mono_runtime_invoke_checked (resolve
, NULL
, args
, error
);
655 goto_if_nok (error
, leave
);
657 native_library_lock ();
658 result
= netcore_handle_lookup (lib
);
659 native_library_unlock ();
662 HANDLE_FUNCTION_RETURN_VAL (result
);
666 netcore_resolve_with_load_nofail (MonoAssemblyLoadContext
*alc
, const char *scope
)
668 MonoDl
*result
= NULL
;
671 result
= netcore_resolve_with_load (alc
, scope
, error
);
673 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Error while invoking ALC LoadUnmanagedDll(\"%s\") method: '%s'", scope
, mono_error_get_message (error
));
675 mono_error_cleanup (error
);
681 netcore_resolve_with_resolving_event (MonoAssemblyLoadContext
*alc
, MonoAssembly
*assembly
, const char *scope
, MonoError
*error
)
683 MonoDl
*result
= NULL
;
685 MonoDomain
*domain
= mono_alc_domain (alc
);
687 MONO_STATIC_POINTER_INIT (MonoMethod
, resolve
)
689 ERROR_DECL (local_error
);
690 MonoClass
*alc_class
= mono_class_get_assembly_load_context_class ();
691 g_assert (alc_class
);
692 resolve
= mono_class_get_method_from_name_checked (alc_class
, "MonoResolveUnmanagedDllUsingEvent", -1, 0, local_error
);
693 mono_error_assert_ok (local_error
);
695 MONO_STATIC_POINTER_INIT_END (MonoMethod
, resolve
)
698 if (mono_runtime_get_no_exec ())
701 HANDLE_FUNCTION_ENTER ();
703 MonoStringHandle scope_handle
;
704 scope_handle
= mono_string_new_handle (domain
, scope
, error
);
705 goto_if_nok (error
, leave
);
707 MonoReflectionAssemblyHandle assembly_handle
;
708 assembly_handle
= mono_assembly_get_object_handle (domain
, assembly
, error
);
709 goto_if_nok (error
, leave
);
712 gchandle
= GUINT_TO_POINTER (alc
->gchandle
);
714 args
[0] = MONO_HANDLE_RAW (scope_handle
);
715 args
[1] = MONO_HANDLE_RAW (assembly_handle
);
716 args
[2] = &gchandle
;
718 mono_runtime_invoke_checked (resolve
, NULL
, args
, error
);
719 goto_if_nok (error
, leave
);
721 native_library_lock ();
722 result
= netcore_handle_lookup (lib
);
723 native_library_unlock ();
726 HANDLE_FUNCTION_RETURN_VAL (result
);
730 netcore_resolve_with_resolving_event_nofail (MonoAssemblyLoadContext
*alc
, MonoAssembly
*assembly
, const char *scope
)
732 MonoDl
*result
= NULL
;
735 result
= netcore_resolve_with_resolving_event (alc
, assembly
, scope
, error
);
737 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Error while invoking ALC ResolvingUnmangedDll(\"%s\") event: '%s'", scope
, mono_error_get_message (error
));
739 mono_error_cleanup (error
);
744 // LOCKING: expects you to hold the ALC's pinvoke lock
746 netcore_check_alc_cache (MonoAssemblyLoadContext
*alc
, const char *scope
)
748 MonoDl
*result
= NULL
;
750 result
= (MonoDl
*)g_hash_table_lookup (alc
->pinvoke_scopes
, scope
);
753 gboolean blocklisted
;
755 native_library_lock ();
756 blocklisted
= netcore_check_blocklist (result
);
757 native_library_unlock ();
760 g_hash_table_remove (alc
->pinvoke_scopes
, scope
);
769 netcore_lookup_native_library (MonoAssemblyLoadContext
*alc
, MonoImage
*image
, const char *scope
, guint32 flags
)
771 MonoDl
*module
= NULL
;
773 MonoAssembly
*assembly
= mono_image_get_assembly (image
);
774 char *error_msg
= NULL
;
776 MONO_REQ_GC_UNSAFE_MODE
;
778 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "DllImport attempting to load: '%s'.", scope
);
780 // We allow a special name to dlopen from the running process namespace, which is not present in CoreCLR
781 if (strcmp (scope
, "__Internal") == 0) {
782 if (!internal_module
)
783 internal_module
= mono_dl_open_self (&error_msg
);
784 module
= internal_module
;
787 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '__Internal': '%s'.", error_msg
);
791 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Native library found via __Internal: '%s'.", scope
);
797 * Try these until one of them succeeds:
799 * 1. Check the cache in the active ALC.
801 * 2. Call the DllImportResolver on the active assembly.
803 * 3. Call LoadUnmanagedDll on the active ALC.
805 * 4. Check the global cache.
807 * 5. Run the unmanaged probing logic.
809 * 6. Raise the ResolvingUnmanagedDll event on the active ALC.
814 alc_pinvoke_lock (alc
);
815 module
= netcore_check_alc_cache (alc
, scope
);
816 alc_pinvoke_unlock (alc
);
818 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Native library found in the active ALC cache: '%s'.", scope
);
822 module
= (MonoDl
*)netcore_resolve_with_dll_import_resolver_nofail (alc
, assembly
, scope
, flags
);
824 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Native library found via DllImportResolver: '%s'.", scope
);
825 goto add_to_alc_cache
;
828 module
= (MonoDl
*)netcore_resolve_with_load_nofail (alc
, scope
);
830 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Native library found via LoadUnmanagedDll: '%s'.", scope
);
831 goto add_to_alc_cache
;
835 mono_global_loader_data_lock ();
837 module
= (MonoDl
*)g_hash_table_lookup (global_module_map
, scope
);
839 mono_global_loader_data_unlock ();
842 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Native library found in the global cache: '%s'.", scope
);
843 goto add_to_alc_cache
;
846 module
= netcore_probe_for_module (image
, scope
, flags
);
848 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Native library found via filesystem probing: '%s'.", scope
);
849 goto add_to_global_cache
;
852 /* As this is last chance, I've opted not to put it in a cache, but that is not necessarily the correct decision.
853 * It is rather convenient here, however, because it means the global cache will only be populated by libraries
854 * resolved via netcore_probe_for_module and not NativeLibrary, eliminating potential races/conflicts.
856 module
= netcore_resolve_with_resolving_event_nofail (alc
, assembly
, scope
);
858 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "Native library found via the Resolving event: '%s'.", scope
);
862 module
= mono_loader_register_module_locking (scope
, module
);
865 /* Nothing is closed here because the only two places this can come from are:
866 * 1. A managed callback that made use of NativeLibrary.Load, in which case closing is dependent on NativeLibrary.Free
867 * 2. The global cache, which is only populated by results of netcore_probe_for_module. When adding to the global cache,
868 * we free the new MonoDl if another thread beat us, so we don't have to repeat that here.
870 alc_pinvoke_lock (alc
);
871 cached
= netcore_check_alc_cache (alc
, scope
);
875 g_hash_table_insert (alc
->pinvoke_scopes
, g_strdup (scope
), module
);
876 alc_pinvoke_unlock (alc
);
883 get_dllimportsearchpath_flags (MonoCustomAttrInfo
*cinfo
)
886 MonoCustomAttrEntry
*attr
= NULL
;
887 MonoClass
*dllimportsearchpath
= mono_class_try_get_dllimportsearchpath_attribute_class ();
891 if (!dllimportsearchpath
)
896 for (idx
= 0; idx
< cinfo
->num_attrs
; ++idx
) {
897 MonoClass
*ctor_class
= cinfo
->attrs
[idx
].ctor
->klass
;
898 if (ctor_class
== dllimportsearchpath
) {
899 attr
= &cinfo
->attrs
[idx
];
906 gpointer
*typed_args
, *named_args
;
907 CattrNamedArg
*arginfo
;
910 mono_reflection_create_custom_attr_data_args_noalloc (m_class_get_image (attr
->ctor
->klass
), attr
->ctor
, attr
->data
, attr
->data_size
,
911 &typed_args
, &named_args
, &num_named_args
, &arginfo
, error
);
912 if (!is_ok (error
)) {
913 mono_error_cleanup (error
);
917 flags
= *(gint32
*)typed_args
[0];
918 g_free (typed_args
[0]);
926 #else // ENABLE_NETCORE
929 cached_module_load (const char *name
, int flags
, char **err
)
937 mono_global_loader_data_lock ();
940 res
= (MonoDl
*)g_hash_table_lookup (global_module_map
, name
);
944 res
= mono_dl_open (name
, flags
, err
);
946 g_hash_table_insert (global_module_map
, g_strdup (name
), res
);
950 mono_global_loader_data_unlock ();
957 * legacy_probe_transform_path:
959 * Try transforming the library path given in \p new_scope in different ways
960 * depending on \p phase
962 * \returns \c TRUE if a transformation was applied and the transformed path
963 * components are written to the out arguments, or \c FALSE if a transformation
967 legacy_probe_transform_path (const char *new_scope
, int phase
, char **file_name_out
, char **base_name_out
, char **dir_name_out
, gboolean
*is_absolute_out
)
969 char *file_name
= NULL
, *base_name
= NULL
, *dir_name
= NULL
;
970 gboolean changed
= FALSE
;
971 gboolean is_absolute
= is_absolute_path (new_scope
);
974 /* Try the original name */
975 file_name
= g_strdup (new_scope
);
979 /* Try trimming the .dll extension */
980 if (strstr (new_scope
, ".dll") == (new_scope
+ strlen (new_scope
) - 4)) {
981 file_name
= g_strdup (new_scope
);
982 file_name
[strlen (new_scope
) - 4] = '\0';
988 dir_name
= g_path_get_dirname (new_scope
);
989 base_name
= g_path_get_basename (new_scope
);
990 if (strstr (base_name
, "lib") != base_name
) {
991 char *tmp
= g_strdup_printf ("lib%s", base_name
);
994 file_name
= g_strdup_printf ("%s%s%s", dir_name
, G_DIR_SEPARATOR_S
, base_name
);
997 } else if (strstr (new_scope
, "lib") != new_scope
) {
998 file_name
= g_strdup_printf ("lib%s", new_scope
);
1003 if (!is_absolute
&& mono_dl_get_system_dir ()) {
1004 dir_name
= (char*)mono_dl_get_system_dir ();
1005 file_name
= g_path_get_basename (new_scope
);
1011 #ifndef TARGET_WIN32
1012 if (!g_ascii_strcasecmp ("user32.dll", new_scope
) ||
1013 !g_ascii_strcasecmp ("kernel32.dll", new_scope
) ||
1014 !g_ascii_strcasecmp ("user32", new_scope
) ||
1015 !g_ascii_strcasecmp ("kernel", new_scope
)) {
1016 file_name
= g_strdup ("libMonoSupportW.so");
1022 if (changed
&& is_absolute
) {
1024 dir_name
= g_path_get_dirname (file_name
);
1026 base_name
= g_path_get_basename (file_name
);
1028 *file_name_out
= file_name
;
1029 *base_name_out
= base_name
;
1030 *dir_name_out
= dir_name
;
1031 *is_absolute_out
= is_absolute
;
1036 legacy_probe_for_module_in_directory (const char *mdirname
, const char *file_name
)
1040 MonoDl
* module
= NULL
;
1042 while ((full_name
= mono_dl_build_path (mdirname
, file_name
, &iter
)) && module
== NULL
) {
1044 module
= cached_module_load (full_name
, MONO_DL_LAZY
, &error_msg
);
1046 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '%s': '%s'.", full_name
, error_msg
);
1057 legacy_probe_for_module_relative_directories (MonoImage
*image
, const char *file_name
)
1059 MonoDl
* module
= NULL
;
1061 for (int j
= 0; j
< 3; ++j
) {
1062 char *mdirname
= NULL
;
1066 mdirname
= g_path_get_dirname (image
->filename
);
1068 case 1: // @executable_path@/../lib
1070 char buf
[4096]; // FIXME: MAX_PATH
1072 binl
= mono_dl_get_executable_path (buf
, sizeof (buf
));
1074 char *base
, *newbase
;
1077 resolvedname
= mono_path_resolve_symlinks (buf
);
1079 base
= g_path_get_dirname (resolvedname
);
1080 newbase
= g_path_get_dirname(base
);
1082 // On Android the executable for the application is going to be /system/bin/app_process{32,64} depending on
1083 // the application's architecture. However, libraries for the different architectures live in different
1084 // subdirectories of `/system`: `lib` for 32-bit apps and `lib64` for 64-bit ones. Thus appending `/lib` below
1085 // will fail to load the DSO for a 64-bit app, even if it exists there, because it will have a different
1086 // architecture. This is the cause of https://github.com/xamarin/xamarin-android/issues/2780 and the ifdef
1087 // below is the fix.
1088 mdirname
= g_strdup_printf (
1089 #if defined(TARGET_ANDROID) && (defined(TARGET_ARM64) || defined(TARGET_AMD64))
1095 g_free (resolvedname
);
1102 case 2: // @executable_path@/../Libraries
1104 char buf
[4096]; // FIXME: MAX_PATH
1106 binl
= mono_dl_get_executable_path (buf
, sizeof (buf
));
1108 char *base
, *newbase
;
1111 resolvedname
= mono_path_resolve_symlinks (buf
);
1113 base
= g_path_get_dirname (resolvedname
);
1114 newbase
= g_path_get_dirname(base
);
1115 mdirname
= g_strdup_printf ("%s/Libraries", newbase
);
1117 g_free (resolvedname
);
1129 module
= legacy_probe_for_module_in_directory (mdirname
, file_name
);
1139 legacy_probe_for_module (MonoImage
*image
, const char *new_scope
)
1141 char *full_name
, *file_name
;
1142 char *error_msg
= NULL
;
1144 MonoDl
*module
= NULL
;
1146 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "DllImport attempting to load: '%s'.", new_scope
);
1148 /* we allow a special name to dlopen from the running process namespace */
1149 if (strcmp (new_scope
, "__Internal") == 0) {
1150 if (!internal_module
)
1151 internal_module
= mono_dl_open (NULL
, MONO_DL_LAZY
, &error_msg
);
1152 module
= internal_module
;
1155 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '__Internal': '%s'.", error_msg
);
1163 * Try loading the module using a variety of names
1165 for (i
= 0; i
< 5; ++i
) {
1166 char *base_name
= NULL
, *dir_name
= NULL
;
1167 gboolean is_absolute
;
1169 gboolean changed
= legacy_probe_transform_path (new_scope
, i
, &file_name
, &base_name
, &dir_name
, &is_absolute
);
1173 if (!module
&& is_absolute
) {
1174 module
= cached_module_load (file_name
, MONO_DL_LAZY
, &error_msg
);
1176 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
,
1177 "DllImport error loading library '%s': '%s'.",
1178 file_name
, error_msg
);
1183 if (!module
&& !is_absolute
) {
1184 module
= legacy_probe_for_module_relative_directories (image
, file_name
);
1189 char *file_or_base
= is_absolute
? base_name
: file_name
;
1190 while ((full_name
= mono_dl_build_path (dir_name
, file_or_base
, &iter
))) {
1191 module
= cached_module_load (full_name
, MONO_DL_LAZY
, &error_msg
);
1193 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
,
1194 "DllImport error loading library '%s': '%s'.",
1195 full_name
, error_msg
);
1205 module
= cached_module_load (file_name
, MONO_DL_LAZY
, &error_msg
);
1207 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
,
1208 "DllImport error loading library '%s': '%s'.",
1209 file_name
, error_msg
);
1228 legacy_lookup_native_library (MonoImage
*image
, const char *scope
)
1230 MonoDl
*module
= NULL
;
1231 gboolean cached
= FALSE
;
1233 mono_image_lock (image
);
1234 if (!image
->pinvoke_scopes
)
1235 image
->pinvoke_scopes
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
1236 module
= (MonoDl
*)g_hash_table_lookup (image
->pinvoke_scopes
, scope
);
1237 mono_image_unlock (image
);
1242 module
= legacy_probe_for_module (image
, scope
);
1244 if (module
&& !cached
) {
1245 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
,
1246 "DllImport loaded library '%s'.", module
->full_name
);
1247 mono_image_lock (image
);
1248 if (!g_hash_table_lookup (image
->pinvoke_scopes
, scope
)) {
1249 g_hash_table_insert (image
->pinvoke_scopes
, g_strdup (scope
), module
);
1251 mono_image_unlock (image
);
1257 #endif // ENABLE_NETCORE
1260 lookup_pinvoke_call_impl (MonoMethod
*method
, MonoLookupPInvokeStatus
*status_out
)
1262 MonoImage
*image
= m_class_get_image (method
->klass
);
1263 #ifdef ENABLE_NETCORE
1264 MonoAssemblyLoadContext
*alc
= mono_image_get_alc (image
);
1265 MonoCustomAttrInfo
*cinfo
;
1268 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*)method
;
1269 MonoTableInfo
*tables
= image
->tables
;
1270 MonoTableInfo
*im
= &tables
[MONO_TABLE_IMPLMAP
];
1271 MonoTableInfo
*mr
= &tables
[MONO_TABLE_MODULEREF
];
1272 guint32 im_cols
[MONO_IMPLMAP_SIZE
];
1273 guint32 scope_token
;
1274 const char *orig_import
= NULL
;
1275 const char *new_import
= NULL
;
1276 const char *orig_scope
= NULL
;
1277 const char *new_scope
= NULL
;
1278 char *error_msg
= NULL
;
1279 MonoDl
*module
= NULL
;
1280 gpointer addr
= NULL
;
1282 MONO_REQ_GC_UNSAFE_MODE
;
1284 g_assert (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
);
1286 g_assert (status_out
);
1289 return piinfo
->addr
;
1291 if (image_is_dynamic (image
)) {
1292 MonoReflectionMethodAux
*method_aux
=
1293 (MonoReflectionMethodAux
*)g_hash_table_lookup (
1294 ((MonoDynamicImage
*)m_class_get_image (method
->klass
))->method_aux_hash
, method
);
1298 orig_import
= method_aux
->dllentry
;
1299 orig_scope
= method_aux
->dll
;
1302 if (!piinfo
->implmap_idx
|| piinfo
->implmap_idx
> im
->rows
)
1305 mono_metadata_decode_row (im
, piinfo
->implmap_idx
- 1, im_cols
, MONO_IMPLMAP_SIZE
);
1307 if (!im_cols
[MONO_IMPLMAP_SCOPE
] || im_cols
[MONO_IMPLMAP_SCOPE
] > mr
->rows
)
1310 piinfo
->piflags
= im_cols
[MONO_IMPLMAP_FLAGS
];
1311 orig_import
= mono_metadata_string_heap (image
, im_cols
[MONO_IMPLMAP_NAME
]);
1312 scope_token
= mono_metadata_decode_row_col (mr
, im_cols
[MONO_IMPLMAP_SCOPE
] - 1, MONO_MODULEREF_NAME
);
1313 orig_scope
= mono_metadata_string_heap (image
, scope_token
);
1316 #ifndef DISABLE_DLLMAP
1317 // FIXME: The dllmap remaps System.Native to mono-native
1318 mono_dllmap_lookup (image
, orig_scope
, orig_import
, &new_scope
, &new_import
);
1320 new_scope
= g_strdup (orig_scope
);
1321 new_import
= g_strdup (orig_import
);
1324 if (strcmp (new_scope
, "QCall") == 0) {
1325 piinfo
->addr
= mono_lookup_pinvoke_qcall_internal (method
, status_out
);
1326 if (!piinfo
->addr
) {
1327 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_DLLIMPORT
,
1328 "Unable to find qcall for '%s'.",
1330 status_out
->err_code
= LOOKUP_PINVOKE_ERR_NO_SYM
;
1331 status_out
->err_arg
= g_strdup (new_import
);
1333 return piinfo
->addr
;
1336 #ifdef ENABLE_NETCORE
1338 retry_with_libcoreclr
:
1341 ERROR_DECL (local_error
);
1342 cinfo
= mono_custom_attrs_from_method_checked (method
, local_error
);
1343 mono_error_cleanup (local_error
);
1345 flags
= get_dllimportsearchpath_flags (cinfo
);
1346 if (cinfo
&& !cinfo
->cached
)
1347 mono_custom_attrs_free (cinfo
);
1350 ERROR_DECL (local_error
);
1351 cinfo
= mono_custom_attrs_from_assembly_checked (m_class_get_image (method
->klass
)->assembly
, TRUE
, local_error
);
1352 mono_error_cleanup (local_error
);
1353 flags
= get_dllimportsearchpath_flags (cinfo
);
1354 if (cinfo
&& !cinfo
->cached
)
1355 mono_custom_attrs_free (cinfo
);
1359 module
= netcore_lookup_native_library (alc
, image
, new_scope
, flags
);
1361 module
= legacy_lookup_native_library (image
, new_scope
);
1365 mono_trace (G_LOG_LEVEL_WARNING
, MONO_TRACE_DLLIMPORT
,
1366 "DllImport unable to load library '%s'.",
1369 status_out
->err_code
= LOOKUP_PINVOKE_ERR_NO_LIB
;
1370 status_out
->err_arg
= g_strdup (new_scope
);
1374 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
,
1375 "DllImport searching in: '%s' ('%s').", new_scope
, module
->full_name
);
1377 addr
= pinvoke_probe_for_symbol (module
, piinfo
, new_import
, &error_msg
);
1380 #if defined(ENABLE_NETCORE) && !defined(HOST_WIN32)
1381 if (strcmp (new_scope
, "__Internal") == 0) {
1382 g_free ((char *)new_scope
);
1383 new_scope
= g_strdup (MONO_LOADER_LIBRARY_NAME
);
1384 goto retry_with_libcoreclr
;
1387 status_out
->err_code
= LOOKUP_PINVOKE_ERR_NO_SYM
;
1388 status_out
->err_arg
= g_strdup (new_import
);
1391 piinfo
->addr
= addr
;
1394 g_free ((char *)new_import
);
1395 g_free ((char *)new_scope
);
1401 pinvoke_probe_for_symbol (MonoDl
*module
, MonoMethodPInvoke
*piinfo
, const char *import
, char **error_msg_out
)
1403 char *error_msg
= NULL
;
1404 gpointer addr
= NULL
;
1406 g_assert (error_msg_out
);
1409 if (import
&& import
[0] == '#' && isdigit (import
[1])) {
1413 id
= strtol (import
+ 1, &end
, 10);
1414 if (id
> 0 && *end
== '\0')
1418 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
,
1419 "Searching for '%s'.", import
);
1421 #if !defined(ENABLE_NETCORE) || defined(HOST_WIN32) // For netcore, name mangling is Windows-exclusive
1422 if (piinfo
->piflags
& PINVOKE_ATTRIBUTE_NO_MANGLE
)
1423 error_msg
= mono_dl_symbol (module
, import
, &addr
);
1426 * Search using a variety of mangled names
1428 for (int mangle_stdcall
= 0; mangle_stdcall
<= 1 && addr
== NULL
; mangle_stdcall
++) {
1429 #if HOST_WIN32 && HOST_X86
1430 const int max_managle_param_count
= (mangle_stdcall
== 0) ? 0 : 256;
1432 const int max_managle_param_count
= 0;
1434 for (int mangle_charset
= 0; mangle_charset
<= 1 && addr
== NULL
; mangle_charset
++) {
1435 for (int mangle_param_count
= 0; mangle_param_count
<= max_managle_param_count
&& addr
== NULL
; mangle_param_count
+= 4) {
1437 char *mangled_name
= (char*)import
;
1438 switch (piinfo
->piflags
& PINVOKE_ATTRIBUTE_CHAR_SET_MASK
) {
1439 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE
:
1440 /* Try the mangled name first */
1441 if (mangle_charset
== 0)
1442 mangled_name
= g_strconcat (import
, "W", (const char*)NULL
);
1444 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO
:
1446 if (mangle_charset
== 0)
1447 mangled_name
= g_strconcat (import
, "W", (const char*)NULL
);
1449 /* Try the mangled name last */
1450 if (mangle_charset
== 1)
1451 mangled_name
= g_strconcat (import
, "A", (const char*)NULL
);
1454 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI
:
1456 /* Try the mangled name last */
1457 if (mangle_charset
== 1)
1458 mangled_name
= g_strconcat (import
, "A", (const char*)NULL
);
1462 #if HOST_WIN32 && HOST_X86
1463 /* Try the stdcall mangled name */
1465 * gcc under windows creates mangled names without the underscore, but MS.NET
1466 * doesn't support it, so we doesn't support it either.
1468 if (mangle_stdcall
== 1) {
1469 MonoMethod
*method
= &piinfo
->method
;
1471 if (mangle_param_count
== 0)
1472 param_count
= mono_method_signature_internal (method
)->param_count
* sizeof (gpointer
);
1474 /* Try brute force, since it would be very hard to compute the stack usage correctly */
1475 param_count
= mangle_param_count
;
1477 char *mangled_stdcall_name
= g_strdup_printf ("_%s@%d", mangled_name
, param_count
);
1479 if (mangled_name
!= import
)
1480 g_free (mangled_name
);
1482 mangled_name
= mangled_stdcall_name
;
1485 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
,
1486 "Probing '%s'.", mangled_name
);
1488 error_msg
= mono_dl_symbol (module
, mangled_name
, &addr
);
1491 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
,
1492 "Found as '%s'.", mangled_name
);
1494 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
,
1495 "Could not find '%s' due to '%s'.", mangled_name
, error_msg
);
1500 if (mangled_name
!= import
)
1501 g_free (mangled_name
);
1507 error_msg
= mono_dl_symbol (module
, import
, &addr
);
1510 *error_msg_out
= error_msg
;
1514 #ifdef ENABLE_NETCORE
1516 ves_icall_System_Runtime_InteropServices_NativeLibrary_FreeLib (gpointer lib
, MonoError
*error
)
1523 // Don't free __Internal
1524 if (internal_module
&& lib
== internal_module
->handle
)
1527 native_library_lock ();
1529 module
= netcore_handle_lookup (lib
);
1533 ref_count
= mono_refcount_dec (module
);
1537 g_hash_table_remove (native_library_module_map
, module
->handle
);
1538 g_hash_table_add (native_library_module_blocklist
, module
);
1539 mono_dl_close (module
);
1542 native_library_unlock ();
1546 ves_icall_System_Runtime_InteropServices_NativeLibrary_GetSymbol (gpointer lib
, MonoStringHandle symbol_name_handle
, MonoBoolean throw_on_error
, MonoError
*error
)
1549 gpointer symbol
= NULL
;
1554 ERROR_LOCAL_BEGIN (local_error
, error
, throw_on_error
)
1556 symbol_name
= mono_string_handle_to_utf8 (symbol_name_handle
, error
);
1557 goto_if_nok (error
, leave_nolock
);
1559 native_library_lock ();
1561 module
= netcore_handle_lookup (lib
);
1563 mono_error_set_generic_error (error
, "System", "DllNotFoundException", "%p: %s", lib
, symbol_name
);
1564 goto_if_nok (error
, leave
);
1566 mono_dl_symbol (module
, symbol_name
, &symbol
);
1568 mono_error_set_generic_error (error
, "System", "EntryPointNotFoundException", "%s: %s", module
->full_name
, symbol_name
);
1569 goto_if_nok (error
, leave
);
1572 native_library_unlock ();
1575 ERROR_LOCAL_END (local_error
);
1576 g_free (symbol_name
);
1581 // LOCKING: expects you to hold native_library_module_lock
1583 check_native_library_cache (MonoDl
*module
)
1585 gpointer handle
= module
->handle
;
1587 MonoDl
*cached_module
= netcore_handle_lookup (handle
);
1588 if (cached_module
) {
1589 g_free (module
->full_name
);
1591 mono_refcount_inc (cached_module
);
1592 return cached_module
;
1594 g_hash_table_insert (native_library_module_map
, handle
, (gpointer
)module
);
1600 ves_icall_System_Runtime_InteropServices_NativeLibrary_LoadByName (MonoStringHandle lib_name_handle
, MonoReflectionAssemblyHandle assembly_handle
, MonoBoolean has_search_flag
, guint32 search_flag
, MonoBoolean throw_on_error
, MonoError
*error
)
1603 gpointer handle
= NULL
;
1604 MonoAssembly
*assembly
= MONO_HANDLE_GETVAL (assembly_handle
, assembly
);
1605 MonoImage
*image
= mono_assembly_get_image_internal (assembly
);
1608 ERROR_LOCAL_BEGIN (local_error
, error
, throw_on_error
)
1610 lib_name
= mono_string_handle_to_utf8 (lib_name_handle
, error
);
1611 goto_if_nok (error
, leave
);
1613 // FIXME: implement search flag defaults properly
1614 module
= netcore_probe_for_module (image
, lib_name
, has_search_flag
? search_flag
: DLLIMPORTSEARCHPATH_ASSEMBLY_DIRECTORY
);
1616 mono_error_set_generic_error (error
, "System", "DllNotFoundException", "%s", lib_name
);
1617 goto_if_nok (error
, leave
);
1619 native_library_lock ();
1620 module
= check_native_library_cache (module
);
1621 native_library_unlock ();
1623 handle
= module
->handle
;
1626 ERROR_LOCAL_END (local_error
);
1633 ves_icall_System_Runtime_InteropServices_NativeLibrary_LoadFromPath (MonoStringHandle lib_path_handle
, MonoBoolean throw_on_error
, MonoError
*error
)
1636 gpointer handle
= NULL
;
1637 char *error_msg
= NULL
;
1640 ERROR_LOCAL_BEGIN (local_error
, error
, throw_on_error
)
1642 lib_path
= mono_string_handle_to_utf8 (lib_path_handle
, error
);
1643 goto_if_nok (error
, leave
);
1645 module
= mono_dl_open (lib_path
, MONO_DL_LAZY
, &error_msg
);
1647 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_DLLIMPORT
, "DllImport error loading library '%s': '%s'.", lib_path
, error_msg
);
1648 mono_error_set_generic_error (error
, "System", "DllNotFoundException", "'%s': '%s'", lib_path
, error_msg
);
1651 goto_if_nok (error
, leave
);
1653 native_library_lock ();
1654 module
= check_native_library_cache (module
);
1655 native_library_unlock ();
1657 handle
= module
->handle
;
1660 ERROR_LOCAL_END (local_error
);
1669 delete_bundled_libraries (void)
1673 for (list
= bundle_library_paths
; list
!= NULL
; list
= list
->next
){
1674 unlink ((const char*)list
->data
);
1676 rmdir (bundled_dylibrary_directory
);
1681 bundle_save_library_initialize (void)
1683 bundle_save_library_initialized
= TRUE
;
1684 char *path
= g_build_filename (g_get_tmp_dir (), "mono-bundle-XXXXXX", (const char*)NULL
);
1685 bundled_dylibrary_directory
= g_mkdtemp (path
);
1687 if (bundled_dylibrary_directory
== NULL
)
1690 atexit (delete_bundled_libraries
);
1695 mono_loader_save_bundled_library (int fd
, uint64_t offset
, uint64_t size
, const char *destfname
)
1698 char *file
, *buffer
, *err
, *internal_path
;
1699 if (!bundle_save_library_initialized
)
1700 bundle_save_library_initialize ();
1702 file
= g_build_filename (bundled_dylibrary_directory
, destfname
, (const char*)NULL
);
1703 buffer
= g_str_from_file_region (fd
, offset
, size
);
1704 g_file_set_contents (file
, buffer
, size
, NULL
);
1706 lib
= mono_dl_open (file
, MONO_DL_LAZY
, &err
);
1708 fprintf (stderr
, "Error loading shared library: %s %s\n", file
, err
);
1711 // Register the name with "." as this is how it will be found when embedded
1712 internal_path
= g_build_filename (".", destfname
, (const char*)NULL
);
1713 mono_loader_register_module (internal_path
, lib
);
1714 g_free (internal_path
);
1715 bundle_library_paths
= g_slist_append (bundle_library_paths
, file
);