[loader] Unmanaged library refactoring and NativeLibrary implementation (mono/mono...
authorRyan Lucia <rylucia@microsoft.com>
Fri, 8 Nov 2019 18:42:56 +0000 (13:42 -0500)
committerGitHub <noreply@github.com>
Fri, 8 Nov 2019 18:42:56 +0000 (13:42 -0500)
Commit migrated from https://github.com/mono/mono/commit/d5b6cf33b3d2a89189be4e6bddcf0207e9887ecd

20 files changed:
src/mono/mono/eglib/eglib-remap.h
src/mono/mono/eglib/ghashtable.c
src/mono/mono/eglib/glib.h
src/mono/mono/metadata/assembly-load-context.c
src/mono/mono/metadata/class-internals.h
src/mono/mono/metadata/icall-def-netcore.h
src/mono/mono/metadata/image.c
src/mono/mono/metadata/loader-internals.h
src/mono/mono/metadata/loader.c
src/mono/mono/metadata/metadata-internals.h
src/mono/mono/metadata/native-library.c
src/mono/mono/utils/mono-dl.c
src/mono/mono/utils/mono-dl.h
src/mono/mono/utils/mono-error-internals.h
src/mono/mono/utils/refcount.h
src/mono/netcore/CoreFX.issues.rsp
src/mono/netcore/CoreFX.issues_linux.rsp
src/mono/netcore/System.Private.CoreLib/src/LinkerDescriptor/System.Private.CoreLib.xml
src/mono/netcore/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.Mono.cs
src/mono/netcore/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.Mono.cs

index 0bbbcab..f261003 100644 (file)
@@ -68,6 +68,7 @@
 #define g_hash_table_foreach_steal monoeg_g_hash_table_foreach_steal
 #define g_hash_table_get_keys monoeg_g_hash_table_get_keys
 #define g_hash_table_get_values monoeg_g_hash_table_get_values
+#define g_hash_table_contains monoeg_g_hash_table_contains
 #define g_hash_table_insert_replace monoeg_g_hash_table_insert_replace
 #define g_hash_table_lookup monoeg_g_hash_table_lookup
 #define g_hash_table_lookup_extended monoeg_g_hash_table_lookup_extended
index 03ae92e..5329fab 100644 (file)
@@ -305,6 +305,14 @@ g_hash_table_size (GHashTable *hash)
        return hash->in_use;
 }
 
