[loader] Move PInvoke and DllMap code into separate source file
authorRyan Lucia <rylucia@microsoft.com>
Tue, 8 Oct 2019 22:02:05 +0000 (18:02 -0400)
committerRyan Lucia <ryan@luciaonline.net>
Mon, 14 Oct 2019 16:51:29 +0000 (12:51 -0400)
Commit migrated from https://github.com/mono/mono/commit/bf3afd6cad3974706287d0943c3a5d0e823c1e5f

src/mono/mono/metadata/Makefile.am
src/mono/mono/metadata/loader-internals.h
src/mono/mono/metadata/loader.c
src/mono/mono/metadata/loader.h
src/mono/mono/metadata/metadata-internals.h
src/mono/mono/metadata/mono-config.c
src/mono/mono/metadata/native-library.c [new file with mode: 0644]
src/mono/msvc/libmonoruntime-common.targets
src/mono/msvc/libmonoruntime-common.targets.filters

index 0ca4f7a..c23570a 100644 (file)
@@ -421,8 +421,8 @@ common_sources = \
        fdhandle.c      \
        callspec.h      \
        callspec.c      \
-       abi.c
-
+       abi.c   \
+       native-library.c
 
 # These source files have compile time dependencies on GC code
 gc_dependent_sources = \
index 9d61ed4..4837040 100644 (file)
 typedef struct _MonoLoadedImages MonoLoadedImages;
 typedef struct _MonoAssemblyLoadContext MonoAssemblyLoadContext;
 
