2 * assembly.c: Routines for loading assemblies.
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc. http://www.ximian.com
10 * Implement big-endian versions of the reading routines.
21 #include "rawbuffer.h"
23 #include "mono-bundle.h"
25 #include <mono/metadata/loader.h>
26 #include <mono/metadata/tabledefs.h>
27 #include <mono/io-layer/io-layer.h>
28 #include <mono/utils/mono-uri.h>
29 #include <mono/metadata/mono-config.h>
30 #include <mono/utils/mono-digest.h>
32 /* the default search path is just MONO_ASSEMBLIES */
39 static char **assemblies_path = NULL;
42 * keeps track of loaded assemblies
44 static GList *loaded_assemblies = NULL;
45 static MonoAssembly *corlib;
47 /* This protects loaded_assemblies and image->references */
48 static CRITICAL_SECTION assemblies_mutex;
50 /* A hastable of thread->assembly list mappings */
51 static GHashTable *assemblies_loading;
53 static gboolean allow_user_gac = FALSE;
58 init_default_path (void)
62 default_path [0] = g_strdup (MONO_ASSEMBLIES);
63 for (i = strlen (MONO_ASSEMBLIES) - 1; i >= 0; i--) {
64 if (default_path [0][i] == '/')
65 ((char*) default_path [0])[i] = '\\';
72 encode_public_tok (const guchar *token, gint32 len)
74 static gchar allowed [] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
78 res = g_malloc (len * 2 + 1);
79 for (i = 0; i < len; i++) {
80 res [i * 2] = allowed [token [i] >> 4];
81 res [i * 2 + 1] = allowed [token [i] & 0xF];
92 path = getenv ("MONO_PATH");
95 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
97 g_strfreev (assemblies_path);
98 assemblies_path = splitted;
102 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
104 if (!l->name || !r->name)
107 if (strcmp (l->name, r->name))
111 * simply compare names until some other issues are resolved
112 * (version info not getting set correctly for custom
116 if (l->major != r->major || l->minor != r->minor ||
117 l->build != r->build || l->revision != r->revision)
120 if (!l->public_tok_value && !r->public_tok_value)
123 if ((l->public_tok_value && !r->public_tok_value) || (!l->public_tok_value && r->public_tok_value))
126 if (strcmp (l->public_tok_value, r->public_tok_value))
132 /* assemblies_mutex must be held by the caller */
134 search_loaded (MonoAssemblyName* aname)
140 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
142 /* g_print ("compare %s %s\n", aname->name, ass->aname.name); */
143 if (!mono_assembly_names_equal (aname, &ass->aname))
145 /* g_print ("success\n"); */
151 * The assembly might be under load by this thread. In this case, it is
152 * safe to return an incomplete instance to prevent loops.
154 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
155 for (tmp = loading; tmp; tmp = tmp->next) {
157 if (!mono_assembly_names_equal (aname, &ass->aname))
166 static MonoAssembly *
167 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
171 MonoAssembly *result;
173 for (i = 0; search_path [i]; ++i) {
174 fullpath = g_build_filename (search_path [i], basename, NULL);
175 result = mono_assembly_open (fullpath, status);
184 * mono_assembly_setrootdir:
185 * @root_dir: The pathname of the root directory where we will locate assemblies
187 * This routine sets the internal default root directory for looking up
188 * assemblies. This is used by Windows installations to compute dynamically
189 * the place where the Mono assemblies are located.
193 mono_assembly_setrootdir (const char *root_dir)
196 * Override the MONO_ASSEMBLIES directory configured at compile time.
198 /* Leak if called more than once */
199 default_path [0] = g_strdup (root_dir);
203 * mono_assemblies_init:
205 * Initialize global variables used by this module.
208 mono_assemblies_init (void)
210 #ifdef PLATFORM_WIN32
211 init_default_path ();
216 InitializeCriticalSection (&assemblies_mutex);
218 assemblies_loading = g_hash_table_new (NULL, NULL);
222 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
224 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
225 guint32 cols [MONO_ASSEMBLY_SIZE];
230 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
233 aname->hash_value = NULL;
234 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
235 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
236 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
237 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
238 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
239 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
240 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
241 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
242 if (cols [MONO_ASSEMBLY_PUBLIC_KEY])
243 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
245 aname->public_key = 0;
251 assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
253 const gchar *public_tok;
256 public_tok = mono_metadata_blob_heap (image, key_index);
257 len = mono_metadata_decode_blob_size (public_tok, &public_tok);
259 if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
261 mono_digest_get_public_token (token, public_tok, len);
262 return encode_public_tok (token, 8);
265 return encode_public_tok (public_tok, len);
269 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
272 guint32 cols [MONO_ASSEMBLYREF_SIZE];
275 MonoAssembly **references = NULL;
277 *status = MONO_IMAGE_OK;
280 * image->references is shared between threads, so we need to access
281 * it inside a critical section.
283 EnterCriticalSection (&assemblies_mutex);
284 references = image->references;
285 LeaveCriticalSection (&assemblies_mutex);
289 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
291 references = g_new0 (MonoAssembly *, t->rows + 1);
294 * Load any assemblies this image references
296 for (i = 0; i < t->rows; i++) {
297 MonoAssemblyName aname;
299 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
301 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
302 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
303 aname.hash_value = hash;
304 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
305 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
306 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
307 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
308 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
309 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
310 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
312 if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
313 aname.public_tok_value = assemblyref_public_tok (image,
314 cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname.flags);
316 aname.public_tok_value = NULL;
319 references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
321 if (references [i] == NULL){
325 ** Temporary work around: any System.* which are 3300 build, will get
326 ** remapped, this is to keep old applications running that might have
327 ** been linked against our 5000 API, before we were strongnamed, and
328 ** hence were labeled as 3300 builds by reflection.c
330 if (aname.build == 3300 && strncmp (aname.name, "System", 6) == 0){
333 references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
335 if (references [i] != NULL){
336 if (getenv ("MONO_SILENT_WARNING") == NULL)
337 g_printerr ("Compat mode: the request from %s to load %s was remapped (http://www.go-mono.com/remap.html)\n",
338 image->name, aname.name);
342 for (j = 0; j < i; j++)
343 mono_assembly_close (references [j]);
346 g_warning ("Could not find assembly %s, references from %s (assemblyref_index=%d)\n"
347 " Major/Minor: %d,%d\n"
350 aname.name, image->name, i,
351 aname.major, aname.minor, aname.build, aname.revision,
352 aname.public_tok_value);
353 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
359 * This check is disabled since lots of people seem to have an older
360 * corlib which triggers this.
363 if (image->references [i]->image == image)
364 g_error ("Error: Assembly %s references itself", image->name);
367 references [i] = NULL;
369 /* resolve assembly references for modules */
370 t = &image->tables [MONO_TABLE_MODULEREF];
371 for (i = 0; i < t->rows; i++){
372 if (image->modules [i]) {
373 image->modules [i]->assembly = image->assembly;
374 mono_assembly_load_references (image->modules [i], status);
378 EnterCriticalSection (&assemblies_mutex);
379 if (!image->references)
380 image->references = references;
381 LeaveCriticalSection (&assemblies_mutex);
383 if (image->references != references) {
384 /* Somebody loaded it before us */
385 for (i = 0; i < t->rows; i++)
386 mono_assembly_close (references [i]);
391 typedef struct AssemblyLoadHook AssemblyLoadHook;
392 struct AssemblyLoadHook {
393 AssemblyLoadHook *next;
394 MonoAssemblyLoadFunc func;
398 AssemblyLoadHook *assembly_load_hook = NULL;
401 mono_assembly_invoke_load_hook (MonoAssembly *ass)
403 AssemblyLoadHook *hook;
405 for (hook = assembly_load_hook; hook; hook = hook->next) {
406 hook->func (ass, hook->user_data);
411 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
413 AssemblyLoadHook *hook;
415 g_return_if_fail (func != NULL);
417 hook = g_new0 (AssemblyLoadHook, 1);
419 hook->user_data = user_data;
420 hook->next = assembly_load_hook;
421 assembly_load_hook = hook;
424 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
425 struct AssemblyPreLoadHook {
426 AssemblyPreLoadHook *next;
427 MonoAssemblyPreLoadFunc func;
431 AssemblyPreLoadHook *assembly_preload_hook = NULL;
433 static MonoAssembly *
434 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
436 AssemblyPreLoadHook *hook;
437 MonoAssembly *assembly;
439 for (hook = assembly_preload_hook; hook; hook = hook->next) {
440 assembly = hook->func (aname, assemblies_path, hook->user_data);
441 if (assembly != NULL)
449 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
451 AssemblyPreLoadHook *hook;
453 g_return_if_fail (func != NULL);
455 hook = g_new0 (AssemblyPreLoadHook, 1);
457 hook->user_data = user_data;
458 hook->next = assembly_preload_hook;
459 assembly_preload_hook = hook;
463 absolute_dir (const gchar *filename)
474 if (g_path_is_absolute (filename))
475 return g_path_get_dirname (filename);
477 cwd = g_get_current_dir ();
478 mixed = g_build_filename (cwd, filename, NULL);
479 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
484 for (i = 0; (part = parts [i]) != NULL; i++) {
485 if (!strcmp (part, "."))
488 if (!strcmp (part, "..")) {
489 if (list && list->next) /* Don't remove root */
490 list = g_list_delete_link (list, list);
492 list = g_list_prepend (list, part);
496 result = g_string_new ("");
497 list = g_list_reverse (list);
499 /* Ignores last data pointer, which should be the filename */
500 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
502 g_string_append_printf (result, "%s%c", (char *) tmp->data,
506 g_string_free (result, FALSE);
511 return g_strdup (".");
518 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
520 MonoImage *image = NULL;
523 char *name = g_path_get_basename (filename);
524 char *dot = strrchr (name, '.');
530 /* we do a very simple search for bundled assemblies: it's not a general
531 * purpose assembly loading mechanism.
533 EnterCriticalSection (&assemblies_mutex);
534 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
536 if (!ass->aname.name)
538 if (strcmp (name, ass->aname.name))
544 for (i = 0; !image && bundled_assemblies [i]; ++i) {
545 if (strcmp (bundled_assemblies [i]->name, name) == 0) {
546 image = mono_image_open_from_data ((char*)bundled_assemblies [i]->data, bundled_assemblies [i]->size, FALSE, status);
550 LeaveCriticalSection (&assemblies_mutex);
553 mono_image_addref (image);
557 EnterCriticalSection (&assemblies_mutex);
558 image = mono_image_open (filename, status);
559 LeaveCriticalSection (&assemblies_mutex);
565 * mono_assembly_open:
566 * @filename: Opens the assembly pointed out by this name
567 * @status: where a status code can be returned
569 * mono_assembly_open opens the PE-image pointed by @filename, and
570 * loads any external assemblies referenced by it.
572 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
576 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
580 MonoImageOpenStatus def_status;
583 g_return_val_if_fail (filename != NULL, NULL);
586 status = &def_status;
587 *status = MONO_IMAGE_OK;
589 if (strncmp (filename, "file://", 7) == 0) {
590 GError *error = NULL;
591 gchar *uri = (gchar *) filename;
595 * MS allows file://c:/... and fails on file://localhost/c:/...
596 * They also throw an IndexOutOfRangeException if "file://"
599 uri = g_strdup_printf ("file:///%s", uri + 7);
602 uri = mono_escape_uri_string (tmpuri);
603 fname = g_filename_from_uri (uri, NULL, &error);
606 if (tmpuri != filename)
610 g_warning ("%s\n", error->message);
611 g_error_free (error);
612 fname = g_strdup (filename);
615 fname = g_strdup (filename);
618 /* g_print ("file loading %s\n", fname); */
619 image = do_mono_assembly_open (fname, status);
622 *status = MONO_IMAGE_ERROR_ERRNO;
627 ass = mono_assembly_load_from (image, fname, status);
629 mono_config_for_assembly (ass->image);
637 mono_assembly_load_from (MonoImage *image, const char*fname,
638 MonoImageOpenStatus *status)
640 MonoAssembly *ass, *ass2;
644 #if defined (PLATFORM_WIN32)
649 tmp_fn = g_strdup (fname);
650 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
651 if (tmp_fn [i] == '/')
655 base_dir = absolute_dir (tmp_fn);
659 base_dir = absolute_dir (fname);
663 * To avoid deadlocks and scalability problems, we load assemblies outside
664 * the assembly lock. This means that multiple threads might try to load
665 * the same assembly at the same time. The first one to load it completely
666 * "wins", the other threads free their copy and use the one loaded by
667 * the winning thread.
671 * Create assembly struct, and enter it into the assembly cache
673 ass = g_new0 (MonoAssembly, 1);
674 ass->basedir = base_dir;
677 mono_assembly_fill_assembly_name (image, &ass->aname);
680 * Atomically search the loaded list and add ourselves to it if necessary.
682 EnterCriticalSection (&assemblies_mutex);
684 /* avoid loading the same assembly twice for now... */
685 if ((ass2 = search_loaded (&ass->aname))) {
688 mono_image_close (image);
689 *status = MONO_IMAGE_OK;
690 LeaveCriticalSection (&assemblies_mutex);
693 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
694 loading = g_list_prepend (loading, ass);
695 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
696 LeaveCriticalSection (&assemblies_mutex);
698 image->assembly = ass;
701 * We load referenced assemblies outside the lock to prevent deadlocks
702 * with regards to preload hooks.
704 mono_assembly_load_references (image, status);
706 EnterCriticalSection (&assemblies_mutex);
708 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
709 loading = g_list_remove (loading, ass);
711 /* Prevent memory leaks */
712 g_hash_table_remove (assemblies_loading, GetCurrentThread ());
714 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
715 if (*status != MONO_IMAGE_OK) {
716 LeaveCriticalSection (&assemblies_mutex);
717 mono_assembly_close (ass);
721 if (ass->aname.name) {
722 ass2 = search_loaded (&ass->aname);
724 /* Somebody else has loaded the assembly before us */
725 LeaveCriticalSection (&assemblies_mutex);
726 mono_assembly_close (ass);
731 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
732 LeaveCriticalSection (&assemblies_mutex);
734 mono_assembly_invoke_load_hook (ass);
740 * mono_assembly_load_from_gac
742 * @aname: The assembly name object
745 mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImageOpenStatus *status)
747 MonoAssembly *result = NULL;
748 gchar *name, *version, *fullpath;
751 if (!aname->public_tok_value) {
755 if (strstr (aname->name, ".dll")) {
756 len = strlen (filename) - 4;
757 name = g_malloc (len);
758 strncpy (name, aname->name, len);
760 name = g_strdup (aname->name);
763 version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
764 aname->minor, aname->build, aname->revision,
765 aname->culture == NULL ? "" : aname->culture,
766 aname->public_tok_value);
768 fullpath = g_build_path (G_DIR_SEPARATOR_S, MONO_ASSEMBLIES, "mono", "gac",
769 name, version, filename, NULL);
770 result = mono_assembly_open (fullpath, status);
774 if (!result && allow_user_gac) {
775 fullpath = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir (), ".mono", "gac",
776 name, version, filename, NULL);
777 result = mono_assembly_open (fullpath, status);
782 result->in_gac = TRUE;
792 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
794 MonoAssembly *result;
795 char *fullpath, *filename;
797 result = invoke_assembly_preload_hook (aname, assemblies_path);
800 /* g_print ("loading %s\n", aname->name); */
801 /* special case corlib */
802 if (strcmp (aname->name, "mscorlib") == 0) {
804 /* g_print ("corlib already loaded\n"); */
807 /* g_print ("corlib load\n"); */
808 if (assemblies_path) {
809 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status);
813 corlib = load_in_path ("mscorlib.dll", default_path, status);
816 result = search_loaded (aname);
820 /* g_print ("%s not found in cache\n", aname->name); */
821 if (strstr (aname->name, ".dll"))
822 filename = g_strdup (aname->name);
824 filename = g_strconcat (aname->name, ".dll", NULL);
826 result = mono_assembly_load_from_gac (aname, filename, status);
833 fullpath = g_build_filename (basedir, filename, NULL);
834 result = mono_assembly_open (fullpath, status);
837 result->in_gac = FALSE;
842 if (assemblies_path) {
843 result = load_in_path (filename, (const char**)assemblies_path, status);
845 result->in_gac = FALSE;
850 result = load_in_path (filename, default_path, status);
853 result->in_gac = FALSE;
859 mono_assembly_loaded (MonoAssemblyName *aname)
863 EnterCriticalSection (&assemblies_mutex);
864 res = search_loaded (aname);
865 LeaveCriticalSection (&assemblies_mutex);
871 mono_assembly_close (MonoAssembly *assembly)
876 g_return_if_fail (assembly != NULL);
878 EnterCriticalSection (&assemblies_mutex);
879 if (--assembly->ref_count != 0) {
880 LeaveCriticalSection (&assemblies_mutex);
883 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
884 LeaveCriticalSection (&assemblies_mutex);
885 image = assembly->image;
886 if (image->references) {
887 for (i = 0; image->references [i] != NULL; i++)
888 mono_image_close (image->references [i]->image);
889 g_free (image->references);
892 mono_image_close (assembly->image);
894 g_free (assembly->basedir);
899 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
901 MonoImageOpenStatus status;
904 module = mono_image_load_file_for_image (assembly->image, idx);
906 mono_assembly_load_references (module, &status);
912 mono_assembly_foreach (GFunc func, gpointer user_data)
917 * We make a copy of the list to avoid calling the callback inside the
918 * lock, which could lead to deadlocks.
920 EnterCriticalSection (&assemblies_mutex);
921 copy = g_list_copy (loaded_assemblies);
922 LeaveCriticalSection (&assemblies_mutex);
924 g_list_foreach (loaded_assemblies, func, user_data);
929 /* Holds the assembly of the application, for
930 * System.Diagnostics.Process::MainModule
932 static MonoAssembly *main_assembly=NULL;
935 mono_assembly_set_main (MonoAssembly *assembly)
937 main_assembly=assembly;
941 mono_assembly_get_main (void)
943 return(main_assembly);
947 mono_assembly_allow_user_gac (gboolean allow)
949 allow_user_gac = allow;