+gboolean
+g_hash_table_contains (GHashTable *hash, gconstpointer key)
+{
+       g_return_val_if_fail (key != NULL, FALSE);
+
+       return g_hash_table_lookup_extended (hash, key, NULL, NULL);
+}
+
 gpointer
 g_hash_table_lookup (GHashTable *hash, gconstpointer key)
 {
index 3e21c3c..d5ceb66 100644 (file)
@@ -623,6 +623,7 @@ void            g_hash_table_insert_replace  (GHashTable *hash, gpointer key, gp
 guint           g_hash_table_size            (GHashTable *hash);
 GList          *g_hash_table_get_keys        (GHashTable *hash);
 GList          *g_hash_table_get_values      (GHashTable *hash);
+gboolean        g_hash_table_contains (GHashTable *hash, gconstpointer key);
 G_EXTERN_C // Used by MonoPosixHelper or MonoSupportW, at least.
 gpointer        g_hash_table_lookup          (GHashTable *hash, gconstpointer key);
 gboolean        g_hash_table_lookup_extended (GHashTable *hash, gconstpointer key, gpointer *orig_key, gpointer *value);
@@ -646,6 +647,7 @@ guint           g_spaced_primes_closest      (guint x);
 
 #define g_hash_table_insert(h,k,v)    g_hash_table_insert_replace ((h),(k),(v),FALSE)
 #define g_hash_table_replace(h,k,v)   g_hash_table_insert_replace ((h),(k),(v),TRUE)
+#define g_hash_table_add(h,k)         g_hash_table_insert_replace ((h),(k),(k),TRUE)
 
 G_EXTERN_C // Used by MonoPosixHelper or MonoSupportW, at least.
 gboolean g_direct_equal (gconstpointer v1, gconstpointer v2);
index 7c972cf..708293c 100644 (file)
@@ -22,7 +22,9 @@ mono_alc_init (MonoAssemblyLoadContext *alc, MonoDomain *domain)
        alc->domain = domain;
        alc->loaded_images = li;
        alc->loaded_assemblies = NULL;
+       alc->pinvoke_scopes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
        mono_coop_mutex_init (&alc->assemblies_lock);
+       mono_coop_mutex_init (&alc->pinvoke_lock);
 }
 
 void
@@ -53,7 +55,9 @@ mono_alc_cleanup (MonoAssemblyLoadContext *alc)
         */
 
        alc->loaded_assemblies = NULL;
+       g_hash_table_destroy (alc->pinvoke_scopes);
        mono_coop_mutex_destroy (&alc->assemblies_lock);
+       mono_coop_mutex_destroy (&alc->pinvoke_lock);
 
        mono_loaded_images_free (alc->loaded_images);
 
index 294d6f4..92bdc67 100644 (file)
@@ -1059,6 +1059,7 @@ GENERATE_TRY_GET_CLASS_WITH_CACHE_DECL(handleref)
 
 #ifdef ENABLE_NETCORE
 GENERATE_GET_CLASS_WITH_CACHE_DECL (assembly_load_context)
+GENERATE_GET_CLASS_WITH_CACHE_DECL (native_library)
 #endif
 
 /* If you need a MonoType, use one of the mono_get_*_type () functions in class-inlines.h */
index 5656c57..145c443 100644 (file)
@@ -368,6 +368,12 @@ HANDLES(MARSHAL_34, "StructureToPtr", ves_icall_System_Runtime_InteropServices_M
 HANDLES(MARSHAL_41, "copy_from_unmanaged_fixed", ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged, void, 5, (gconstpointer, gint32, MonoArray, gint32, gpointer))
 HANDLES(MARSHAL_42, "copy_to_unmanaged_fixed", ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged, void, 5, (MonoArray, gint32, gpointer, gint32, gconstpointer))
 
+ICALL_TYPE(NATIVEL, "System.Runtime.InteropServices.NativeLibrary", NATIVEL_1)
+HANDLES(NATIVEL_1, "FreeLib", ves_icall_System_Runtime_InteropServices_NativeLibrary_FreeLib, void, 1, (gpointer))
+HANDLES(NATIVEL_2, "GetSymbol", ves_icall_System_Runtime_InteropServices_NativeLibrary_GetSymbol, gpointer, 3, (gpointer, MonoString, MonoBoolean))
+HANDLES(NATIVEL_3, "LoadByName", ves_icall_System_Runtime_InteropServices_NativeLibrary_LoadByName, gpointer, 5, (MonoString, MonoReflectionAssembly, MonoBoolean, guint32, MonoBoolean))
+HANDLES(NATIVEL_4, "LoadFromPath", ves_icall_System_Runtime_InteropServices_NativeLibrary_LoadFromPath, gpointer, 2, (MonoString, MonoBoolean))
+
 ICALL_TYPE(ALC, "System.Runtime.Loader.AssemblyLoadContext", ALC_5)
 HANDLES(ALC_5, "GetLoadContextForAssembly", ves_icall_System_Runtime_Loader_AssemblyLoadContext_GetLoadContextForAssembly, gpointer, 1, (MonoReflectionAssembly))
 HANDLES(ALC_4, "InternalGetLoadedAssemblies", ves_icall_System_Runtime_Loader_AssemblyLoadContext_InternalGetLoadedAssemblies, MonoArray, 0, ())
index 9e05d37..8a9f688 100644 (file)
@@ -2441,8 +2441,9 @@ mono_image_close_except_pools (MonoImage *image)
        if (image->mvar_gparam_cache)
                mono_conc_hashtable_destroy (image->mvar_gparam_cache);
        free_hash (image->wrapper_param_names);
+#ifndef ENABLE_NETCORE
        free_hash (image->pinvoke_scopes);
-       free_hash (image->pinvoke_scope_filenames);
+#endif
        free_hash (image->native_func_wrapper_cache);
        mono_conc_hashtable_destroy (image->typespec_cache);
        free_hash (image->weak_field_indexes);
index c6ae068..bd2f343 100644 (file)
@@ -38,6 +38,11 @@ struct _MonoAssemblyLoadContext {
         * collectible, the handle is weak, otherwise it's strong.
         */
        uint32_t gchandle;
+
+       // Used in native-library.c for the hash table below; do not access anywhere else
+       MonoCoopMutex pinvoke_lock;
+       // Maps malloc-ed char* pinvoke scope -> MonoDl*
+       GHashTable *pinvoke_scopes;
 };
 #endif /* ENABLE_NETCORE */
 
@@ -59,7 +64,10 @@ mono_global_dllmap_cleanup (void);
 #endif
 
 void
-mono_cached_module_cleanup (void);
+mono_global_loader_cache_init (void);
+
+void
+mono_global_loader_cache_cleanup (void);
 
 #ifdef ENABLE_NETCORE
 void
index 499fa7e..9de71c4 100644 (file)
@@ -88,6 +88,8 @@ mono_loader_init ()
                mono_os_mutex_init_recursive (&global_loader_data_mutex);
                loader_lock_inited = TRUE;
 
+               mono_global_loader_cache_init ();
+
                mono_native_tls_alloc (&loader_lock_nest_id, NULL);
 
                mono_counters_init ();
@@ -110,7 +112,7 @@ mono_loader_cleanup (void)
 #ifndef DISABLE_DLLMAP
        mono_global_dllmap_cleanup ();
 #endif
-       mono_cached_module_cleanup ();
+       mono_global_loader_cache_cleanup ();
 
        mono_native_tls_free (loader_lock_nest_id);
 
index 15f66bf..d9a9b3e 100644 (file)
@@ -562,11 +562,10 @@ struct _MonoImage {
        MonoConcurrentHashTable *var_gparam_cache;
        MonoConcurrentHashTable *mvar_gparam_cache;
 
+#ifndef ENABLE_NETCORE
        /* Maps malloc-ed char* pinvoke scope -> MonoDl* */
        GHashTable *pinvoke_scopes;
-
-       /* Maps malloc-ed char* pinvoke scope -> malloced-ed char* filename */
-       GHashTable *pinvoke_scope_filenames;
+#endif
 
        /* Indexed by MonoGenericParam pointers */
        GHashTable **gshared_types;
index e33d821..b52dd8e 100644 (file)
@@ -1,7 +1,11 @@
 #include "config.h"
+#include "mono/metadata/assembly-internals.h"
 #include "mono/metadata/class-internals.h"
+#include "mono/metadata/icall-decl.h"
 #include "mono/metadata/loader-internals.h"
 #include "mono/metadata/loader.h"
+#include "mono/metadata/object-internals.h"
+#include "mono/metadata/reflection-internals.h"
 #include "mono/utils/checked-build.h"
 #include "mono/utils/mono-compiler.h"
 #include "mono/utils/mono-logger-internals.h"
 #ifdef ENABLE_NETCORE
 static int pinvoke_search_directories_count;
 static char **pinvoke_search_directories;
+
+// In DllImportSearchPath enum, bit 0x2 represents AssemblyDirectory. It is not passed on and is instead handled by the runtime.
+#define DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY 0x2
+
+// This lock may be taken within an ALC lock, and should never be the other way around.
+static MonoCoopMutex native_library_module_lock;
+static GHashTable *native_library_module_map;
+/*
+ * This blacklist is used as a set for cache invalidation purposes with netcore pinvokes.
+ * When pinvokes are resolved with anything other than the last-chance managed event,
+ * the results of that lookup are added to an ALC-level cache. However, if a library is then
+ * unloaded with NativeLibrary.Free(), this cache should be invalidated so that a newly called
+ * pinvoke will not attempt to use it, hence the blacklist. This design means that if another
+ * library is loaded at the same address, it will function with a perf hit, as the entry will
+ * repeatedly be added and removed from the cache due to its presence in the blacklist.
+ * This is a rare scenario and considered a worthwhile tradeoff.
+ */
+static GHashTable *native_library_module_blacklist;
 #endif
 
 #ifndef DISABLE_DLLMAP
 static MonoDllMap *global_dll_map;
 #endif
-static GHashTable *global_module_map;
 
-static MonoDl *internal_module;
+static GHashTable *global_module_map; // should only be accessed with the global loader data lock
+
+static MonoDl *internal_module; // used when pinvoking `__Internal`
 
 typedef enum {
        LOOKUP_PINVOKE_ERR_OK = 0, /* No error */
@@ -41,6 +64,9 @@ typedef struct MonoLookupPInvokeStatus {
 /* Class lazy loading functions */
 GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, "System", "AppDomainUnloadedException")
 GENERATE_TRY_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, "System", "AppDomainUnloadedException")
+#ifdef ENABLE_NETCORE
+GENERATE_GET_CLASS_WITH_CACHE (native_library, "System.Runtime.InteropServices", "NativeLibrary");
+#endif
 
 #ifndef DISABLE_DLLMAP
 /*
@@ -124,8 +150,6 @@ dllmap_insert_global (const char *dll, const char *func, const char *tdll, const
 {
        MonoDllMap *entry;
 
-       mono_loader_init ();
-
        entry = (MonoDllMap *)g_malloc0 (sizeof (MonoDllMap));
        entry->dll = dll? g_strdup (dll): NULL;
        entry->target = tdll? g_strdup (tdll): NULL;
@@ -148,8 +172,6 @@ dllmap_insert_image (MonoImage *assembly, const char *dll, const char *func, con
 
        MONO_REQ_GC_UNSAFE_MODE;
 
-       mono_loader_init ();
-
        entry = (MonoDllMap *)mono_image_alloc0 (assembly, sizeof (MonoDllMap));
        entry->dll = dll? mono_image_strdup (assembly, dll): NULL;
        entry->target = tdll? mono_image_strdup (assembly, tdll): NULL;
@@ -184,6 +206,7 @@ free_dllmap (MonoDllMap *map)
 void
 mono_dllmap_insert_internal (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc)
 {
+       mono_loader_init ();
        // The locking in here is _really_ wonky, and I'm not convinced this function should exist.
        // I've split it into an internal version to offer flexibility in the future.
        if (!assembly)
@@ -201,6 +224,8 @@ mono_global_dllmap_cleanup (void)
        free_dllmap (global_dll_map);
        global_dll_map = NULL;
 
+       // We don't care about freeing native_library_module_map on netcore because of the expedited shutdown.
+
        mono_global_loader_data_unlock ();
 }
 #endif
@@ -243,49 +268,44 @@ mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, cons
 #endif
 }
 
-static MonoDl*
-cached_module_load (const char *name, int flags, char **err)
+void
+mono_loader_register_module (const char *name, MonoDl *module)
 {
-       MonoDl *res;
-
-       if (err)
-               *err = NULL;
-
-       MONO_ENTER_GC_SAFE;
+       mono_loader_init ();
 
+       // No transition here because this is early in startup
        mono_global_loader_data_lock ();
 
-       if (!global_module_map)
-               global_module_map = g_hash_table_new (g_str_hash, g_str_equal);
-
-       res = (MonoDl *)g_hash_table_lookup (global_module_map, name);
-       if (res)
-               goto exit;
-
-       res = mono_dl_open (name, flags, err);
-       if (res)
-               g_hash_table_insert (global_module_map, g_strdup (name), res);
+       g_hash_table_insert (global_module_map, g_strdup (name), module);
 
-exit:
        mono_global_loader_data_unlock ();
-
-       MONO_EXIT_GC_SAFE;
-
-       return res;
 }
 
-void
-mono_loader_register_module (const char *name, MonoDl *module)
+static MonoDl *
+mono_loader_register_module_locking (const char *name, MonoDl *module)
 {
-       // No transition here because this is early in startup
+       MonoDl *result = NULL;
+
+       MONO_ENTER_GC_SAFE;
        mono_global_loader_data_lock ();
+       MONO_EXIT_GC_SAFE;
 
-       if (!global_module_map)
-               global_module_map = g_hash_table_new (g_str_hash, g_str_equal);
+       result = (MonoDl *)g_hash_table_lookup (global_module_map, name);
+       if (result) {
+               g_free (module->full_name);
+               g_free (module);
+               goto exit;
+       }
 
        g_hash_table_insert (global_module_map, g_strdup (name), module);
+       result = module;
 
+exit:
+       MONO_ENTER_GC_SAFE;
        mono_global_loader_data_unlock ();
+       MONO_EXIT_GC_SAFE;
+
+       return result;
 }
 
 static void
@@ -295,11 +315,23 @@ remove_cached_module (gpointer key, gpointer value, gpointer user_data)
 }
 
 void
-mono_cached_module_cleanup (void)
+mono_global_loader_cache_init (void)
 {
-       // No need for a transition here since the thread is already detached from the runtime
-       mono_global_loader_data_lock ();
+       if (!global_module_map)
+               global_module_map = g_hash_table_new (g_str_hash, g_str_equal);
+
+#ifdef ENABLE_NETCORE
+       if (!native_library_module_map)
+               native_library_module_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+       if (!native_library_module_blacklist)
+               native_library_module_blacklist = g_hash_table_new (g_direct_hash, g_direct_equal);
+       mono_coop_mutex_init (&native_library_module_lock);
+#endif
+}
 
+void
+mono_global_loader_cache_cleanup (void)
+{
        if (global_module_map != NULL) {
                g_hash_table_foreach(global_module_map, remove_cached_module, NULL);
 
@@ -307,16 +339,16 @@ mono_cached_module_cleanup (void)
                global_module_map = NULL;
        }
 
-       mono_global_loader_data_unlock ();
+       // No need to clean up the native library hash tables since they're netcore-only, where this is never called
 }
 
 static gboolean
 is_absolute_path (const char *path)
 {
+       // FIXME: other platforms have similar prefixes, such as $ORIGIN
 #ifdef HOST_DARWIN
-       if (!strncmp (path, "@executable_path/", 17) || !strncmp (path, "@loader_path/", 13) ||
-           !strncmp (path, "@rpath/", 7))
-           return TRUE;
+       if (!strncmp (path, "@executable_path/", 17) || !strncmp (path, "@loader_path/", 13) || !strncmp (path, "@rpath/", 7))
+               return TRUE;
 #endif
        return g_path_is_absolute (path);
 }
@@ -324,6 +356,9 @@ is_absolute_path (const char *path)
 static gpointer
 lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_out);
 
+static gpointer
+pinvoke_probe_for_symbol (MonoDl *module, MonoMethodPInvoke *piinfo, const char *import, char **error_msg_out);
+
 static void
 pinvoke_probe_convert_status_for_api (MonoLookupPInvokeStatus *status, const char **exc_class, const char **exc_arg)
 {
@@ -387,15 +422,6 @@ mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char
        return result;
 }
 
-static MonoDl*
-pinvoke_probe_for_module (MonoImage *image, const char*new_scope, char **found_name_out, char **error_msg_out);
-
-static MonoDl*
-pinvoke_probe_for_module_relative_directories (MonoImage *image, const char *file_name, char **found_name_out);
-
-static gpointer
-pinvoke_probe_for_symbol (MonoDl *module, MonoMethodPInvoke *piinfo, const char *import, char **error_msg_out);
-
 gpointer
 mono_lookup_pinvoke_call_internal (MonoMethod *method, MonoError *error)
 {
@@ -408,138 +434,447 @@ mono_lookup_pinvoke_call_internal (MonoMethod *method, MonoError *error)
        return result;
 }
 
-gpointer
-lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_out)
+#ifdef ENABLE_NETCORE
+void
+mono_set_pinvoke_search_directories (int dir_count, char **dirs)
 {
-       MonoImage *image = m_class_get_image (method->klass);
-       MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
-       MonoTableInfo *tables = image->tables;
-       MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
-       MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
-       guint32 im_cols [MONO_IMPLMAP_SIZE];
-       guint32 scope_token;
-       const char *orig_import = NULL;
-       const char *new_import = NULL;
-       const char *orig_scope = NULL;
-       const char *new_scope = NULL;
-       char *error_msg = NULL;
-       char *found_name = NULL;
-       MonoDl *module = NULL;
-       gboolean cached = FALSE;
-       gpointer addr = NULL;
+       pinvoke_search_directories_count = dir_count;
+       pinvoke_search_directories = dirs;
+}
 
-       g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
+static void
+native_library_lock (void)
+{
+       mono_coop_mutex_lock (&native_library_module_lock);
+}
 
-       g_assert (status_out);
+static void
+native_library_unlock (void)
+{
+       mono_coop_mutex_unlock (&native_library_module_lock);
+}
 
-       if (piinfo->addr)
-               return piinfo->addr;
+static void
+alc_pinvoke_lock (MonoAssemblyLoadContext *alc)
+{
+       mono_coop_mutex_lock (&alc->pinvoke_lock);
+}
 
-       if (image_is_dynamic (m_class_get_image (method->klass))) {
-               MonoReflectionMethodAux *method_aux = 
-                       (MonoReflectionMethodAux *)g_hash_table_lookup (
-                               ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
-               if (!method_aux)
-                       goto exit;
+static void
+alc_pinvoke_unlock (MonoAssemblyLoadContext *alc)
+{
+       mono_coop_mutex_unlock (&alc->pinvoke_lock);
+}
 
-               orig_import = method_aux->dllentry;
-               orig_scope = method_aux->dll;
+// LOCKING: expects you to hold native_library_module_lock
+static MonoDl *
+netcore_handle_lookup (gpointer handle)
+{
+       return (MonoDl *)g_hash_table_lookup (native_library_module_map, handle);
+}
+
+// LOCKING: expects you to hold native_library_module_lock
+static gboolean
+netcore_check_blacklist (MonoDl *module)
+{
+       return g_hash_table_contains (native_library_module_blacklist, module);
+}
+
+static MonoDl *
+netcore_probe_for_module_variations (const char *mdirname, const char *file_name)
+{
+       void *iter = NULL;
+       char *full_name;
+       MonoDl *module = NULL;
+
+       // This does not actually mirror CoreCLR's algorithm; if that becomes a problem, potentially use theirs
+       // FIXME: this appears to search *.dylib twice for some reason
+       while ((full_name = mono_dl_build_path (mdirname, file_name, &iter)) && module == NULL) {
+               char *error_msg;
+               module = mono_dl_open (full_name, MONO_DL_LAZY, &error_msg);
+               if (!module) {
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '%s': '%s'.", full_name, error_msg);
+                       g_free (error_msg);
+               }
+               g_free (full_name);
        }
-       else {
-               if (!piinfo->implmap_idx || piinfo->implmap_idx > im->rows)
-                       goto exit;
+       g_free (full_name);
 
-               mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
+       return module;
+}
 
-               if (!im_cols [MONO_IMPLMAP_SCOPE] || im_cols [MONO_IMPLMAP_SCOPE] > mr->rows)
-                       goto exit;
+static MonoDl *
+netcore_probe_for_module (MonoImage *image, const char *file_name, int flags)
+{
+       MonoDl *module = NULL;
+       gboolean search_assembly_dir = flags & DLLIMPORTSEARCHPATH_ASSEMBLYDIRECTORY;
 
-               piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
-               orig_import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
-               scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
-               orig_scope = mono_metadata_string_heap (image, scope_token);
+       // Try without any path additions
+       module = netcore_probe_for_module_variations (NULL, file_name);
+
+       // Check the NATIVE_DLL_SEARCH_DIRECTORIES
+       for (int i = 0; i < pinvoke_search_directories_count && module == NULL; ++i)
+               module = netcore_probe_for_module_variations (pinvoke_search_directories[i], file_name);
+
+       // Check the assembly directory if the search flag is set and the image exists
+       if (search_assembly_dir && image != NULL && module == NULL) {
+               char *mdirname = g_path_get_dirname (image->filename);
+               if (mdirname)
+                       module = netcore_probe_for_module_variations (mdirname, file_name);
+               g_free (mdirname);
        }
 
-#ifndef DISABLE_DLLMAP
-       // FIXME: The dllmap remaps System.Native to mono-native
-       mono_dllmap_lookup (image, orig_scope, orig_import, &new_scope, &new_import);
-#else
-       new_scope = g_strdup (orig_scope);
-       new_import = g_strdup (orig_import);
-#endif
+       return module;
+}
 
-       if (!module) {
-               mono_image_lock (image);
-               if (!image->pinvoke_scopes) {
-                       image->pinvoke_scopes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-                       image->pinvoke_scope_filenames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-               }
-               module = (MonoDl *)g_hash_table_lookup (image->pinvoke_scopes, new_scope);
-               found_name = (char *)g_hash_table_lookup (image->pinvoke_scope_filenames, new_scope);
-               mono_image_unlock (image);
-               if (module)
-                       cached = TRUE;
-               found_name = g_strdup (found_name);
+static MonoDl *
+netcore_resolve_with_dll_import_resolver (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, const char *scope, guint32 flags, MonoError *error)
+{
+       MonoDl *result = NULL;
+       gpointer lib = NULL;
+       MonoDomain *domain = mono_alc_domain (alc);
+
+       static MonoMethod *resolve;
+
+       if (!resolve) {
+               ERROR_DECL (local_error);
+               MonoClass *native_lib_class = mono_class_get_native_library_class ();
+               g_assert (native_lib_class);
+               MonoMethod *m = mono_class_get_method_from_name_checked (native_lib_class, "MonoLoadLibraryCallbackStub", -1, 0, local_error);
+               mono_error_assert_ok (local_error);
+               resolve = m;
        }
+       g_assert (resolve);
 
-       if (!module)
-               module = pinvoke_probe_for_module (image, new_scope, &found_name, &error_msg);
+       if (mono_runtime_get_no_exec ())
+               return NULL;
 
-       if (!module) {
-               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DLLIMPORT,
-                               "DllImport unable to load library '%s'.",
-                               error_msg);
+       HANDLE_FUNCTION_ENTER ();
 
-               status_out->err_code = LOOKUP_PINVOKE_ERR_NO_LIB;
-               status_out->err_arg = g_strdup (new_scope);
-               goto exit;
+       MonoStringHandle scope_handle = mono_string_new_handle (domain, scope, error);
+       goto_if_nok (error, leave);
+       MonoReflectionAssemblyHandle assembly_handle = mono_assembly_get_object_handle (domain, assembly, error);
+       goto_if_nok (error, leave);
+
+       gboolean has_search_flags = flags != 0 ? TRUE : FALSE;
+       gpointer args [5];
+       args [0] = &scope_handle;
+       args [1] = MONO_HANDLE_RAW (assembly_handle);
+       args [2] = &has_search_flags;
+       args [3] = &flags;
+       args [4] = &lib;
+       mono_runtime_invoke_checked (resolve, NULL, args, error);
+       goto_if_nok (error, leave);
+
+       native_library_lock ();
+       result = netcore_handle_lookup (lib);
+       native_library_unlock ();
+
+leave:
+       HANDLE_FUNCTION_RETURN_VAL (result);
+}
+
+static MonoDl *
+netcore_resolve_with_dll_import_resolver_nofail (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, const char *scope, guint32 flags)
+{
+       MonoDl *result = NULL;
+       ERROR_DECL (error);
+
+       result = netcore_resolve_with_dll_import_resolver (alc, assembly, scope, flags, error);
+       if (!is_ok (error))
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC DllImportResolver(\"%s\") delegate: '%s'", scope, mono_error_get_message (error));
+
+       mono_error_cleanup (error);
+
+       return result;
+}
+
+static MonoDl *
+netcore_resolve_with_load (MonoAssemblyLoadContext *alc, const char *scope, MonoError *error)
+{
+       MonoDl *result = NULL;
+       gpointer lib = NULL;
+
+       static MonoMethod *resolve;
+
+       if (!resolve) {
+               ERROR_DECL (local_error);
+               MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
+               g_assert (alc_class);
+               MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUnmanagedDll", -1, 0, local_error);
+               mono_error_assert_ok (local_error);
+               resolve = m;
        }
+       g_assert (resolve);
 
-       if (!cached) {
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
-                                       "DllImport loaded library '%s'.", found_name);
-               mono_image_lock (image);
-               if (!g_hash_table_lookup (image->pinvoke_scopes, new_scope)) {
-                       g_hash_table_insert (image->pinvoke_scopes, g_strdup (new_scope), module);
-                       g_hash_table_insert (image->pinvoke_scope_filenames, g_strdup (new_scope), g_strdup (found_name));
-               }
-               mono_image_unlock (image);
+       if (mono_runtime_get_no_exec ())
+               return NULL;
+
+       HANDLE_FUNCTION_ENTER ();
+
+       MonoStringHandle scope_handle = mono_string_new_handle (mono_alc_domain (alc), scope, error);
+       goto_if_nok (error, leave);
+
+       gpointer gchandle = GUINT_TO_POINTER (alc->gchandle);
+       gpointer args [3];
+       args [0] = &scope_handle;
+       args [1] = &gchandle;
+       args [2] = &lib;
+       mono_runtime_invoke_checked (resolve, NULL, args, error);
+       goto_if_nok (error, leave);
+
+       native_library_lock ();
+       result = netcore_handle_lookup (lib);
+       native_library_unlock ();
+
+leave:
+       HANDLE_FUNCTION_RETURN_VAL (result);
+}
+
+static MonoDl *
+netcore_resolve_with_load_nofail (MonoAssemblyLoadContext *alc, const char *scope)
+{
+       MonoDl *result = NULL;
+       ERROR_DECL (error);
+
+       result = netcore_resolve_with_load (alc, scope, error);
+       if (!is_ok (error))
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC LoadUnmanagedDll(\"%s\") method: '%s'", scope, mono_error_get_message (error));
+
+       mono_error_cleanup (error);
+
+       return result;
+}
+
+static MonoDl *
+netcore_resolve_with_resolving_event (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, const char *scope, MonoError *error)
+{
+       MonoDl *result = NULL;
+       gpointer lib = NULL;
+       MonoDomain *domain = mono_alc_domain (alc);
+
+       static MonoMethod *resolve;
+
+       if (!resolve) {
+               ERROR_DECL (local_error);
+               MonoClass *alc_class = mono_class_get_assembly_load_context_class ();
+               g_assert (alc_class);
+               MonoMethod *m = mono_class_get_method_from_name_checked (alc_class, "MonoResolveUnmanagedDllUsingEvent", -1, 0, local_error);
+               mono_error_assert_ok (local_error);
+               resolve = m;
        }
+       g_assert (resolve);
 
-       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
-                               "DllImport searching in: '%s' ('%s').", new_scope, found_name);
+       if (mono_runtime_get_no_exec ())
+               return NULL;
 
-       addr = pinvoke_probe_for_symbol (module, piinfo, new_import, &error_msg);
+       HANDLE_FUNCTION_ENTER ();
 
-       if (!addr) {
-               status_out->err_code = LOOKUP_PINVOKE_ERR_NO_SYM;
-               status_out->err_arg = g_strdup (new_import);
-               goto exit;
+       MonoStringHandle scope_handle = mono_string_new_handle (domain, scope, error);
+       goto_if_nok (error, leave);
+       MonoReflectionAssemblyHandle assembly_handle = mono_assembly_get_object_handle (domain, assembly, error);
+       goto_if_nok (error, leave);
+
+       gpointer gchandle = GUINT_TO_POINTER (alc->gchandle);
+       gpointer args [4];
+       args [0] = &scope_handle;
+       args [1] = MONO_HANDLE_RAW (assembly_handle);
+       args [2] = &gchandle;
+       args [3] = &lib;
+       mono_runtime_invoke_checked (resolve, NULL, args, error);
+       goto_if_nok (error, leave);
+
+       native_library_lock ();
+       result = netcore_handle_lookup (lib);
+       native_library_unlock ();
+
+leave:
+       HANDLE_FUNCTION_RETURN_VAL (result);
+}
+
+static MonoDl *
+netcore_resolve_with_resolving_event_nofail (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, const char *scope)
+{
+       MonoDl *result = NULL;
+       ERROR_DECL (error);
+
+       result = netcore_resolve_with_resolving_event (alc, assembly, scope, error);
+       if (!is_ok (error))
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Error while invoking ALC ResolvingUnmangedDll(\"%s\") event: '%s'", scope, mono_error_get_message (error));
+
+       mono_error_cleanup (error);
+
+       return result;
+}
+
+// LOCKING: expects you to hold the ALC's pinvoke lock
+static MonoDl *
+netcore_check_alc_cache (MonoAssemblyLoadContext *alc, const char *scope)
+{
+       MonoDl *result = NULL;
+
+       result = (MonoDl *)g_hash_table_lookup (alc->pinvoke_scopes, scope);
+
+       if (result) {
+               gboolean blacklisted;
+
+               native_library_lock ();
+               blacklisted = netcore_check_blacklist (result);
+               native_library_unlock ();
+
+               if (blacklisted) {
+                       g_hash_table_remove (alc->pinvoke_scopes, scope);
+                       result = NULL;
+               }
        }
-       piinfo->addr = addr;
 
-exit:
-       g_free ((char *)new_import);
-       g_free ((char *)new_scope);
-       g_free (error_msg);
-       g_free (found_name);
-       return addr;
+       return result;
 }
 
-/**
- * pinvoke_probe_transform_path:
- *
- * Try transforming the library path given in \p new_scope in different ways
- * depending on \p phase
- *
- * \returns \c TRUE if a transformation was applied and the transformed path
- * components are written to the out arguments, or \c FALSE if a transformation
- * did not apply.
- */
-static gboolean
-pinvoke_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)
+static MonoDl *
+netcore_lookup_native_library (MonoAssemblyLoadContext *alc, MonoImage *image, const char *scope, guint32 flags)
 {
-       char *file_name = NULL, *base_name = NULL, *dir_name = NULL;
+       MonoDl *module = NULL;
+       MonoDl *cached;
+       MonoAssembly *assembly = mono_image_get_assembly (image);
+       char *error_msg = NULL;
+
+       MONO_REQ_GC_UNSAFE_MODE;
+
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport attempting to load: '%s'.", scope);
+
+       // We allow a special name to dlopen from the running process namespace, which is not present in CoreCLR
+       if (strcmp (scope, "__Internal") == 0) {
+               if (!internal_module)
+                       internal_module = mono_dl_open (NULL, MONO_DL_LAZY, &error_msg);
+               module = internal_module;
+
+               if (!module) {
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", error_msg);
+                       g_free (error_msg);
+               }
+
+               return module;
+       }
+
+       /*
+        * Try these until one of them succeeds:
+        *
+        * 1. Check the cache in the active ALC.
+        *
+        * 2. Call the DllImportResolver on the active assembly.
+        *
+        * 3. Call LoadUnmanagedDll on the active ALC.
+        *
+        * 4. Check the global cache.
+        *
+        * 5. Run the unmanaged probing logic.
+        *
+        * 6. Raise the ResolvingUnmanagedDll event on the active ALC.
+        *
+        * 7. Return NULL.
+        */
+
+       alc_pinvoke_lock (alc);
+       module = netcore_check_alc_cache (alc, scope);
+       alc_pinvoke_unlock (alc);
+       if (module)
+               goto leave;
+
+       module = (MonoDl *)netcore_resolve_with_dll_import_resolver_nofail (alc, assembly, scope, flags);
+       if (module)
+               goto add_to_alc_cache;
+
+       module = (MonoDl *)netcore_resolve_with_load_nofail (alc, scope);
+       if (module)
+               goto add_to_alc_cache;
+
+       MONO_ENTER_GC_SAFE;
+       mono_global_loader_data_lock ();
+       MONO_EXIT_GC_SAFE;
+       module = (MonoDl *)g_hash_table_lookup (global_module_map, scope);
+       MONO_ENTER_GC_SAFE;
+       mono_global_loader_data_unlock ();
+       MONO_EXIT_GC_SAFE;
+       if (module)
+               goto add_to_alc_cache;
+
+       module = netcore_probe_for_module (image, scope, flags);
+       if (module)
+               goto add_to_global_cache;
+
+       /* As this is last chance, I've opted not to put it in a cache, but that is not necessarily the correct decision.
+        * It is rather convenient here, however, because it means the global cache will only be populated by libraries
+        * resolved via netcore_probe_for_module and not NativeLibrary, eliminating potential races/conflicts.
+        */
+       module = netcore_resolve_with_resolving_event_nofail (alc, assembly, scope);
+       goto leave;
+
+add_to_global_cache:
+       module = mono_loader_register_module_locking (scope, module);
+
+add_to_alc_cache:
+       /* Nothing is closed here because the only two places this can come from are:
+        * 1. A managed callback that made use of NativeLibrary.Load, in which case closing is dependent on NativeLibrary.Free
+        * 2. The global cache, which is only populated by results of netcore_probe_for_module. When adding to the global cache,
+        *      we free the new MonoDl if another thread beat us, so we don't have to repeat that here.
+        */
+       alc_pinvoke_lock (alc);
+       cached = netcore_check_alc_cache (alc, scope);
+       if (cached)
+               module = cached;
+       else
+               g_hash_table_insert (alc->pinvoke_scopes, g_strdup (scope), module);
+       alc_pinvoke_unlock (alc);
+
+leave:
+       return module;
+}
+
+#else // ENABLE_NETCORE
+
+static MonoDl *
+cached_module_load (const char *name, int flags, char **err)
+{
+       MonoDl *res;
+
+       if (err)
+               *err = NULL;
+
+       MONO_ENTER_GC_SAFE;
+       mono_global_loader_data_lock ();
+       MONO_EXIT_GC_SAFE;
+
+       res = (MonoDl *)g_hash_table_lookup (global_module_map, name);
+       if (res)
+               goto exit;
+
+       res = mono_dl_open (name, flags, err);
+       if (res)
+               g_hash_table_insert (global_module_map, g_strdup (name), res);
+
+exit:
+       MONO_ENTER_GC_SAFE;
+       mono_global_loader_data_unlock ();
+       MONO_EXIT_GC_SAFE;
+
+       return res;
+}
+
+/**
+ * legacy_probe_transform_path:
+ *
+ * Try transforming the library path given in \p new_scope in different ways
+ * depending on \p phase
+ *
+ * \returns \c TRUE if a transformation was applied and the transformed path
+ * components are written to the out arguments, or \c FALSE if a transformation
+ * did not apply.
+ */
+static gboolean
+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)
+{
+       char *file_name = NULL, *base_name = NULL, *dir_name = NULL;
        gboolean changed = FALSE;
        gboolean is_absolute = is_absolute_path (new_scope);
        switch (phase) {
@@ -605,29 +940,131 @@ pinvoke_probe_transform_path (const char *new_scope, int phase, char **file_name
        return changed;
 }
 
-static MonoDl*
-pinvoke_probe_for_module (MonoImage *image, const char *new_scope, char **found_name_out, char **error_msg_out)
+static MonoDl *
+legacy_probe_for_module_in_directory (const char *mdirname, const char *file_name)
+{
+       void *iter = NULL;
+       char *full_name;
+       MonoDl* module = NULL;
+
+       while ((full_name = mono_dl_build_path (mdirname, file_name, &iter)) && module == NULL) {
+               char *error_msg;
+               module = cached_module_load (full_name, MONO_DL_LAZY, &error_msg);
+               if (!module) {
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '%s': '%s'.", full_name, error_msg);
+                       g_free (error_msg);
+               }
+               g_free (full_name);
+       }
+       g_free (full_name);
+
+       return module;
+}
+
+static MonoDl *
+legacy_probe_for_module_relative_directories (MonoImage *image, const char *file_name)
+{
+       MonoDl* module = NULL;
+
+       for (int j = 0; j < 3; ++j) {
+               char *mdirname = NULL;
+
+               switch (j) {
+                       case 0:
+                               mdirname = g_path_get_dirname (image->filename);
+                               break;
+                       case 1: // @executable_path@/../lib
+                       {
+                               char buf [4096]; // FIXME: MAX_PATH
+                               int binl;
+                               binl = mono_dl_get_executable_path (buf, sizeof (buf));
+                               if (binl != -1) {
+                                       char *base, *newbase;
+                                       char *resolvedname;
+                                       buf [binl] = 0;
+                                       resolvedname = mono_path_resolve_symlinks (buf);
+
+                                       base = g_path_get_dirname (resolvedname);
+                                       newbase = g_path_get_dirname(base);
+
+                                       // On Android the executable for the application is going to be /system/bin/app_process{32,64} depending on
+                                       // the application's architecture. However, libraries for the different architectures live in different
+                                       // subdirectories of `/system`: `lib` for 32-bit apps and `lib64` for 64-bit ones. Thus appending `/lib` below
+                                       // will fail to load the DSO for a 64-bit app, even if it exists there, because it will have a different
+                                       // architecture. This is the cause of https://github.com/xamarin/xamarin-android/issues/2780 and the ifdef
+                                       // below is the fix.
+                                       mdirname = g_strdup_printf (
+#if defined(TARGET_ANDROID) && (defined(TARGET_ARM64) || defined(TARGET_AMD64))
+                                                       "%s/lib64",
+#else
+                                                       "%s/lib",
+#endif
+                                                       newbase);
+                                       g_free (resolvedname);
+                                       g_free (base);
+                                       g_free (newbase);
+                               }
+                               break;
+                       }
+#ifdef __MACH__
+                       case 2: // @executable_path@/../Libraries
+                       {
+                               char buf [4096]; // FIXME: MAX_PATH
+                               int binl;
+                               binl = mono_dl_get_executable_path (buf, sizeof (buf));
+                               if (binl != -1) {
+                                       char *base, *newbase;
+                                       char *resolvedname;
+                                       buf [binl] = 0;
+                                       resolvedname = mono_path_resolve_symlinks (buf);
+
+                                       base = g_path_get_dirname (resolvedname);
+                                       newbase = g_path_get_dirname(base);
+                                       mdirname = g_strdup_printf ("%s/Libraries", newbase);
+
+                                       g_free (resolvedname);
+                                       g_free (base);
+                                       g_free (newbase);
+                               }
+                               break;
+                       }
+#endif
+               }
+
+               if (!mdirname)
+                       continue;
+
+               module = legacy_probe_for_module_in_directory (mdirname, file_name);
+               g_free (mdirname);
+               if (module)
+                       break;
+       }
+
+       return module;
+}
+
+static MonoDl *
+legacy_probe_for_module (MonoImage *image, const char *new_scope)
 {
        char *full_name, *file_name;
        char *error_msg = NULL;
-       char *found_name = NULL;
        int i;
        MonoDl *module = NULL;
 
-       g_assert (found_name_out);
-       g_assert (error_msg_out);
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport attempting to load: '%s'.", new_scope);
 
-       if (!module) {
-               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
-                                       "DllImport attempting to load: '%s'.", new_scope);
-
-               /* we allow a special name to dlopen from the running process namespace */
-               if (strcmp (new_scope, "__Internal") == 0){
-                       if (internal_module == NULL)
-                               internal_module = mono_dl_open (NULL, MONO_DL_LAZY, &error_msg);
-                       module = internal_module;
-                       goto leave;
+       /* we allow a special name to dlopen from the running process namespace */
+       if (strcmp (new_scope, "__Internal") == 0) {
+               if (!internal_module)
+                       internal_module = mono_dl_open (NULL, MONO_DL_LAZY, &error_msg);
+               module = internal_module;
+
+               if (!module) {
+                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", error_msg);
+                       g_free (error_msg);
                }
+
+               return module;
        }
 
        /*
@@ -637,7 +1074,7 @@ pinvoke_probe_for_module (MonoImage *image, const char *new_scope, char **found_
                char *base_name = NULL, *dir_name = NULL;
                gboolean is_absolute;
 
-               gboolean changed = pinvoke_probe_transform_path (new_scope, i, &file_name, &base_name, &dir_name, &is_absolute);
+               gboolean changed = legacy_probe_transform_path (new_scope, i, &file_name, &base_name, &dir_name, &is_absolute);
                if (!changed)
                        continue;
                
@@ -648,13 +1085,11 @@ pinvoke_probe_for_module (MonoImage *image, const char *new_scope, char **found_
                                                "DllImport error loading library '%s': '%s'.",
                                                        file_name, error_msg);
                                g_free (error_msg);
-                       } else {
-                               found_name = g_strdup (file_name);
                        }
                }
 
                if (!module && !is_absolute) {
-                       module = pinvoke_probe_for_module_relative_directories (image, file_name, &found_name);
+                       module = legacy_probe_for_module_relative_directories (image, file_name);
                }
 
                if (!module) {
@@ -667,8 +1102,6 @@ pinvoke_probe_for_module (MonoImage *image, const char *new_scope, char **found_
                                                        "DllImport error loading library '%s': '%s'.",
                                                                full_name, error_msg);
                                        g_free (error_msg);
-                               } else {
-                                       found_name = g_strdup (full_name);
                                }
                                g_free (full_name);
                                if (module)
@@ -682,8 +1115,7 @@ pinvoke_probe_for_module (MonoImage *image, const char *new_scope, char **found_
                                mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
                                                "DllImport error loading library '%s': '%s'.",
                                                        file_name, error_msg);
-                       } else {
-                               found_name = g_strdup (file_name);
+                               g_free (error_msg);
                        }
                }
 
@@ -697,145 +1129,138 @@ pinvoke_probe_for_module (MonoImage *image, const char *new_scope, char **found_
                        break;
        }
 
-leave:
-       *found_name_out = found_name;
-       *error_msg_out = error_msg;
        return module;
 }
 
-#ifdef ENABLE_NETCORE
-void
-mono_set_pinvoke_search_directories (int dir_count, char **dirs)
+static MonoDl *
+legacy_lookup_native_library (MonoImage *image, const char *scope)
 {
-       pinvoke_search_directories_count = dir_count;
-       pinvoke_search_directories = dirs;
-}
-#endif
+       MonoDl *module = NULL;
+       gboolean cached = FALSE;
 
-static MonoDl*
-pinvoke_probe_for_module_in_directory (const char *mdirname, const char *file_name, char **found_name_out)
-{
-       void *iter = NULL;
-       char *full_name;
-       MonoDl* module = NULL;
+       mono_image_lock (image);
+       if (!image->pinvoke_scopes)
+               image->pinvoke_scopes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       module = (MonoDl *)g_hash_table_lookup (image->pinvoke_scopes, scope);
+       mono_image_unlock (image);
+       if (module)
+               cached = TRUE;
 
-       while ((full_name = mono_dl_build_path (mdirname, file_name, &iter)) && module == NULL) {
-               char *error_msg;
-               module = cached_module_load (full_name, MONO_DL_LAZY, &error_msg);
-               if (!module) {
-                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '%s': '%s'.", full_name, error_msg);
-                       g_free (error_msg);
-               } else {
-                       *found_name_out = g_strdup (full_name);
+       if (!module)
+               module = legacy_probe_for_module (image, scope);
+
+       if (module && !cached) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
+                                       "DllImport loaded library '%s'.", module->full_name);
+               mono_image_lock (image);
+               if (!g_hash_table_lookup (image->pinvoke_scopes, scope)) {
+                       g_hash_table_insert (image->pinvoke_scopes, g_strdup (scope), module);
                }
-               g_free (full_name);
+               mono_image_unlock (image);
        }
-       g_free (full_name);
 
        return module;
 }
 
-static MonoDl*
-pinvoke_probe_for_module_relative_directories (MonoImage *image, const char *file_name, char **found_name_out)
+#endif // ENABLE_NETCORE
+
+gpointer
+lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_out)
 {
-       char *found_name = NULL;
-       MonoDl* module = NULL;
+       MonoImage *image = m_class_get_image (method->klass);
+#ifdef ENABLE_NETCORE
+       MonoAssemblyLoadContext *alc = mono_image_get_alc (image);
+#endif
+       MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *)method;
+       MonoTableInfo *tables = image->tables;
+       MonoTableInfo *im = &tables [MONO_TABLE_IMPLMAP];
+       MonoTableInfo *mr = &tables [MONO_TABLE_MODULEREF];
+       guint32 im_cols [MONO_IMPLMAP_SIZE];
+       guint32 scope_token;
+       const char *orig_import = NULL;
+       const char *new_import = NULL;
+       const char *orig_scope = NULL;
+       const char *new_scope = NULL;
+       char *error_msg = NULL;
+       MonoDl *module = NULL;
+       gpointer addr = NULL;
+
+       MONO_REQ_GC_UNSAFE_MODE;
 
-       g_assert (found_name_out);
+       g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
+
+       g_assert (status_out);
+
+       if (piinfo->addr)
+               return piinfo->addr;
 
-#if ENABLE_NETCORE
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "netcore DllImport handler: wanted '%s'", file_name);
+       if (image_is_dynamic (image)) {
+               MonoReflectionMethodAux *method_aux =
+                       (MonoReflectionMethodAux *)g_hash_table_lookup (
+                               ((MonoDynamicImage*)m_class_get_image (method->klass))->method_aux_hash, method);
+               if (!method_aux)
+                       goto exit;
 
-       // Search in predefined directories first
-       for (int j = 0; j < pinvoke_search_directories_count && module == NULL; ++j) {
-               module = pinvoke_probe_for_module_in_directory (pinvoke_search_directories[j], file_name, &found_name);
+               orig_import = method_aux->dllentry;
+               orig_scope = method_aux->dll;
        }
+       else {
+               if (!piinfo->implmap_idx || piinfo->implmap_idx > im->rows)
+                       goto exit;
 
-       // Fallback to image directory
-       if (module == NULL) {
-               // TODO: Check DefaultDllImportSearchPathsAttribute, NativeLibrary callback
-               char *mdirname = g_path_get_dirname (image->name);
-               if (mdirname)
-                       module = pinvoke_probe_for_module_in_directory (mdirname, file_name, &found_name);
-               g_free (mdirname);
+               mono_metadata_decode_row (im, piinfo->implmap_idx - 1, im_cols, MONO_IMPLMAP_SIZE);
+
+               if (!im_cols [MONO_IMPLMAP_SCOPE] || im_cols [MONO_IMPLMAP_SCOPE] > mr->rows)
+                       goto exit;
+
+               piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
+               orig_import = mono_metadata_string_heap (image, im_cols [MONO_IMPLMAP_NAME]);
+               scope_token = mono_metadata_decode_row_col (mr, im_cols [MONO_IMPLMAP_SCOPE] - 1, MONO_MODULEREF_NAME);
+               orig_scope = mono_metadata_string_heap (image, scope_token);
        }
+
+#ifndef DISABLE_DLLMAP
+       // FIXME: The dllmap remaps System.Native to mono-native
+       mono_dllmap_lookup (image, orig_scope, orig_import, &new_scope, &new_import);
 #else
-                       for (int j = 0; j < 3; ++j) {
-                               char *mdirname = NULL;
-                               switch (j) {
-                                       case 0:
-                                               mdirname = g_path_get_dirname (image->name);
-                                               break;
-                                       case 1: /* @executable_path@/../lib */
-                                       {
-                                               char buf [4096];
-                                               int binl;
-                                               binl = mono_dl_get_executable_path (buf, sizeof (buf));
-                                               if (binl != -1) {
-                                                       char *base, *newbase;
-                                                       char *resolvedname;
-                                                       buf [binl] = 0;
-                                                       resolvedname = mono_path_resolve_symlinks (buf);
-
-                                                       base = g_path_get_dirname (resolvedname);
-                                                       newbase = g_path_get_dirname(base);
-
-                                                       // On Android the executable for the application is going to be /system/bin/app_process{32,64} depending on
-                                                       // the application's architecture. However, libraries for the different architectures live in different
-                                                       // subdirectories of `/system`: `lib` for 32-bit apps and `lib64` for 64-bit ones. Thus appending `/lib` below
-                                                       // will fail to load the DSO for a 64-bit app, even if it exists there, because it will have a different
-                                                       // architecture. This is the cause of https://github.com/xamarin/xamarin-android/issues/2780 and the ifdef
-                                                       // below is the fix.
-                                                       mdirname = g_strdup_printf (
-#if defined(TARGET_ANDROID) && (defined(TARGET_ARM64) || defined(TARGET_AMD64))
-                                                                       "%s/lib64",
-#else
-                                                                       "%s/lib",
+       new_scope = g_strdup (orig_scope);
+       new_import = g_strdup (orig_import);
 #endif
-                                                                       newbase);
-                                                       g_free (resolvedname);
-                                                       g_free (base);
-                                                       g_free (newbase);
-                                               }
-                                               break;
-                                       }
-#ifdef __MACH__
-                                       case 2: /* @executable_path@/../Libraries */
-                                       {
-                                               char buf [4096];
-                                               int binl;
-                                               binl = mono_dl_get_executable_path (buf, sizeof (buf));
-                                               if (binl != -1) {
-                                                       char *base, *newbase;
-                                                       char *resolvedname;
-                                                       buf [binl] = 0;
-                                                       resolvedname = mono_path_resolve_symlinks (buf);
-
-                                                       base = g_path_get_dirname (resolvedname);
-                                                       newbase = g_path_get_dirname(base);
-                                                       mdirname = g_strdup_printf ("%s/Libraries", newbase);
-
-                                                       g_free (resolvedname);
-                                                       g_free (base);
-                                                       g_free (newbase);
-                                               }
-                                               break;
-                                       }
+
+#ifdef ENABLE_NETCORE
+       // FIXME: these flags are not getting passed correctly
+       module = netcore_lookup_native_library (alc, image, new_scope, 0);
+#else
+       module = legacy_lookup_native_library (image, new_scope);
 #endif
-                               }
 
-                               if (!mdirname)
-                                       continue;
+       if (!module) {
+               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DLLIMPORT,
+                               "DllImport unable to load library '%s'.",
+                               new_scope);
 
-                               module = pinvoke_probe_for_module_in_directory (mdirname, file_name, &found_name);
-                               g_free (mdirname);
-                               if (module)
-                                       break;
-                       }
-#endif
+               status_out->err_code = LOOKUP_PINVOKE_ERR_NO_LIB;
+               status_out->err_arg = g_strdup (new_scope);
+               goto exit;
+       }
 
-       *found_name_out = found_name;
-       return module;
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
+                               "DllImport searching in: '%s' ('%s').", new_scope, module->full_name);
+
+       addr = pinvoke_probe_for_symbol (module, piinfo, new_import, &error_msg);
+
+       if (!addr) {
+               status_out->err_code = LOOKUP_PINVOKE_ERR_NO_SYM;
+               status_out->err_arg = g_strdup (new_import);
+               goto exit;
+       }
+       piinfo->addr = addr;
+
+exit:
+       g_free ((char *)new_import);
+       g_free ((char *)new_scope);
+       g_free (error_msg);
+       return addr;
 }
 
 static gpointer