+typedef struct _MonoDllMap MonoDllMap;
+struct _MonoDllMap {
+       char *dll;
+       char *target;
+       char *func;
+       char *target_func;
+       MonoDllMap *next;
+};
+
 #ifdef ENABLE_NETCORE
 /* FIXME: this probably belongs somewhere else */
 struct _MonoAssemblyLoadContext {
@@ -30,9 +39,24 @@ struct _MonoAssemblyLoadContext {
 };
 #endif /* ENABLE_NETCORE */
 
+void
+mono_global_loader_data_lock (void);
+
+void
+mono_global_loader_data_unlock (void);
+
 gpointer
 mono_lookup_pinvoke_call_internal (MonoMethod *method, MonoError *error);
 
+void
+mono_dllmap_insert_internal (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc);
+
+void
+mono_global_dllmap_cleanup (void);
+
+void
+mono_cached_module_cleanup (void);
+
 #ifdef ENABLE_NETCORE
 void
 mono_set_pinvoke_search_directories (int dir_count, char **dirs);
index baf7241..1919ef4 100644 (file)
@@ -51,8 +51,6 @@
 #include <mono/utils/mono-tls.h>
 #include <mono/utils/mono-path.h>
 
-MonoDefaults mono_defaults;
-
 /*
  * This lock protects the hash tables inside MonoImage used by the metadata 
  * loading functions in class.c and loader.c.
@@ -63,12 +61,7 @@ MonoDefaults mono_defaults;
 static MonoCoopMutex loader_mutex;
 static mono_mutex_t global_loader_data_mutex;
 static gboolean loader_lock_inited;
-
-/* Statistics */
-static gint32 inflated_signatures_size;
-static gint32 memberref_sig_cache_size;
-static gint32 methods_size;
-static gint32 signatures_size;
+static gboolean loader_lock_track_ownership = FALSE;
 
 /*
  * This TLS variable holds how many times the current thread has acquired the loader 
@@ -76,33 +69,13 @@ static gint32 signatures_size;
  */
 static MonoNativeTlsKey loader_lock_nest_id;
 
-#if ENABLE_NETCORE
-static int pinvoke_search_directories_count;
-static char **pinvoke_search_directories;
-#endif
-
-static void dllmap_cleanup (void);
-static void cached_module_cleanup(void);
-
-static void dllmap_insert_global (const char *dll, const char *func, const char *tdll, const char *tfunc);
-static void dllmap_insert_image (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfun);
-
-
-/* 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")
-
-static void
-global_loader_data_lock (void)
-{
-       mono_locks_os_acquire (&global_loader_data_mutex, LoaderGlobalDataLock);
-}
+MonoDefaults mono_defaults;
 
-static void
-global_loader_data_unlock (void)
-{
-       mono_locks_os_release (&global_loader_data_mutex, LoaderGlobalDataLock);
-}
+/* Statistics */
+static gint32 inflated_signatures_size;
+static gint32 memberref_sig_cache_size;
+static gint32 methods_size;
+static gint32 signatures_size;
 
 void
 mono_loader_init ()
@@ -133,8 +106,8 @@ mono_loader_init ()
 void
 mono_loader_cleanup (void)
 {
-       dllmap_cleanup ();
-       cached_module_cleanup ();
+       mono_global_dllmap_cleanup ();
+       mono_cached_module_cleanup ();
 
        mono_native_tls_free (loader_lock_nest_id);
 
@@ -143,6 +116,91 @@ mono_loader_cleanup (void)
        loader_lock_inited = FALSE;     
 }
 
+void
+mono_global_loader_data_lock (void)
+{
+       mono_locks_os_acquire (&global_loader_data_mutex, LoaderGlobalDataLock);
+}
+
+void
+mono_global_loader_data_unlock (void)
+{
+       mono_locks_os_release (&global_loader_data_mutex, LoaderGlobalDataLock);
+}
+
+/**
+ * mono_loader_lock:
+ *
+ * See \c docs/thread-safety.txt for the locking strategy.
+ */
+void
+mono_loader_lock (void)
+{
+       mono_locks_coop_acquire (&loader_mutex, LoaderLock);
+       if (G_UNLIKELY (loader_lock_track_ownership)) {
+               mono_native_tls_set_value (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) + 1));
+       }
+}
+
+/**
+ * mono_loader_unlock:
+ */
+void
+mono_loader_unlock (void)
+{
+       mono_locks_coop_release (&loader_mutex, LoaderLock);
+       if (G_UNLIKELY (loader_lock_track_ownership)) {
+               mono_native_tls_set_value (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) - 1));
+       }
+}
+
+/*
+ * mono_loader_lock_track_ownership:
+ *
+ *   Set whenever the runtime should track ownership of the loader lock. If set to TRUE,
+ * the mono_loader_lock_is_owned_by_self () can be called to query whenever the current
+ * thread owns the loader lock. 
+ */
+void
+mono_loader_lock_track_ownership (gboolean track)
+{
+       loader_lock_track_ownership = track;
+}
+
+/*
+ * mono_loader_lock_is_owned_by_self:
+ *
+ *   Return whenever the current thread owns the loader lock.
+ * This is useful to avoid blocking operations while holding the loader lock.
+ */
+gboolean
+mono_loader_lock_is_owned_by_self (void)
+{
+       g_assert (loader_lock_track_ownership);
+
+       return GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) > 0;
+}
+
+/*
+ * mono_loader_lock_if_inited:
+ *
+ *   Acquire the loader lock if it has been initialized, no-op otherwise. This can
+ * be used in runtime initialization code which can be executed before mono_loader_init ().
+ */
+void
+mono_loader_lock_if_inited (void)
+{
+       if (loader_lock_inited)
+               mono_loader_lock ();
+}
+
+void
+mono_loader_unlock_if_inited (void)
+{
+       if (loader_lock_inited)
+               mono_loader_unlock ();
+}
+
 /*
  * find_cached_memberref_sig:
  *
@@ -965,878 +1023,6 @@ method_from_methodspec (MonoImage *image, MonoGenericContext *context, guint32 i
        return method;
 }
 
-struct _MonoDllMap {
-       char *dll;
-       char *target;
-       char *func;
-       char *target_func;
-       MonoDllMap *next;
-};
-
-static MonoDllMap *global_dll_map;
-
-static int 
-mono_dllmap_lookup_list (MonoDllMap *dll_map, const char *dll, const char* func, const char **rdll, const char **rfunc) {
-       int found = 0;
-
-       *rdll = dll;
-
-       if (!dll_map)
-               return 0;
-
-       global_loader_data_lock ();
-
-       /* 
-        * we use the first entry we find that matches, since entries from
-        * the config file are prepended to the list and we document that the
-        * later entries win.
-        */
-       for (; dll_map; dll_map = dll_map->next) {
-               if (dll_map->dll [0] == 'i' && dll_map->dll [1] == ':') {
-                       if (g_ascii_strcasecmp (dll_map->dll + 2, dll))
-                               continue;
-               } else if (strcmp (dll_map->dll, dll)) {
-                       continue;
-               }
-               if (!found && dll_map->target) {
-                       *rdll = dll_map->target;
-                       found = 1;
-                       /* we don't quit here, because we could find a full
-                        * entry that matches also function and that has priority.
-                        */
-               }
-               if (dll_map->func && strcmp (dll_map->func, func) == 0) {
-                       *rdll = dll_map->target;
-                       *rfunc = dll_map->target_func;
-                       break;
-               }
-       }
-
-       global_loader_data_unlock ();
-       return found;
-}
-
-static int 
-mono_dllmap_lookup (MonoImage *assembly, const char *dll, const char* func, const char **rdll, const char **rfunc)
-{
-       int res;
-       if (assembly && assembly->dll_map) {
-               res = mono_dllmap_lookup_list (assembly->dll_map, dll, func, rdll, rfunc);
-               if (res)
-                       return res;
-       }
-       return mono_dllmap_lookup_list (global_dll_map, dll, func, rdll, rfunc);
-}
-
-/**
- * mono_dllmap_insert:
- * \param assembly if NULL, this is a global mapping, otherwise the remapping of the dynamic library will only apply to the specified assembly
- * \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
- * \param func if not null, the mapping will only applied to the named function (the value of <code>EntryPoint</code>)
- * \param tdll The name of the library to map the specified \p dll if it matches.
- * \param tfunc The name of the function that replaces the invocation.  If NULL, it is replaced with a copy of \p func.
- *
- * LOCKING: Acquires the loader lock.
- *
- * This function is used to programatically add \c DllImport remapping in either
- * a specific assembly, or as a global remapping.   This is done by remapping
- * references in a \c DllImport attribute from the \p dll library name into the \p tdll
- * name. If the \p dll name contains the prefix <code>i:</code>, the comparison of the 
- * library name is done without case sensitivity.
- *
- * If you pass \p func, this is the name of the \c EntryPoint in a \c DllImport if specified
- * or the name of the function as determined by \c DllImport. If you pass \p func, you
- * must also pass \p tfunc which is the name of the target function to invoke on a match.
- *
- * Example:
- *
- * <code>mono_dllmap_insert (NULL, "i:libdemo.dll", NULL, relocated_demo_path, NULL);</code>
- *
- * The above will remap \c DllImport statements for \c libdemo.dll and \c LIBDEMO.DLL to
- * the contents of \c relocated_demo_path for all assemblies in the Mono process.
- *
- * NOTE: This can be called before the runtime is initialized, for example from
- * \c mono_config_parse.
- */
-void
-mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc)
-{
-       if (!assembly)
-               dllmap_insert_global (dll, func, tdll, tfunc);
-       else {
-               MONO_ENTER_GC_UNSAFE;
-               dllmap_insert_image (assembly, dll, func, tdll, tfunc);
-               MONO_EXIT_GC_UNSAFE;
-       }
-}
-
-void
-dllmap_insert_global (const char *dll, const char *func, const char *tdll, const char *tfunc)
-{
-       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;
-               entry->func = func? g_strdup (func): NULL;
-               entry->target_func = tfunc? g_strdup (tfunc): (func? g_strdup (func): NULL);
-
-               global_loader_data_lock ();
-               entry->next = global_dll_map;
-               global_dll_map = entry;
-               global_loader_data_unlock ();
-}
-
-void
-dllmap_insert_image (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc)
-{
-       MonoDllMap *entry;
-       g_assert (assembly != NULL);
-
-               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;
-               entry->func = func? mono_image_strdup (assembly, func): NULL;
-               entry->target_func = tfunc? mono_image_strdup (assembly, tfunc): (func? mono_image_strdup (assembly, func): NULL);
-
-               mono_image_lock (assembly);
-               entry->next = assembly->dll_map;
-               assembly->dll_map = entry;
-               mono_image_unlock (assembly);
-}
-
-static void
-free_dllmap (MonoDllMap *map)
-{
-       while (map) {
-               MonoDllMap *next = map->next;
-
-               g_free (map->dll);
-               g_free (map->target);
-               g_free (map->func);
-               g_free (map->target_func);
-               g_free (map);
-               map = next;
-       }
-}
-
-static void
-dllmap_cleanup (void)
-{
-       free_dllmap (global_dll_map);
-       global_dll_map = NULL;
-}
-
-static GHashTable *global_module_map;
-
-static MonoDl*
-cached_module_load (const char *name, int flags, char **err)
-{
-       MonoDl *res;
-
-       if (err)
-               *err = NULL;
-       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) {
-               global_loader_data_unlock ();
-               return res;
-       }
-       res = mono_dl_open (name, flags, err);
-       if (res)
-               g_hash_table_insert (global_module_map, g_strdup (name), res);
-       global_loader_data_unlock ();
-       return res;
-}
-
-void
-mono_loader_register_module (const char *name, MonoDl *module)
-{
-       if (!global_module_map)
-               global_module_map = g_hash_table_new (g_str_hash, g_str_equal);
-       g_hash_table_insert (global_module_map, g_strdup (name), module);
-}
-
-static void
-remove_cached_module(gpointer key, gpointer value, gpointer user_data)
-{
-       mono_dl_close((MonoDl*)value);
-}
-
-static void
-cached_module_cleanup(void)
-{
-       if (global_module_map != NULL) {
-               g_hash_table_foreach(global_module_map, remove_cached_module, NULL);
-
-               g_hash_table_destroy(global_module_map);
-               global_module_map = NULL;
-       }
-}
-
-static MonoDl *internal_module;
-
-static gboolean
-is_absolute_path (const char *path)
-{
-#ifdef HOST_DARWIN
-       if (!strncmp (path, "@executable_path/", 17) || !strncmp (path, "@loader_path/", 13) ||
-           !strncmp (path, "@rpath/", 7))
-           return TRUE;
-#endif
-       return g_path_is_absolute (path);
-}
-
-typedef enum {
-       LOOKUP_PINVOKE_ERR_OK = 0, /* No error */
-       LOOKUP_PINVOKE_ERR_NO_LIB, /* DllNotFoundException */
-       LOOKUP_PINVOKE_ERR_NO_SYM, /* EntryPointNotFoundException */
-} MonoLookupPInvokeErr;
-
-/* We should just use a MonoError, but mono_lookup_pinvoke_call has this legacy
- * error reporting mechanism where it returns an exception class and a string
- * message.  So instead we return an error code and message, and for internal
- * callers convert it to a MonoError.
- *
- * Don't expose this type to the runtime.  It's just an implementation
- * detail for backward compatability.
- */
-typedef struct MonoLookupPInvokeStatus {
-       MonoLookupPInvokeErr err_code;
-       char *err_arg;
-} MonoLookupPInvokeStatus;
-
-static gpointer
-lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_out);
-
-static void
-pinvoke_probe_convert_status_for_api (MonoLookupPInvokeStatus *status, const char **exc_class, const char **exc_arg)
-{
-       if (!exc_class)
-               return;
-       switch (status->err_code) {
-       case LOOKUP_PINVOKE_ERR_OK:
-               *exc_class = NULL;
-               *exc_arg = NULL;
-               break;
-       case LOOKUP_PINVOKE_ERR_NO_LIB:
-               *exc_class = "DllNotFoundException";
-               *exc_arg = status->err_arg;
-               status->err_arg = NULL;
-               break;
-       case LOOKUP_PINVOKE_ERR_NO_SYM:
-               *exc_class = "EntryPointNotFoundException";
-               *exc_arg = status->err_arg;
-               status->err_arg = NULL;
-               break;
-       default:
-               g_assert_not_reached ();
-       }
-}
-
-static void
-pinvoke_probe_convert_status_to_error (MonoLookupPInvokeStatus *status, MonoError *error)
-{
-       /* Note: this has to return a MONO_ERROR_GENERIC because mono_mb_emit_exception_for_error only knows how to decode generic errors. */
-       switch (status->err_code) {
-       case LOOKUP_PINVOKE_ERR_OK:
-               return;
-       case LOOKUP_PINVOKE_ERR_NO_LIB:
-               mono_error_set_generic_error (error, "System", "DllNotFoundException", "%s", status->err_arg);
-               g_free (status->err_arg);
-               status->err_arg = NULL;
-               break;
-       case LOOKUP_PINVOKE_ERR_NO_SYM:
-               mono_error_set_generic_error (error, "System", "EntryPointNotFoundException", "%s", status->err_arg);
-               g_free (status->err_arg);
-               status->err_arg = NULL;
-               break;
-       default:
-               g_assert_not_reached ();
-       }
-}
-
-/**
- * mono_lookup_pinvoke_call:
- */
-gpointer
-mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char **exc_arg)
-{
-       gpointer result;
-       MONO_ENTER_GC_UNSAFE;
-       MonoLookupPInvokeStatus status;
-       memset (&status, 0, sizeof (status));
-       result = lookup_pinvoke_call_impl (method, &status);
-       pinvoke_probe_convert_status_for_api (&status, exc_class, exc_arg);
-       MONO_EXIT_GC_UNSAFE;
-       return result;
-}
-
-static MonoDl*
-pinvoke_probe_for_module (MonoImage *image, const char*new_scope, const char *import, 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)
-{
-       gpointer result;
-       MonoLookupPInvokeStatus status;
-       memset (&status, 0, sizeof (status));
-       result = lookup_pinvoke_call_impl (method, &status);
-       if (status.err_code)
-               pinvoke_probe_convert_status_to_error (&status, error);
-       return result;
-}
-
-gpointer
-lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_out)
-{
-       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 *import = NULL;
-       const char *orig_scope;
-       const char *new_scope;
-       char *error_msg;
-       char *found_name = NULL;
-       MonoDl *module = NULL;
-       gboolean cached = FALSE;
-       gpointer addr = NULL;
-
-       g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
-
-       g_assert (status_out);
-
-       if (piinfo->addr)
-               return piinfo->addr;
-
-       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)
-                       return NULL;
-
-               import = method_aux->dllentry;
-               orig_scope = method_aux->dll;
-       }
-       else {
-               if (!piinfo->implmap_idx || piinfo->implmap_idx > im->rows)
-                       return NULL;
-
-               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)
-                       return NULL;
-
-               piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
-               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 ENABLE_NETCORE
-       // FIXME: The dllmap remaps System.Native to mono-native
-       mono_dllmap_lookup (image, orig_scope, import, &new_scope, &import);
-#else
-       /* AK: FIXME: dllmap, above doesn't strdup the results, so these leak
-        * since there's no free() */
-       new_scope = g_strdup (orig_scope);
-       import = g_strdup (import);
-#endif
-
-       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;
-               if (found_name)
-                       found_name = g_strdup (found_name);
-       }
-
-       if (!module)
-               module = pinvoke_probe_for_module (image, new_scope, import, &found_name, &error_msg);
-
-       if (!module) {
-               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DLLIMPORT,
-                               "DllImport unable to load library '%s'.",
-                               error_msg);
-               g_free (error_msg);
-
-               status_out->err_code = LOOKUP_PINVOKE_ERR_NO_LIB;
-               status_out->err_arg = g_strdup (new_scope);
-               return NULL;
-       }
-
-       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);
-       }
-
-       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
-                               "DllImport searching in: '%s' ('%s').", new_scope, found_name);
-       g_free (found_name);
-
-       addr = pinvoke_probe_for_symbol (module, piinfo, import, &error_msg);
-
-       if (!addr) {
-               g_free (error_msg);
-               status_out->err_code = LOOKUP_PINVOKE_ERR_NO_SYM;
-               status_out->err_arg = g_strdup (import);
-               return NULL;
-       }
-       piinfo->addr = addr;
-       return addr;
-}
-
-/**
- * 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)
-{
-       char *file_name = NULL, *base_name = NULL, *dir_name = NULL;
-       gboolean changed = FALSE;
-       gboolean is_absolute = is_absolute_path (new_scope);
-       switch (phase) {
-       case 0:
-               /* Try the original name */
-               file_name = g_strdup (new_scope);
-               changed = TRUE;
-               break;
-       case 1:
-               /* Try trimming the .dll extension */
-               if (strstr (new_scope, ".dll") == (new_scope + strlen (new_scope) - 4)) {
-                       file_name = g_strdup (new_scope);
-                       file_name [strlen (new_scope) - 4] = '\0';
-                       changed = TRUE;
-               }
-               break;
-       case 2:
-               if (is_absolute) {
-                       dir_name = g_path_get_dirname (new_scope);
-                       base_name = g_path_get_basename (new_scope);
-                       if (strstr (base_name, "lib") != base_name) {
-                               char *tmp = g_strdup_printf ("lib%s", base_name);       
-                               g_free (base_name);
-                               base_name = tmp;
-                               file_name = g_strdup_printf ("%s%s%s", dir_name, G_DIR_SEPARATOR_S, base_name);
-                               changed = TRUE;
-                       }
-               } else if (strstr (new_scope, "lib") != new_scope) {
-                       file_name = g_strdup_printf ("lib%s", new_scope);
-                       changed = TRUE;
-               }
-               break;
-       case 3:
-               if (!is_absolute && mono_dl_get_system_dir ()) {
-                       dir_name = (char*)mono_dl_get_system_dir ();
-                       file_name = g_path_get_basename (new_scope);
-                       base_name = NULL;
-                       changed = TRUE;
-               }
-               break;
-       default:
-#ifndef TARGET_WIN32
-               if (!g_ascii_strcasecmp ("user32.dll", new_scope) ||
-                   !g_ascii_strcasecmp ("kernel32.dll", new_scope) ||
-                   !g_ascii_strcasecmp ("user32", new_scope) ||
-                   !g_ascii_strcasecmp ("kernel", new_scope)) {
-                       file_name = g_strdup ("libMonoSupportW.so");
-                       changed = TRUE;
-               }
-#endif
-               break;
-       }
-       if (changed && is_absolute) {
-               if (!dir_name)
-                       dir_name = g_path_get_dirname (file_name);
-               if (!base_name)
-                       base_name = g_path_get_basename (file_name);
-       }
-       *file_name_out = file_name;
-       *base_name_out = base_name;
-       *dir_name_out = dir_name;
-       *is_absolute_out = is_absolute;
-       return changed;
-}
-
-static MonoDl*
-pinvoke_probe_for_module (MonoImage *image, const char*new_scope, const char *import, char **found_name_out, char **error_msg_out)
-{
-       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);
-
-       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;
-               }
-       }
-
-       /*
-        * Try loading the module using a variety of names
-        */
-       for (i = 0; i < 5; ++i) {
-               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);
-               if (!changed)
-                       continue;
-               
-               if (!module && is_absolute) {
-                       module = cached_module_load (file_name, MONO_DL_LAZY, &error_msg);
-                       if (!module) {
-                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
-                                               "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);
-               }
-
-               if (!module) {
-                       void *iter = NULL;
-                       char *file_or_base = is_absolute ? base_name : file_name;
-                       while ((full_name = mono_dl_build_path (dir_name, file_or_base, &iter))) {
-                               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 = g_strdup (full_name);
-                               }
-                               g_free (full_name);
-                               if (module)
-                                       break;
-                       }
-               }
-
-               if (!module) {
-                       module = cached_module_load (file_name, MONO_DL_LAZY, &error_msg);
-                       if (!module) {
-                               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 (file_name);
-               if (is_absolute) {
-                       g_free (base_name);
-                       g_free (dir_name);
-               }
-
-               if (module)
-                       break;
-       }
-
-       *found_name_out = found_name;
-       *error_msg_out = error_msg;
-       return module;
-}
-
-#if ENABLE_NETCORE
-void
-mono_set_pinvoke_search_directories (int dir_count, char **dirs)
-{
-       pinvoke_search_directories_count = dir_count;
-       pinvoke_search_directories = dirs;
-}
-#endif
-
-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;
-
-       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);
-               }
-               g_free (full_name);
-       }
-       g_free (full_name);
-
-       return module;
-}
-
-static MonoDl*
-pinvoke_probe_for_module_relative_directories (MonoImage *image, const char *file_name, char **found_name_out)
-{
-       char *found_name = NULL;
-       MonoDl* module = NULL;
-
-       g_assert (found_name_out);
-
-#if ENABLE_NETCORE
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "netcore DllImport handler: wanted '%s'", file_name);
-
-       // 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);
-       }
-
-       // 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);
-       }
-#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",
-#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;
-                                       }
-#endif
-                               }
-
-                               if (!mdirname)
-                                       continue;
-
-                               module = pinvoke_probe_for_module_in_directory (mdirname, file_name, &found_name);
-                               g_free (mdirname);
-                               if (module)
-                                       break;
-                       }
-#endif
-
-       *found_name_out = found_name;
-       return module;
-}
-
-
-static gpointer
-pinvoke_probe_for_symbol (MonoDl *module, MonoMethodPInvoke *piinfo, const char *import, char **error_msg_out)
-{
-       char *error_msg = NULL;
-       gpointer addr = NULL;
-
-       g_assert (error_msg_out);
-
-#ifdef HOST_WIN32
-       if (import && import [0] == '#' && isdigit (import [1])) {
-               char *end;
-               long id;
-
-               id = strtol (import + 1, &end, 10);
-               if (id > 0 && *end == '\0')
-                       import++;
-       }
-#endif
-       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 {
-               /*
-                * Search using a variety of mangled names
-                */
-               for (int mangle_stdcall = 0; mangle_stdcall <= 1 && addr == NULL; mangle_stdcall++) {
-#if HOST_WIN32 && HOST_X86
-                       const int max_managle_param_count = (mangle_stdcall == 0) ? 0 : 256;
-#else
-                       const int max_managle_param_count = 0;
-#endif
-                       for (int mangle_charset = 0; mangle_charset <= 1 && addr == NULL; mangle_charset ++) {
-                               for (int mangle_param_count = 0; mangle_param_count <= max_managle_param_count && addr == NULL; mangle_param_count += 4) {
-
-                                       char *mangled_name = (char*)import;
-                                       switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
-                                       case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
-                                               /* Try the mangled name first */
-                                               if (mangle_charset == 0)
-                                                       mangled_name = g_strconcat (import, "W", (const char*)NULL);
-                                               break;
-                                       case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
-#ifdef HOST_WIN32
-                                               if (mangle_charset == 0)
-                                                       mangled_name = g_strconcat (import, "W", (const char*)NULL);
-#else
-                                               /* Try the mangled name last */
-                                               if (mangle_charset == 1)
-                                                       mangled_name = g_strconcat (import, "A", (const char*)NULL);
-#endif
-                                               break;
-                                       case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
-                                       default:
-                                               /* Try the mangled name last */
-                                               if (mangle_charset == 1)
-                                                       mangled_name = g_strconcat (import, "A", (const char*)NULL);
-                                               break;
-                                       }
-
-#if HOST_WIN32 && HOST_X86
-                                       /* Try the stdcall mangled name */
-                                       /* 
-                                        * gcc under windows creates mangled names without the underscore, but MS.NET
-                                        * doesn't support it, so we doesn't support it either.
-                                        */
-                                       if (mangle_stdcall == 1) {
-                                               MonoMethod *method = &piinfo->method;
-                                               int param_count;
-                                               if (mangle_param_count == 0)
-                                                       param_count = mono_method_signature_internal (method)->param_count * sizeof (gpointer);
-                                               else
-                                                       /* Try brute force, since it would be very hard to compute the stack usage correctly */
-                                                       param_count = mangle_param_count;
-
-                                               char *mangled_stdcall_name = g_strdup_printf ("_%s@%d", mangled_name, param_count);
-
-                                               if (mangled_name != import)
-                                                       g_free (mangled_name);
-
-                                               mangled_name = mangled_stdcall_name;
-                                       }
-#endif
-                                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
-                                                               "Probing '%s'.", mangled_name);
-
-                                       error_msg = mono_dl_symbol (module, mangled_name, &addr);
-
-                                       if (addr)
-                                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
-                                                                       "Found as '%s'.", mangled_name);
-                                       else
-                                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
-                                                                       "Could not find '%s' due to '%s'.", mangled_name, error_msg);
-
-                                       g_free (error_msg);
-                                       error_msg = NULL;
-
-                                       if (mangled_name != import)
-                                               g_free (mangled_name);
-                               }
-                       }
-               }
-       }
-
-       *error_msg_out = error_msg;
-       return addr;
-}
-
 /*
  * LOCKING: assumes the loader lock to be taken.
  */
