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/io-layer/io-layer.h>
26 #include <mono/utils/mono-uri.h>
28 /* the default search path is just MONO_ASSEMBLIES */
35 static char **assemblies_path = NULL;
38 * keeps track of loaded assemblies
40 static GList *loaded_assemblies = NULL;
41 static MonoAssembly *corlib;
43 /* This protects loaded_assemblies and image->references */
44 static CRITICAL_SECTION assemblies_mutex;
46 /* A hastable of thread->assembly list mappings */
47 static GHashTable *assemblies_loading;
52 init_default_path (void)
56 default_path [0] = g_strdup (MONO_ASSEMBLIES);
57 for (i = strlen (MONO_ASSEMBLIES) - 1; i >= 0; i--) {
58 if (default_path [0][i] == '/')
59 ((char*) default_path [0])[i] = '\\';
69 path = getenv ("MONO_PATH");
72 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
74 g_strfreev (assemblies_path);
75 assemblies_path = splitted;
78 /* assemblies_mutex must be held by the caller */
80 search_loaded (MonoAssemblyName* aname)
86 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
90 /* we just compare the name, but later we'll do all the checks */
91 /* g_print ("compare %s %s\n", aname->name, ass->aname.name); */
92 if (strcmp (aname->name, ass->aname.name))
94 /* g_print ("success\n"); */
100 * The assembly might be under load by this thread. In this case, it is
101 * safe to return an incomplete instance to prevent loops.
103 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
104 for (tmp = loading; tmp; tmp = tmp->next) {
106 if (!ass->aname.name)
108 if (strcmp (aname->name, ass->aname.name))
117 static MonoAssembly *
118 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
122 MonoAssembly *result;
124 for (i = 0; search_path [i]; ++i) {
125 fullpath = g_build_filename (search_path [i], basename, NULL);
126 result = mono_assembly_open (fullpath, status);
135 * mono_assembly_setrootdir:
136 * @root_dir: The pathname of the root directory where we will locate assemblies
138 * This routine sets the internal default root directory for looking up
139 * assemblies. This is used by Windows installations to compute dynamically
140 * the place where the Mono assemblies are located.
144 mono_assembly_setrootdir (const char *root_dir)
147 * Override the MONO_ASSEMBLIES directory configured at compile time.
149 /* Leak if called more than once */
150 default_path [0] = g_strdup (root_dir);
154 * mono_assemblies_init:
156 * Initialize global variables used by this module.
159 mono_assemblies_init (void)
161 #ifdef PLATFORM_WIN32
162 init_default_path ();
167 InitializeCriticalSection (&assemblies_mutex);
169 assemblies_loading = g_hash_table_new (NULL, NULL);
173 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
175 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
176 guint32 cols [MONO_ASSEMBLY_SIZE];
181 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
184 aname->hash_value = NULL;
185 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
186 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
187 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
188 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
189 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
190 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
191 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
192 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
193 if (cols [MONO_ASSEMBLY_PUBLIC_KEY])
194 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
196 aname->public_key = 0;
202 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
205 guint32 cols [MONO_ASSEMBLYREF_SIZE];
209 *status = MONO_IMAGE_OK;
211 if (image->references)
214 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
216 image->references = g_new0 (MonoAssembly *, t->rows + 1);
219 * Load any assemblies this image references
221 for (i = 0; i < t->rows; i++) {
222 MonoAssemblyName aname;
224 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
226 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
227 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
228 aname.hash_value = hash;
229 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
230 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
231 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
232 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
233 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
234 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
235 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
237 image->references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
239 if (image->references [i] == NULL){
242 for (j = 0; j < i; j++)
243 mono_assembly_close (image->references [j]);
244 g_free (image->references);
246 g_warning ("Could not find assembly %s", aname.name);
247 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
252 * This check is disabled since lots of people seem to have an older
253 * corlib which triggers this.
256 if (image->references [i]->image == image)
257 g_error ("Error: Assembly %s references itself", image->name);
260 image->references [i] = NULL;
262 /* resolve assembly references for modules */
263 t = &image->tables [MONO_TABLE_MODULEREF];
264 for (i = 0; i < t->rows; i++){
265 if (image->modules [i]) {
266 image->modules [i]->assembly = image->assembly;
267 mono_assembly_load_references (image->modules [i], status);
272 typedef struct AssemblyLoadHook AssemblyLoadHook;
273 struct AssemblyLoadHook {
274 AssemblyLoadHook *next;
275 MonoAssemblyLoadFunc func;
279 AssemblyLoadHook *assembly_load_hook = NULL;
282 mono_assembly_invoke_load_hook (MonoAssembly *ass)
284 AssemblyLoadHook *hook;
286 for (hook = assembly_load_hook; hook; hook = hook->next) {
287 hook->func (ass, hook->user_data);
292 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
294 AssemblyLoadHook *hook;
296 g_return_if_fail (func != NULL);
298 hook = g_new0 (AssemblyLoadHook, 1);
300 hook->user_data = user_data;
301 hook->next = assembly_load_hook;
302 assembly_load_hook = hook;
305 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
306 struct AssemblyPreLoadHook {
307 AssemblyPreLoadHook *next;
308 MonoAssemblyPreLoadFunc func;
312 AssemblyPreLoadHook *assembly_preload_hook = NULL;
314 static MonoAssembly *
315 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
317 AssemblyPreLoadHook *hook;
318 MonoAssembly *assembly;
320 for (hook = assembly_preload_hook; hook; hook = hook->next) {
321 assembly = hook->func (aname, assemblies_path, hook->user_data);
322 if (assembly != NULL)
330 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
332 AssemblyPreLoadHook *hook;
334 g_return_if_fail (func != NULL);
336 hook = g_new0 (AssemblyPreLoadHook, 1);
338 hook->user_data = user_data;
339 hook->next = assembly_preload_hook;
340 assembly_preload_hook = hook;
344 absolute_dir (const gchar *filename)
355 if (g_path_is_absolute (filename))
356 return g_path_get_dirname (filename);
358 cwd = g_get_current_dir ();
359 mixed = g_build_filename (cwd, filename, NULL);
360 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
365 for (i = 0; (part = parts [i]) != NULL; i++) {
366 if (!strcmp (part, "."))
369 if (!strcmp (part, "..")) {
370 if (list && list->next) /* Don't remove root */
371 list = g_list_delete_link (list, list);
373 list = g_list_prepend (list, part);
377 result = g_string_new ("");
378 list = g_list_reverse (list);
380 /* Ignores last data pointer, which should be the filename */
381 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
383 g_string_append_printf (result, "%s%c", (char *) tmp->data,
387 g_string_free (result, FALSE);
392 return g_strdup (".");
399 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
401 MonoImage *image = NULL;
404 char *name = g_path_get_basename (filename);
405 char *dot = strrchr (name, '.');
411 if (strcmp (name, "corlib") == 0) {
413 name = g_strdup ("mscorlib");
415 /* we do a very simple search for bundled assemblies: it's not a general
416 * purpose assembly loading mechanism.
418 EnterCriticalSection (&assemblies_mutex);
419 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
421 if (!ass->aname.name)
423 if (strcmp (name, ass->aname.name))
428 LeaveCriticalSection (&assemblies_mutex);
429 for (i = 0; !image && bundled_assemblies [i]; ++i) {
430 if (strcmp (bundled_assemblies [i]->name, name) == 0) {
431 image = mono_image_open_from_data ((char*)bundled_assemblies [i]->data, bundled_assemblies [i]->size, FALSE, status);
437 InterlockedIncrement (&image->ref_count);
441 image = mono_image_open (filename, status);
446 * mono_assembly_open:
447 * @filename: Opens the assembly pointed out by this name
448 * @status: where a status code can be returned
450 * mono_assembly_open opens the PE-image pointed by @filename, and
451 * loads any external assemblies referenced by it.
453 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
457 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
461 MonoImageOpenStatus def_status;
464 g_return_val_if_fail (filename != NULL, NULL);
467 status = &def_status;
468 *status = MONO_IMAGE_OK;
470 if (strncmp (filename, "file://", 7) == 0) {
471 GError *error = NULL;
472 gchar *uri = (gchar *) filename;
476 * MS allows file://c:/... and fails on file://localhost/c:/...
477 * They also throw an IndexOutOfRangeException if "file://"
480 uri = g_strdup_printf ("file:///%s", uri + 7);
483 uri = mono_escape_uri_string (tmpuri);
484 fname = g_filename_from_uri (uri, NULL, &error);
487 if (tmpuri != filename)
491 g_warning ("%s\n", error->message);
492 g_error_free (error);
493 fname = g_strdup (filename);
496 fname = g_strdup (filename);
499 /* g_print ("file loading %s\n", fname); */
500 image = do_mono_assembly_open (fname, status);
503 *status = MONO_IMAGE_ERROR_ERRNO;
508 ass = mono_assembly_load_from (image, fname, status);
516 mono_assembly_load_from (MonoImage *image, const char*fname,
517 MonoImageOpenStatus *status)
519 MonoAssembly *ass, *ass2;
523 #if defined (PLATFORM_WIN32)
528 tmp_fn = g_strdup (fname);
529 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
530 if (tmp_fn [i] == '/')
534 base_dir = absolute_dir (tmp_fn);
538 base_dir = absolute_dir (fname);
542 * Create assembly struct, and enter it into the assembly cache
544 ass = g_new0 (MonoAssembly, 1);
545 ass->basedir = base_dir;
548 mono_assembly_fill_assembly_name (image, &ass->aname);
551 * Atomically search the loaded list and add ourselves to it if necessary.
553 EnterCriticalSection (&assemblies_mutex);
555 /* avoid loading the same assembly twice for now... */
556 if ((ass2 = search_loaded (&ass->aname))) {
559 mono_image_close (image);
560 *status = MONO_IMAGE_OK;
561 LeaveCriticalSection (&assemblies_mutex);
564 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
565 loading = g_list_prepend (loading, ass);
566 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
567 LeaveCriticalSection (&assemblies_mutex);
569 image->assembly = ass;
572 * We load referenced assemblies outside the lock to prevent deadlocks
573 * with regards to preload hooks.
575 mono_assembly_load_references (image, status);
577 EnterCriticalSection (&assemblies_mutex);
579 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
580 loading = g_list_remove (loading, ass);
582 /* Prevent memory leaks */
583 g_hash_table_remove (assemblies_loading, GetCurrentThread ());
585 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
586 if (*status != MONO_IMAGE_OK) {
587 LeaveCriticalSection (&assemblies_mutex);
588 mono_assembly_close (ass);
592 if (ass->aname.name) {
593 ass2 = search_loaded (&ass->aname);
595 /* Somebody else has loaded the assembly before us */
596 LeaveCriticalSection (&assemblies_mutex);
597 mono_assembly_close (ass);
602 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
603 LeaveCriticalSection (&assemblies_mutex);
605 mono_assembly_invoke_load_hook (ass);
611 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
613 MonoAssembly *result;
614 char *fullpath, *filename;
616 result = invoke_assembly_preload_hook (aname, assemblies_path);
620 /* g_print ("loading %s\n", aname->name); */
621 /* special case corlib */
622 if ((strcmp (aname->name, "mscorlib") == 0) || (strcmp (aname->name, "corlib") == 0)) {
624 /* g_print ("corlib already loaded\n"); */
627 /* g_print ("corlib load\n"); */
628 if (assemblies_path) {
629 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status);
632 corlib = load_in_path ("corlib.dll", (const char**)assemblies_path, status);
636 corlib = load_in_path ("mscorlib.dll", default_path, status);
638 corlib = load_in_path ("corlib.dll", default_path, status);
641 result = search_loaded (aname);
644 /* g_print ("%s not found in cache\n", aname->name); */
645 if (strstr (aname->name, ".dll"))
646 filename = g_strdup (aname->name);
648 filename = g_strconcat (aname->name, ".dll", NULL);
650 fullpath = g_build_filename (basedir, filename, NULL);
651 result = mono_assembly_open (fullpath, status);
658 if (assemblies_path) {
659 result = load_in_path (filename, (const char**)assemblies_path, status);
665 result = load_in_path (filename, default_path, status);
671 mono_assembly_loaded (MonoAssemblyName *aname)
675 EnterCriticalSection (&assemblies_mutex);
676 res = search_loaded (aname);
677 LeaveCriticalSection (&assemblies_mutex);
683 mono_assembly_close (MonoAssembly *assembly)
688 g_return_if_fail (assembly != NULL);
690 EnterCriticalSection (&assemblies_mutex);
691 if (--assembly->ref_count != 0) {
692 LeaveCriticalSection (&assemblies_mutex);
695 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
696 LeaveCriticalSection (&assemblies_mutex);
697 image = assembly->image;
698 if (image->references) {
699 for (i = 0; image->references [i] != NULL; i++)
700 mono_image_close (image->references [i]->image);
701 g_free (image->references);
704 mono_image_close (assembly->image);
706 g_free (assembly->basedir);
711 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
713 MonoImageOpenStatus status;
716 module = mono_image_load_file_for_image (assembly->image, idx);
718 mono_assembly_load_references (module, &status);
724 mono_assembly_foreach (GFunc func, gpointer user_data)
729 * We make a copy of the list to avoid calling the callback inside the
730 * lock, which could lead to deadlocks.
732 EnterCriticalSection (&assemblies_mutex);
733 copy = g_list_copy (loaded_assemblies);
734 LeaveCriticalSection (&assemblies_mutex);
736 g_list_foreach (loaded_assemblies, func, user_data);
741 /* Holds the assembly of the application, for
742 * System.Diagnostics.Process::MainModule
744 static MonoAssembly *main_assembly=NULL;
747 mono_assembly_set_main (MonoAssembly *assembly)
749 main_assembly=assembly;
753 mono_assembly_get_main (void)
755 return(main_assembly);