@@ -859,9 +1284,9 @@ pinvoke_probe_for_symbol (MonoDl *module, MonoMethodPInvoke *piinfo, const char
        mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
                                "Searching for '%s'.", import);
 
-       if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE) {
-               error_msg = mono_dl_symbol (module, import, &addr); 
-       else {
+       if (piinfo->piflags & PINVOKE_ATTRIBUTE_NO_MANGLE)
+               error_msg = mono_dl_symbol (module, import, &addr);
+       else {
                /*
                 * Search using a variety of mangled names
                 */
@@ -947,3 +1372,153 @@ pinvoke_probe_for_symbol (MonoDl *module, MonoMethodPInvoke *piinfo, const char
        *error_msg_out = error_msg;
        return addr;
 }
+
+#ifdef ENABLE_NETCORE
+void
+ves_icall_System_Runtime_InteropServices_NativeLibrary_FreeLib (gpointer lib, MonoError *error)
+{
+       MonoDl *module;
+       guint32 ref_count;
+
+       g_assert (lib);
+
+       // Don't free __Internal
+       if (internal_module && lib == internal_module->handle)
+               return;
+
+       native_library_lock ();
+
+       module = netcore_handle_lookup (lib);
+       if (!module)
+               goto leave;
+
+       ref_count = mono_refcount_dec (module);
+       if (ref_count > 0)
+               goto leave;
+
+       g_hash_table_remove (native_library_module_map, module->handle);
+       g_hash_table_add (native_library_module_blacklist, module);
+       mono_dl_close (module);
+
+leave:
+       native_library_unlock ();
+}
+
+gpointer
+ves_icall_System_Runtime_InteropServices_NativeLibrary_GetSymbol (gpointer lib, MonoStringHandle symbol_name_handle, MonoBoolean throw_on_error, MonoError *error)
+{
+       MonoDl *module;
+       gpointer symbol = NULL;
+       char *symbol_name;
+
+       g_assert (lib);
+
+       ERROR_LOCAL_BEGIN (local_error, error, throw_on_error)
+
+       symbol_name = mono_string_handle_to_utf8 (symbol_name_handle, error);
+       goto_if_nok (error, leave_nolock);
+
+       native_library_lock ();
+
+       module = netcore_handle_lookup (lib);
+       if (!module)
+               mono_error_set_generic_error (error, "System", "DllNotFoundException", "%p: %s", lib, symbol_name);
+       goto_if_nok (error, leave);
+
+       mono_dl_symbol (module, symbol_name, &symbol);
+       if (!symbol)
+               mono_error_set_generic_error (error, "System", "EntryPointNotFoundException", "%s: %s", module->full_name, symbol_name);
+       goto_if_nok (error, leave);
+
+leave:
+       native_library_unlock ();
+
+leave_nolock:
+       ERROR_LOCAL_END (local_error);
+
+       return symbol;
+}
+
+// LOCKING: expects you to hold native_library_module_lock
+static MonoDl *
+check_native_library_cache (MonoDl *module)
+{
+       gpointer handle = module->handle;
+
+       MonoDl *cached_module = netcore_handle_lookup (handle);
+       if (cached_module) {
+               g_free (module->full_name);
+               g_free (module);
+               mono_refcount_inc (cached_module);
+               return cached_module;
+       }
+       g_hash_table_insert (native_library_module_map, handle, (gpointer)module);
+
+       return module;
+}
+
+gpointer
+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)
+{
+       MonoDl *module;
+       gpointer handle = NULL;
+       MonoAssembly *assembly = MONO_HANDLE_GETVAL (assembly_handle, assembly);
+       MonoImage *image = mono_assembly_get_image_internal (assembly);
+       char *lib_name;
+
+       ERROR_LOCAL_BEGIN (local_error, error, throw_on_error)
+
+       lib_name = mono_string_handle_to_utf8 (lib_name_handle, error);
+       goto_if_nok (error, leave);
+
+       // FIXME: implement search flag defaults properly
+       module = netcore_probe_for_module (image, lib_name, has_search_flag ? search_flag : 0x2);
+       if (!module)
+               mono_error_set_generic_error (error, "System", "DllNotFoundException", "%s", lib_name);
+       goto_if_nok (error, leave);
+
+       native_library_lock ();
+       module = check_native_library_cache (module);
+       native_library_unlock ();
+
+       handle = module->handle;
+
+leave:
+       ERROR_LOCAL_END (local_error);
+
+       return handle;
+}
+
+gpointer
+ves_icall_System_Runtime_InteropServices_NativeLibrary_LoadFromPath (MonoStringHandle lib_path_handle, MonoBoolean throw_on_error, MonoError *error)
+{
+       MonoDl *module;
+       gpointer handle = NULL;
+       char *error_msg = NULL;
+       char *lib_path;
+
+       ERROR_LOCAL_BEGIN (local_error, error, throw_on_error)
+
+       lib_path = mono_string_handle_to_utf8 (lib_path_handle, error);
+       goto_if_nok (error, leave);
+
+       module = mono_dl_open (lib_path, MONO_DL_LAZY, &error_msg);
+       if (!module) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '%s': '%s'.", lib_path, error_msg);
+               mono_error_set_generic_error (error, "System", "DllNotFoundException", "'%s': '%s'", lib_path, error_msg);
+               g_free (error_msg);
+       }
+       goto_if_nok (error, leave);
+
+       native_library_lock ();
+       module = check_native_library_cache (module);
+       native_library_unlock ();
+
+       handle = module->handle;
+
+leave:
+       ERROR_LOCAL_END (local_error);
+
+       return handle;
+}
+#endif
index f52103a..bf5e8fc 100644 (file)
@@ -191,6 +191,7 @@ mono_dl_open (const char *name, int flags, char **error_msg)
        void *lib;
        MonoDlFallbackHandler *dl_fallback = NULL;
        int lflags = mono_dl_convert_flags (flags);
+       char *found_name;
 
        if (error_msg)
                *error_msg = NULL;
@@ -209,6 +210,8 @@ mono_dl_open (const char *name, int flags, char **error_msg)
 
        // No GC safe transition because this is called early in main.c
        lib = mono_dl_open_file (name, lflags);
+       if (lib)
+               found_name = g_strdup (name);
 
        if (!lib) {
                GSList *node;
@@ -223,6 +226,7 @@ mono_dl_open (const char *name, int flags, char **error_msg)
                        
                        if (lib != NULL){
                                dl_fallback = handler;
+                               found_name = g_strdup (name);
                                break;
                        }
                }
@@ -247,6 +251,8 @@ mono_dl_open (const char *name, int flags, char **error_msg)
                g_free (lname);
                if (llname) {
                        lib = mono_dl_open_file (llname, lflags);
+                       if (lib)
+                               found_name = g_strdup (llname);
 #if defined (_AIX)
                        /*
                         * HACK: deal with AIX archive members because libtool
@@ -260,6 +266,8 @@ mono_dl_open (const char *name, int flags, char **error_msg)
                                char *llaixname;
                                llaixname = g_strconcat (llname, "(shr_64.o)", (const char*)NULL);
                                lib = mono_dl_open_file (llaixname, lflags);
+                               if (lib)
+                                       found_name = g_strdup (llaixname);
                                /* XXX: try another suffix like (shr.o)? */
                                g_free (llaixname);
                        }
@@ -274,8 +282,10 @@ mono_dl_open (const char *name, int flags, char **error_msg)
                        return NULL;
                }
        }