@@ -2597,81 +1783,6 @@ mono_method_get_last_managed (void)
        return m;
 }
 
-static gboolean loader_lock_track_ownership = FALSE;
-
-/**
- * mono_loader_lock:
- *
- * See \c docs/thread-safety.txt for the locking strategy.
- */
-void
-mono_loader_lock (void)
-{
-       mono_locks_coop_acquire (&loader_mutex, LoaderLock);
-       if (G_UNLIKELY (loader_lock_track_ownership)) {
-               mono_native_tls_set_value (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) + 1));
-       }
-}
-
-/**
- * mono_loader_unlock:
- */
-void
-mono_loader_unlock (void)
-{
-       mono_locks_coop_release (&loader_mutex, LoaderLock);
-       if (G_UNLIKELY (loader_lock_track_ownership)) {
-               mono_native_tls_set_value (loader_lock_nest_id, GUINT_TO_POINTER (GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) - 1));
-       }
-}
-
-/*
- * mono_loader_lock_track_ownership:
- *
- *   Set whenever the runtime should track ownership of the loader lock. If set to TRUE,
- * the mono_loader_lock_is_owned_by_self () can be called to query whenever the current
- * thread owns the loader lock. 
- */
-void
-mono_loader_lock_track_ownership (gboolean track)
-{
-       loader_lock_track_ownership = track;
-}
-
-/*
- * mono_loader_lock_is_owned_by_self:
- *
- *   Return whenever the current thread owns the loader lock.
- * This is useful to avoid blocking operations while holding the loader lock.
- */
-gboolean
-mono_loader_lock_is_owned_by_self (void)
-{
-       g_assert (loader_lock_track_ownership);
-
-       return GPOINTER_TO_UINT (mono_native_tls_get_value (loader_lock_nest_id)) > 0;
-}
-
-/*
- * mono_loader_lock_if_inited:
- *
- *   Acquire the loader lock if it has been initialized, no-op otherwise. This can
- * be used in runtime initialization code which can be executed before mono_loader_init ().
- */
-void
-mono_loader_lock_if_inited (void)
-{
-       if (loader_lock_inited)
-               mono_loader_lock ();
-}
-
-void
-mono_loader_unlock_if_inited (void)
-{
-       if (loader_lock_inited)
-               mono_loader_unlock ();
-}
-
 /**
  * mono_method_signature_checked_slow:
  *
index ad70c77..42c8928 100644 (file)
@@ -68,7 +68,7 @@ mono_lookup_internal_call (MonoMethod *method);
 MONO_API const char*
 mono_lookup_icall_symbol (MonoMethod *m);
 
-MONO_API void
+MONO_API MONO_RT_EXTERNAL_ONLY void
 mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc);
 
 MONO_API MONO_RT_EXTERNAL_ONLY void*
index b033439..eb2b4f8 100644 (file)
@@ -298,8 +298,6 @@ struct _MonoTableInfo {
 
 #define REFERENCE_MISSING ((gpointer) -1)
 
-typedef struct _MonoDllMap MonoDllMap;
-
 typedef struct {
        gboolean (*match) (MonoImage*);
        gboolean (*load_pe_data) (MonoImage*);
index aa9e554..29590ad 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "mono/metadata/assembly.h"
 #include "mono/metadata/loader.h"
+#include "mono/metadata/loader-internals.h"
 #include "mono/metadata/mono-config.h"
 #include "mono/metadata/mono-config-internals.h"
 #include "mono/metadata/metadata-internals.h"
@@ -342,7 +343,7 @@ dllmap_start (gpointer user_data,
                                info->ignore = TRUE;
                }
                if (!info->ignore)
-                       mono_dllmap_insert (info->assembly, info->dll, NULL, info->target, NULL);
+                       mono_dllmap_insert_internal (info->assembly, info->dll, NULL, info->target, NULL);
        } else if (strcmp (element_name, "dllentry") == 0) {
                const char *name = NULL, *target = NULL, *dll = NULL;
                int ignore = FALSE;
@@ -363,7 +364,7 @@ dllmap_start (gpointer user_data,
                if (!dll)
                        dll = info->dll;
                if (!info->ignore && !ignore)
-                       mono_dllmap_insert (info->assembly, info->dll, name, dll, target);
+                       mono_dllmap_insert_internal (info->assembly, info->dll, name, dll, target);
        }
 }
 
diff --git a/src/mono/mono/metadata/native-library.c b/src/mono/mono/metadata/native-library.c
new file mode 100644 (file)
index 0000000..0f72894
--- /dev/null
@@ -0,0 +1,890 @@
+#include "config.h"
+#include "mono/utils/mono-compiler.h"
+#include "mono/metadata/loader-internals.h"
+#include "mono/metadata/loader.h"
+#include "mono/metadata/class-internals.h"
+#include "mono/utils/mono-logger-internals.h"
+#include "mono/utils/mono-path.h"
+
+#ifdef ENABLE_NETCORE
+static int pinvoke_search_directories_count;
+static char **pinvoke_search_directories;
+#endif
+
+static MonoDllMap *global_dll_map;
+static GHashTable *global_module_map;
+
+static MonoDl *internal_module;
+
+typedef enum {
+       LOOKUP_PINVOKE_ERR_OK = 0, /* No error */
+       LOOKUP_PINVOKE_ERR_NO_LIB, /* DllNotFoundException */
+       LOOKUP_PINVOKE_ERR_NO_SYM, /* EntryPointNotFoundException */
+} MonoLookupPInvokeErr;
+
+/* We should just use a MonoError, but mono_lookup_pinvoke_call has this legacy
+ * error reporting mechanism where it returns an exception class and a string
+ * message.  So instead we return an error code and message, and for internal
+ * callers convert it to a MonoError.
+ *
+ * Don't expose this type to the runtime.  It's just an implementation
+ * detail for backward compatability.
+ */
+typedef struct MonoLookupPInvokeStatus {
+       MonoLookupPInvokeErr err_code;
+       char *err_arg;
+} 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")
+
+#ifndef ENABLE_NETCORE
+/*
+ * LOCKING: Assumes the relevant lock is held.
+ * For the global DllMap, this is `global_loader_data_mutex`, and for images it's their internal lock.
+ */
+static int 
+mono_dllmap_lookup_list (MonoDllMap *dll_map, const char *dll, const char* func, const char **rdll, const char **rfunc) {
+       int found = 0;
+
+       *rdll = dll;
+
+       if (!dll_map)
+               return 0;
+
+       mono_global_loader_data_lock ();
+
+       /* 
+        * we use the first entry we find that matches, since entries from
+        * the config file are prepended to the list and we document that the
+        * later entries win.
+        */
+       for (; dll_map; dll_map = dll_map->next) {
+               if (dll_map->dll [0] == 'i' && dll_map->dll [1] == ':') {
+                       if (g_ascii_strcasecmp (dll_map->dll + 2, dll))
+                               continue;
+               } else if (strcmp (dll_map->dll, dll)) {
+                       continue;
+               }
+               if (!found && dll_map->target) {
+                       *rdll = dll_map->target;
+                       found = 1;
+                       /* we don't quit here, because we could find a full
+                        * entry that matches also function and that has priority.
+                        */
+               }
+               if (dll_map->func && strcmp (dll_map->func, func) == 0) {
+                       *rdll = dll_map->target;
+                       *rfunc = dll_map->target_func;
+                       break;
+               }
+       }
+
+       mono_global_loader_data_unlock ();
+       return found;
+}
+
+static int 
+mono_dllmap_lookup (MonoImage *assembly, const char *dll, const char* func, const char **rdll, const char **rfunc)
+{
+       int res;
+       if (assembly && assembly->dll_map) {
+               res = mono_dllmap_lookup_list (assembly->dll_map, dll, func, rdll, rfunc);
+               if (res)
+                       return res;
+       }
+       return mono_dllmap_lookup_list (global_dll_map, dll, func, rdll, rfunc);
+}
+#endif
+
+static void
+dllmap_insert_global (const char *dll, const char *func, const char *tdll, const char *tfunc)
+{
+       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;
+               entry->func = func? g_strdup (func): NULL;
+               entry->target_func = tfunc? g_strdup (tfunc): (func? g_strdup (func): NULL);
+
+               mono_global_loader_data_lock ();
+               entry->next = global_dll_map;
+               global_dll_map = entry;
+               mono_global_loader_data_unlock ();
+}
+
+static void
+dllmap_insert_image (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc)
+{
+       MonoDllMap *entry;
+       g_assert (assembly != NULL);
+
+               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;
+               entry->func = func? mono_image_strdup (assembly, func): NULL;
+               entry->target_func = tfunc? mono_image_strdup (assembly, tfunc): (func? mono_image_strdup (assembly, func): NULL);
+
+               mono_image_lock (assembly);
+               entry->next = assembly->dll_map;
+               assembly->dll_map = entry;
+               mono_image_unlock (assembly);
+}
+
+static void
+free_dllmap (MonoDllMap *map)
+{
+       while (map) {
+               MonoDllMap *next = map->next;
+
+               g_free (map->dll);
+               g_free (map->target);
+               g_free (map->func);
+               g_free (map->target_func);
+               g_free (map);
+               map = next;
+       }
+}
+
+void
+mono_dllmap_insert_internal (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc)
+{
+       if (!assembly)
+               dllmap_insert_global (dll, func, tdll, tfunc);
+       else {
+               MONO_ENTER_GC_UNSAFE;
+               dllmap_insert_image (assembly, dll, func, tdll, tfunc);
+               MONO_EXIT_GC_UNSAFE;
+       }
+}
+
+/**
+ * mono_dllmap_insert:
+ * \param assembly if NULL, this is a global mapping, otherwise the remapping of the dynamic library will only apply to the specified assembly
+ * \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
+ * \param func if not null, the mapping will only applied to the named function (the value of <code>EntryPoint</code>)
+ * \param tdll The name of the library to map the specified \p dll if it matches.
+ * \param tfunc The name of the function that replaces the invocation.  If NULL, it is replaced with a copy of \p func.
+ *
+ * LOCKING: Acquires the loader lock.
+ *
+ * This function is used to programatically add \c DllImport remapping in either
+ * a specific assembly, or as a global remapping.   This is done by remapping
+ * references in a \c DllImport attribute from the \p dll library name into the \p tdll
+ * name. If the \p dll name contains the prefix <code>i:</code>, the comparison of the 
+ * library name is done without case sensitivity.
+ *
+ * If you pass \p func, this is the name of the \c EntryPoint in a \c DllImport if specified
+ * or the name of the function as determined by \c DllImport. If you pass \p func, you
+ * must also pass \p tfunc which is the name of the target function to invoke on a match.
+ *
+ * Example:
+ *
+ * <code>mono_dllmap_insert (NULL, "i:libdemo.dll", NULL, relocated_demo_path, NULL);</code>
+ *
+ * The above will remap \c DllImport statements for \c libdemo.dll and \c LIBDEMO.DLL to
+ * the contents of \c relocated_demo_path for all assemblies in the Mono process.
+ *
+ * NOTE: This can be called before the runtime is initialized, for example from
+ * \c mono_config_parse.
+ */
+void
+mono_dllmap_insert (MonoImage *assembly, const char *dll, const char *func, const char *tdll, const char *tfunc)
+{
+       mono_dllmap_insert_internal (assembly, dll, func, tdll, tfunc);
+}
+
+void
+mono_global_dllmap_cleanup (void)
+{
+       free_dllmap (global_dll_map);
+       global_dll_map = NULL;
+}
+
+static MonoDl*
+cached_module_load (const char *name, int flags, char **err)
+{
+       MonoDl *res;
+
+       if (err)
+               *err = NULL;
+       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) {
+               mono_global_loader_data_unlock ();
+               return res;
+       }
+       res = mono_dl_open (name, flags, err);
+       if (res)
+               g_hash_table_insert (global_module_map, g_strdup (name), res);
+       mono_global_loader_data_unlock ();
+       return res;
+}
+
+void
+mono_loader_register_module (const char *name, MonoDl *module)
+{
+       if (!global_module_map)
+               global_module_map = g_hash_table_new (g_str_hash, g_str_equal);
+       g_hash_table_insert (global_module_map, g_strdup (name), module);
+}
+
+static void
+remove_cached_module (gpointer key, gpointer value, gpointer user_data)
+{
+       mono_dl_close((MonoDl*)value);
+}
+
+void
+mono_cached_module_cleanup (void)
+{
+       if (global_module_map != NULL) {
+               g_hash_table_foreach(global_module_map, remove_cached_module, NULL);
+
+               g_hash_table_destroy(global_module_map);
+               global_module_map = NULL;
+       }
+}
+
+static gboolean
+is_absolute_path (const char *path)
+{
+#ifdef HOST_DARWIN
+       if (!strncmp (path, "@executable_path/", 17) || !strncmp (path, "@loader_path/", 13) ||
+           !strncmp (path, "@rpath/", 7))
+           return TRUE;
+#endif
+       return g_path_is_absolute (path);
+}
+
+static gpointer
+lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_out);
+
+static void
+pinvoke_probe_convert_status_for_api (MonoLookupPInvokeStatus *status, const char **exc_class, const char **exc_arg)
+{
+       if (!exc_class)
+               return;
+       switch (status->err_code) {
+       case LOOKUP_PINVOKE_ERR_OK:
+               *exc_class = NULL;
+               *exc_arg = NULL;
+               break;
+       case LOOKUP_PINVOKE_ERR_NO_LIB:
+               *exc_class = "DllNotFoundException";
+               *exc_arg = status->err_arg;
+               status->err_arg = NULL;
+               break;
+       case LOOKUP_PINVOKE_ERR_NO_SYM:
+               *exc_class = "EntryPointNotFoundException";
+               *exc_arg = status->err_arg;
+               status->err_arg = NULL;
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+}
+
+static void
+pinvoke_probe_convert_status_to_error (MonoLookupPInvokeStatus *status, MonoError *error)
+{
+       /* Note: this has to return a MONO_ERROR_GENERIC because mono_mb_emit_exception_for_error only knows how to decode generic errors. */
+       switch (status->err_code) {
+       case LOOKUP_PINVOKE_ERR_OK:
+               return;
+       case LOOKUP_PINVOKE_ERR_NO_LIB:
+               mono_error_set_generic_error (error, "System", "DllNotFoundException", "%s", status->err_arg);
+               g_free (status->err_arg);
+               status->err_arg = NULL;
+               break;
+       case LOOKUP_PINVOKE_ERR_NO_SYM:
+               mono_error_set_generic_error (error, "System", "EntryPointNotFoundException", "%s", status->err_arg);
+               g_free (status->err_arg);
+               status->err_arg = NULL;
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+}
+
+/**
+ * mono_lookup_pinvoke_call:
+ */
+gpointer
+mono_lookup_pinvoke_call (MonoMethod *method, const char **exc_class, const char **exc_arg)
+{
+       gpointer result;
+       MONO_ENTER_GC_UNSAFE;
+       MonoLookupPInvokeStatus status;
+       memset (&status, 0, sizeof (status));
+       result = lookup_pinvoke_call_impl (method, &status);
+       pinvoke_probe_convert_status_for_api (&status, exc_class, exc_arg);
+       MONO_EXIT_GC_UNSAFE;
+       return result;
+}
+
+static MonoDl*
+pinvoke_probe_for_module (MonoImage *image, const char*new_scope, const char *import, 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)
+{
+       gpointer result;
+       MonoLookupPInvokeStatus status;
+       memset (&status, 0, sizeof (status));
+       result = lookup_pinvoke_call_impl (method, &status);
+       if (status.err_code)
+               pinvoke_probe_convert_status_to_error (&status, error);
+       return result;
+}
+
+gpointer
+lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_out)
+{
+       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 *import = NULL;
+       const char *orig_scope;
+       const char *new_scope;
+       char *error_msg;
+       char *found_name = NULL;
+       MonoDl *module = NULL;
+       gboolean cached = FALSE;
+       gpointer addr = NULL;
+
+       g_assert (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
+
+       g_assert (status_out);
+
+       if (piinfo->addr)
+               return piinfo->addr;
+
+       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)
+                       return NULL;
+
+               import = method_aux->dllentry;
+               orig_scope = method_aux->dll;
+       }
+       else {
+               if (!piinfo->implmap_idx || piinfo->implmap_idx > im->rows)
+                       return NULL;
+
+               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)
+                       return NULL;
+
+               piinfo->piflags = im_cols [MONO_IMPLMAP_FLAGS];
+               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 ENABLE_NETCORE
+       // FIXME: The dllmap remaps System.Native to mono-native
+       mono_dllmap_lookup (image, orig_scope, import, &new_scope, &import);
+#else
+       /* AK: FIXME: dllmap, above doesn't strdup the results, so these leak
+        * since there's no free() */
+       new_scope = g_strdup (orig_scope);
+       import = g_strdup (import);
+#endif
+
+       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;
+               if (found_name)
+                       found_name = g_strdup (found_name);
+       }
+
+       if (!module)
+               module = pinvoke_probe_for_module (image, new_scope, import, &found_name, &error_msg);
+
+       if (!module) {
+               mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DLLIMPORT,
+                               "DllImport unable to load library '%s'.",
+                               error_msg);
+               g_free (error_msg);
+
+               status_out->err_code = LOOKUP_PINVOKE_ERR_NO_LIB;
+               status_out->err_arg = g_strdup (new_scope);
+               return NULL;
+       }
+
+       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);
+       }
+
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
+                               "DllImport searching in: '%s' ('%s').", new_scope, found_name);
+       g_free (found_name);
+
+       addr = pinvoke_probe_for_symbol (module, piinfo, import, &error_msg);
+
+       if (!addr) {
+               g_free (error_msg);
+               status_out->err_code = LOOKUP_PINVOKE_ERR_NO_SYM;
+               status_out->err_arg = g_strdup (import);
+               return NULL;
+       }
+       piinfo->addr = addr;
+       return addr;
+}
+
+/**
+ * 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)
+{
+       char *file_name = NULL, *base_name = NULL, *dir_name = NULL;
+       gboolean changed = FALSE;
+       gboolean is_absolute = is_absolute_path (new_scope);
+       switch (phase) {
+       case 0:
+               /* Try the original name */
+               file_name = g_strdup (new_scope);
+               changed = TRUE;
+               break;
+       case 1:
+               /* Try trimming the .dll extension */
+               if (strstr (new_scope, ".dll") == (new_scope + strlen (new_scope) - 4)) {
+                       file_name = g_strdup (new_scope);
+                       file_name [strlen (new_scope) - 4] = '\0';
+                       changed = TRUE;
+               }
+               break;
+       case 2:
+               if (is_absolute) {
+                       dir_name = g_path_get_dirname (new_scope);
+                       base_name = g_path_get_basename (new_scope);
+                       if (strstr (base_name, "lib") != base_name) {
+                               char *tmp = g_strdup_printf ("lib%s", base_name);       
+                               g_free (base_name);
+                               base_name = tmp;
+                               file_name = g_strdup_printf ("%s%s%s", dir_name, G_DIR_SEPARATOR_S, base_name);
+                               changed = TRUE;
+                       }
+               } else if (strstr (new_scope, "lib") != new_scope) {
+                       file_name = g_strdup_printf ("lib%s", new_scope);
+                       changed = TRUE;
+               }
+               break;
+       case 3:
+               if (!is_absolute && mono_dl_get_system_dir ()) {
+                       dir_name = (char*)mono_dl_get_system_dir ();
+                       file_name = g_path_get_basename (new_scope);
+                       base_name = NULL;
+                       changed = TRUE;
+               }
+               break;
+       default:
+#ifndef TARGET_WIN32
+               if (!g_ascii_strcasecmp ("user32.dll", new_scope) ||
+                   !g_ascii_strcasecmp ("kernel32.dll", new_scope) ||
+                   !g_ascii_strcasecmp ("user32", new_scope) ||
+                   !g_ascii_strcasecmp ("kernel", new_scope)) {
+                       file_name = g_strdup ("libMonoSupportW.so");
+                       changed = TRUE;
+               }
+#endif
+               break;
+       }
+       if (changed && is_absolute) {
+               if (!dir_name)
+                       dir_name = g_path_get_dirname (file_name);
+               if (!base_name)
+                       base_name = g_path_get_basename (file_name);
+       }
+       *file_name_out = file_name;
+       *base_name_out = base_name;
+       *dir_name_out = dir_name;
+       *is_absolute_out = is_absolute;
+       return changed;
+}
+
+static MonoDl*
+pinvoke_probe_for_module (MonoImage *image, const char *new_scope, const char *import, char **found_name_out, char **error_msg_out)
+{
+       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);
+
+       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;
+               }
+       }
+
+       /*
+        * Try loading the module using a variety of names
+        */
+       for (i = 0; i < 5; ++i) {
+               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);
+               if (!changed)
+                       continue;
+               
+               if (!module && is_absolute) {
+                       module = cached_module_load (file_name, MONO_DL_LAZY, &error_msg);
+                       if (!module) {
+                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
+                                               "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);
+               }
+
+               if (!module) {
+                       void *iter = NULL;
+                       char *file_or_base = is_absolute ? base_name : file_name;
+                       while ((full_name = mono_dl_build_path (dir_name, file_or_base, &iter))) {
+                               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 = g_strdup (full_name);
+                               }
+                               g_free (full_name);
+                               if (module)
+                                       break;
+                       }
+               }
+
+               if (!module) {
+                       module = cached_module_load (file_name, MONO_DL_LAZY, &error_msg);
+                       if (!module) {
+                               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 (file_name);
+               if (is_absolute) {
+                       g_free (base_name);
+                       g_free (dir_name);
+               }
+
+               if (module)
+                       break;
+       }
+
+       *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)
+{
+       pinvoke_search_directories_count = dir_count;
+       pinvoke_search_directories = dirs;
+}
+#endif
+
+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;
+
+       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);
+               }
+               g_free (full_name);
+       }
+       g_free (full_name);
+
+       return module;
+}
+
+static MonoDl*
+pinvoke_probe_for_module_relative_directories (MonoImage *image, const char *file_name, char **found_name_out)
+{
+       char *found_name = NULL;
+       MonoDl* module = NULL;
+
+       g_assert (found_name_out);
+
+#if ENABLE_NETCORE
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "netcore DllImport handler: wanted '%s'", file_name);
+
+       // 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);
+       }
+
+       // 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);
+       }
+#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",
+#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;
+                                       }
+#endif
+                               }
+
+                               if (!mdirname)
+                                       continue;
+
+                               module = pinvoke_probe_for_module_in_directory (mdirname, file_name, &found_name);
+                               g_free (mdirname);
+                               if (module)
+                                       break;
+                       }
+#endif
+
+       *found_name_out = found_name;
+       return module;
+}
+
+static gpointer
+pinvoke_probe_for_symbol (MonoDl *module, MonoMethodPInvoke *piinfo, const char *import, char **error_msg_out)
+{
+       char *error_msg = NULL;
+       gpointer addr = NULL;
+
+       g_assert (error_msg_out);
+
+#ifdef HOST_WIN32
+       if (import && import [0] == '#' && isdigit (import [1])) {
+               char *end;
+               long id;
+
+               id = strtol (import + 1, &end, 10);
+               if (id > 0 && *end == '\0')
+                       import++;
+       }
+#endif
+       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 {
+               /*
+                * Search using a variety of mangled names
+                */
+               for (int mangle_stdcall = 0; mangle_stdcall <= 1 && addr == NULL; mangle_stdcall++) {
+#if HOST_WIN32 && HOST_X86
+                       const int max_managle_param_count = (mangle_stdcall == 0) ? 0 : 256;
+#else
+                       const int max_managle_param_count = 0;
+#endif
+                       for (int mangle_charset = 0; mangle_charset <= 1 && addr == NULL; mangle_charset ++) {
+                               for (int mangle_param_count = 0; mangle_param_count <= max_managle_param_count && addr == NULL; mangle_param_count += 4) {
+
+                                       char *mangled_name = (char*)import;
+                                       switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
+                                       case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
+                                               /* Try the mangled name first */
+                                               if (mangle_charset == 0)
+                                                       mangled_name = g_strconcat (import, "W", (const char*)NULL);
+                                               break;
+                                       case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
+#ifdef HOST_WIN32
+                                               if (mangle_charset == 0)
+                                                       mangled_name = g_strconcat (import, "W", (const char*)NULL);
+#else
+                                               /* Try the mangled name last */
+                                               if (mangle_charset == 1)
+                                                       mangled_name = g_strconcat (import, "A", (const char*)NULL);
+#endif
+                                               break;
+                                       case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
+                                       default:
+                                               /* Try the mangled name last */
+                                               if (mangle_charset == 1)
+                                                       mangled_name = g_strconcat (import, "A", (const char*)NULL);
+                                               break;
+                                       }
+
+#if HOST_WIN32 && HOST_X86
+                                       /* Try the stdcall mangled name */
+                                       /* 
+                                        * gcc under windows creates mangled names without the underscore, but MS.NET
+                                        * doesn't support it, so we doesn't support it either.
+                                        */
+                                       if (mangle_stdcall == 1) {
+                                               MonoMethod *method = &piinfo->method;
+                                               int param_count;
+                                               if (mangle_param_count == 0)
+                                                       param_count = mono_method_signature_internal (method)->param_count * sizeof (gpointer);
+                                               else
+                                                       /* Try brute force, since it would be very hard to compute the stack usage correctly */
+                                                       param_count = mangle_param_count;
+
+                                               char *mangled_stdcall_name = g_strdup_printf ("_%s@%d", mangled_name, param_count);
+
+                                               if (mangled_name != import)
+                                                       g_free (mangled_name);
+
+                                               mangled_name = mangled_stdcall_name;
+                                       }
+#endif
+                                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
+                                                               "Probing '%s'.", mangled_name);
+
+                                       error_msg = mono_dl_symbol (module, mangled_name, &addr);
+
+                                       if (addr)
+                                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
+                                                                       "Found as '%s'.", mangled_name);
+                                       else
+                                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT,
+                                                                       "Could not find '%s' due to '%s'.", mangled_name, error_msg);
+
+                                       g_free (error_msg);
+                                       error_msg = NULL;
+
+                                       if (mangled_name != import)
+                                               g_free (mangled_name);
+                               }
+                       }
+               }
+       }
+
+       *error_msg_out = error_msg;
+       return addr;
+}
index b1cc248..4b59bea 100644 (file)
     </ClCompile>
     <ClInclude Include="$(MonoSourceLocation)\mono\metadata\mono-route.h" />
     <ClInclude Include="$(MonoSourceLocation)\mono\metadata\monitor.h" />
+    <ClCompile Include="$(MonoSourceLocation)\mono\metadata\native-library.c" />
     <ClInclude Include="$(MonoSourceLocation)\mono\metadata\normalization-tables.h" />
     <ClInclude Include="$(MonoSourceLocation)\mono\metadata\number-formatter.h" />
     <ClInclude Include="$(MonoSourceLocation)\mono\metadata\number-ms.h" />
index 3457886..51903fe 100644 (file)
     <ClInclude Include="$(MonoSourceLocation)\mono\metadata\runtime.h">
       <Filter>Header Files$(MonoRuntimeFilterSubFolder)\common</Filter>
     </ClInclude>
+    <ClCompile Include="$(MonoSourceLocation)\mono\metadata\native-library.c">
+      <Filter>Source Files$(MonoRuntimeFilterSubFolder)\common</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup Label="config_sources">
     <ClInclude Include="$(MonoSourceLocation)\mono\metadata\mono-config-dirs.h">