+       mono_refcount_init (module, NULL);
        module->handle = lib;
        module->dl_fallback = dl_fallback;
+       module->full_name = found_name;
        return module;
 }
 
@@ -338,6 +348,7 @@ mono_dl_close (MonoDl *module)
        } else
                mono_dl_close_handle (module);
        
+       g_free (module->full_name);
        g_free (module);
 }
 
index 3c99b30..9c8154c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "mono/utils/mono-compiler.h"
 #include "mono/utils/mono-dl-fallback.h"
+#include "mono/utils/refcount.h"
 
 #ifdef TARGET_WIN32
 #define MONO_SOLIB_EXT ".dll"
 #endif
 
 typedef struct {
+       // Only used in native-library.c, native library lock should be held when modifying
+       // Incremented on NativeLibrary.Load calls, decremented on NativeLibrary.Free
+       MonoRefCount ref;
        void *handle;
        int main_module;
-
+       char *full_name;
        /* If not NULL, use the methods in MonoDlFallbackHandler instead of the LL_* methods */
        MonoDlFallbackHandler *dl_fallback;
 } MonoDl;
index 8d7a80d..8de15c5 100644 (file)
@@ -98,6 +98,17 @@ Different names indicate different scenarios, but the same code.
 #define MONO_API_ERROR_INIT(error)     error_init_internal (error)
 #define error_init_reuse(error)        error_init_internal (error)
 
+#define ERROR_LOCAL_BEGIN(local, parent, skip_overwrite) do { \
+MonoError local; \
+gboolean local ## _overwrite_temp = skip_overwrite; \
+error_init_internal (&local); \
+if (!local ## _overwrite_temp) \
+       parent = &local; \
+
+#define ERROR_LOCAL_END(local) if (!local ## _overwrite_temp) \
+       mono_error_cleanup (&local); \
+} while (0) \
+
 // Historical deferred initialization was called error_init.
 
 // possible bug detection that did not work
index 665529e..b8dc9dc 100644 (file)
@@ -27,7 +27,7 @@ typedef struct {
 #define mono_refcount_init(v,destructor) do { mono_refcount_initialize (&(v)->ref, (destructor)); } while (0)
 #define mono_refcount_inc(v) (mono_refcount_increment (&(v)->ref),(v))
 #define mono_refcount_tryinc(v) (mono_refcount_tryincrement (&(v)->ref))
-#define mono_refcount_dec(v) do { mono_refcount_decrement (&(v)->ref); } while (0)
+#define mono_refcount_dec(v) (mono_refcount_decrement (&(v)->ref))
 
 static inline void
 mono_refcount_initialize (MonoRefCount *refcount, void (*destructor) (gpointer data))
@@ -61,7 +61,7 @@ mono_refcount_increment (MonoRefCount *refcount)
                g_error ("%s: cannot increment a ref with value 0", __func__);
 }
 
-static inline void
+static inline guint32
 mono_refcount_decrement (MonoRefCount *refcount)
 {
        guint32 oldref, newref;
@@ -78,6 +78,8 @@ mono_refcount_decrement (MonoRefCount *refcount)
 
        if (newref == 0 && refcount->destructor)
                refcount->destructor ((gpointer) refcount);
+
+       return newref;
 }
 
 #endif /* __MONO_UTILS_REFCOUNT_H__ */
index 3960d1b..090e5d9 100644 (file)
 -nomethod System.Security.Cryptography.Encoding.Tests.OidTests.LookupOidByFriendlyName_Ctor
 
 -nomethod System.Tests.StringComparerTests.CreateCultureOptions_InvalidArguments_Throws
-
-# Requires NativeLibrary implementation
--nomethod System.Net.Tests.HttpWebRequestTest.ServicePoint_GetValue_ExpectedResult
-
index 1f31f31..0ad7f8f 100644 (file)
@@ -23,6 +23,3 @@
 
 # Requires precise GC (should be ignored in dotnet/corefx for mono)
 -nomethod System.Collections.Concurrent.Tests.ConcurrentQueueTests.ReferenceTypes_NulledAfterDequeue
-
-# Requires NativeLibrary implementation
--nomethod System.Data.Odbc.Tests.DependencyCheckTest.OdbcConnection_OpenWhenOdbcNotInstalled_ThrowsException
index f2bd945..2cb1b1f 100644 (file)
                <type fullname="System.Runtime.InteropServices.MarshalDirectiveException">
                        <method signature="System.Void .ctor(System.String)" />
                </type>
+
+               <!-- native-library.c: mono_class_get_native_library_class -->
+               <type fullname="System.Runtime.InteropServices.NativeLibrary">
+                       <method name="MonoLoadLibraryCallbackStub" />
+                       <method name="MonoResolveUnmanagedDll" />
+                       <method name="MonoResolveUnmanagedDllUsingEvent" />
+               </type>
                
                <!-- domain.c: mono_defaults.monitor_class -->
                <!-- monitor.c / method-to-ir.c: Enter and Exit are only string comparison (safe to link) -->
index f342485..32605af 100644 (file)
@@ -4,25 +4,36 @@
 
 using System.IO;
 using System.Reflection;
+using System.Runtime.CompilerServices;
 
 namespace System.Runtime.InteropServices
 {
        partial class NativeLibrary
        {
-               static IntPtr LoadLibraryByName (string libraryName, Assembly assembly, DllImportSearchPath? searchPath, bool throwOnError) => throw new NotImplementedException ();
-
-               static IntPtr LoadFromPath (string libraryName, bool throwOnError) {
-                       // TODO: implement
-                       if (throwOnError) {
-                               throw new DllNotFoundException();
-                       }
-                       return IntPtr.Zero;
+               static IntPtr LoadLibraryByName (string libraryName, Assembly assembly, DllImportSearchPath? searchPath, bool throwOnError)
+               {
+                       return LoadByName (libraryName,
+                                          (RuntimeAssembly)assembly,
+                                          searchPath.HasValue,
+                                          (uint)searchPath.GetValueOrDefault(),
+                                          throwOnError);
                }
 
-               static IntPtr LoadByName (string libraryName, RuntimeAssembly callingAssembly, bool hasDllImportSearchPathFlag, uint dllImportSearchPathFlag, bool throwOnError) => throw new NotImplementedException ();
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               extern static IntPtr LoadFromPath (string libraryName, bool throwOnError);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               extern static IntPtr LoadByName (string libraryName, RuntimeAssembly callingAssembly, bool hasDllImportSearchPathFlag, uint dllImportSearchPathFlag, bool throwOnError);
 
-               static void FreeLib (IntPtr handle) => throw new NotImplementedException ();
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               extern static void FreeLib (IntPtr handle);
 
-               static IntPtr GetSymbol (IntPtr handle, string symbolName, bool throwOnError) => throw new NotImplementedException ();
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               extern static IntPtr GetSymbol (IntPtr handle, string symbolName, bool throwOnError);
+
+               private static void MonoLoadLibraryCallbackStub (string libraryName, Assembly assembly, bool hasDllImportSearchPathFlags, uint dllImportSearchPathFlags, ref IntPtr dll)
+               {
+                       dll = LoadLibraryCallbackStub (libraryName, assembly, hasDllImportSearchPathFlags, dllImportSearchPathFlags);
+               }
        }
 }
index 61143c6..8dd1c3f 100644 (file)
@@ -71,15 +71,7 @@ namespace System.Runtime.Loader
                        if (rtAsm != null) {
                                RuntimeAssembly runtimeAssembly = rtAsm;
                                IntPtr ptrAssemblyLoadContext = GetLoadContextForAssembly (runtimeAssembly);
-                               if (ptrAssemblyLoadContext == IntPtr.Zero)
-                               {
-                                       // If the load context is returned null, then the assembly was bound using the TPA binder
-                                       // and we shall return reference to the active "Default" binder - which could be the TPA binder
-                                       // or an overridden CLRPrivBinderAssemblyLoadContext instance.
-                                       loadContextForAssembly = AssemblyLoadContext.Default;
-                               } else {
-                                       loadContextForAssembly = (AssemblyLoadContext) (GCHandle.FromIntPtr (ptrAssemblyLoadContext).Target)!;
-                               }
+                               loadContextForAssembly = GetAssemblyLoadContext (ptrAssemblyLoadContext);
                        }
 
                        return loadContextForAssembly;
@@ -130,6 +122,53 @@ namespace System.Runtime.Loader
                        return ResolveSatelliteAssembly (gchALC, new AssemblyName (assemblyName));
                }
 
+               private static AssemblyLoadContext GetAssemblyLoadContext (IntPtr gchManagedAssemblyLoadContext)
+               {
+                       AssemblyLoadContext context;
+                       // This check exists because the function can be called early in startup, before the default ALC is initialized
+                       if (gchManagedAssemblyLoadContext == IntPtr.Zero)
+                               context = AssemblyLoadContext.Default;
+                       else
+                               context = (AssemblyLoadContext)(GCHandle.FromIntPtr (gchManagedAssemblyLoadContext).Target)!;
+                       return context;
+               }
+
+               private static void MonoResolveUnmanagedDll (string unmanagedDllName, IntPtr gchManagedAssemblyLoadContext, ref IntPtr dll)
+               {
+                       AssemblyLoadContext context = GetAssemblyLoadContext (gchManagedAssemblyLoadContext);
+                       dll = context.LoadUnmanagedDll(unmanagedDllName);
+               }
+
+               private static void MonoResolveUnmanagedDllUsingEvent (string unmanagedDllName, Assembly assembly, IntPtr gchManagedAssemblyLoadContext, ref IntPtr dll)
+               {
+                       AssemblyLoadContext context = GetAssemblyLoadContext (gchManagedAssemblyLoadContext);
+                       dll = context.GetResolvedUnmanagedDll(assembly, unmanagedDllName);
+               }
+
+#region Copied from AssemblyLoadContext.CoreCLR.cs, being moved to shared
+               private IntPtr GetResolvedUnmanagedDll(Assembly assembly, string unmanagedDllName)
+               {
+                       IntPtr resolvedDll = IntPtr.Zero;
+
+                       Func<Assembly, string, IntPtr>? dllResolveHandler = _resolvingUnmanagedDll;
+
+                       if (dllResolveHandler != null)
+                       {
+                               // Loop through the event subscribers and return the first non-null native library handle
+                               foreach (Func<Assembly, string, IntPtr> handler in dllResolveHandler.GetInvocationList())
+                               {
+                                       resolvedDll = handler(assembly, unmanagedDllName);
+                                       if (resolvedDll != IntPtr.Zero)
+                                       {
+                                               return resolvedDll;
+                                       }
+                               }
+                       }
+
+                       return IntPtr.Zero;
+               }
+#endregion
+
 #region Copied from AssemblyLoadContext.CoreCLR.cs, modified until our AssemblyBuilder implementation is functional
                private static RuntimeAssembly? GetRuntimeAssembly(Assembly? asm)
                {