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>
27 /* the default search path is just MONO_ASSEMBLIES */
34 static char **assemblies_path = NULL;
37 * keeps track of loaded assemblies
39 static GList *loaded_assemblies = NULL;
40 static MonoAssembly *corlib;
42 /* This protects loaded_assemblies and image->references */
43 static CRITICAL_SECTION assemblies_mutex;
45 /* A hastable of thread->assembly list mappings */
46 static GHashTable *assemblies_loading;
51 init_default_path (void)
55 default_path [0] = g_strdup (MONO_ASSEMBLIES);
56 for (i = strlen (MONO_ASSEMBLIES) - 1; i >= 0; i--) {
57 if (default_path [0][i] == '/')
58 ((char*) default_path [0])[i] = '\\';
68 path = getenv ("MONO_PATH");
71 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
73 g_strfreev (assemblies_path);
74 assemblies_path = splitted;
77 /* assemblies_mutex must be held by the caller */
79 search_loaded (MonoAssemblyName* aname)
85 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
89 /* we just compare the name, but later we'll do all the checks */
90 /* g_print ("compare %s %s\n", aname->name, ass->aname.name); */
91 if (strcmp (aname->name, ass->aname.name))
93 /* g_print ("success\n"); */
99 * The assembly might be under load by this thread. In this case, it is
100 * safe to return an incomplete instance to prevent loops.
102 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
103 for (tmp = loading; tmp; tmp = tmp->next) {
105 if (!ass->aname.name)
107 if (strcmp (aname->name, ass->aname.name))
116 static MonoAssembly *
117 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
121 MonoAssembly *result;
123 for (i = 0; search_path [i]; ++i) {
124 fullpath = g_build_filename (search_path [i], basename, NULL);
125 result = mono_assembly_open (fullpath, status);
134 * mono_assembly_setrootdir:
135 * @root_dir: The pathname of the root directory where we will locate assemblies
137 * This routine sets the internal default root directory for looking up
138 * assemblies. This is used by Windows installations to compute dynamically
139 * the place where the Mono assemblies are located.
143 mono_assembly_setrootdir (const char *root_dir)
146 * Override the MONO_ASSEMBLIES directory configured at compile time.
148 /* Leak if called more than once */
149 default_path [0] = g_strdup (root_dir);
153 * mono_assemblies_init:
155 * Initialize global variables used by this module.
158 mono_assemblies_init (void)
160 #ifdef PLATFORM_WIN32
161 init_default_path ();
166 InitializeCriticalSection (&assemblies_mutex);
168 assemblies_loading = g_hash_table_new (NULL, NULL);
172 mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
174 MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
175 guint32 cols [MONO_ASSEMBLY_SIZE];
180 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
183 aname->hash_value = NULL;
184 aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
185 aname->culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
186 aname->flags = cols [MONO_ASSEMBLY_FLAGS];
187 aname->major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
188 aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
189 aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
190 aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
191 aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
192 if (cols [MONO_ASSEMBLY_PUBLIC_KEY])
193 aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
195 aname->public_key = 0;
201 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
204 guint32 cols [MONO_ASSEMBLYREF_SIZE];
208 *status = MONO_IMAGE_OK;
210 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
212 image->references = g_new0 (MonoAssembly *, t->rows + 1);
215 * Load any assemblies this image references
217 for (i = 0; i < t->rows; i++) {
218 MonoAssemblyName aname;
220 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
222 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
223 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
224 aname.hash_value = hash;
225 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
226 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
227 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
228 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
229 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
230 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
231 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
233 image->references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
235 if (image->references [i] == NULL){
238 for (j = 0; j < i; j++)
239 mono_assembly_close (image->references [j]);
240 g_free (image->references);
242 g_warning ("Could not find assembly %s", aname.name);
243 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
248 * This check is disabled since lots of people seem to have an older
249 * corlib which triggers this.
252 if (image->references [i]->image == image)
253 g_error ("Error: Assembly %s references itself", image->name);
256 image->references [i] = NULL;
258 /* resolve assembly references for modules */
259 t = &image->tables [MONO_TABLE_MODULEREF];
260 for (i = 0; i < t->rows; i++){
261 if (image->modules [i]) {
262 image->modules [i]->assembly = image->assembly;
263 mono_assembly_load_references (image->modules [i], status);
268 typedef struct AssemblyLoadHook AssemblyLoadHook;
269 struct AssemblyLoadHook {
270 AssemblyLoadHook *next;
271 MonoAssemblyLoadFunc func;
275 AssemblyLoadHook *assembly_load_hook = NULL;
278 mono_assembly_invoke_load_hook (MonoAssembly *ass)
280 AssemblyLoadHook *hook;
282 for (hook = assembly_load_hook; hook; hook = hook->next) {
283 hook->func (ass, hook->user_data);
288 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
290 AssemblyLoadHook *hook;
292 g_return_if_fail (func != NULL);
294 hook = g_new0 (AssemblyLoadHook, 1);
296 hook->user_data = user_data;
297 hook->next = assembly_load_hook;
298 assembly_load_hook = hook;
301 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
302 struct AssemblyPreLoadHook {
303 AssemblyPreLoadHook *next;
304 MonoAssemblyPreLoadFunc func;
308 AssemblyPreLoadHook *assembly_preload_hook = NULL;
310 static MonoAssembly *
311 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
313 AssemblyPreLoadHook *hook;
314 MonoAssembly *assembly;
316 for (hook = assembly_preload_hook; hook; hook = hook->next) {
317 assembly = hook->func (aname, assemblies_path, hook->user_data);
318 if (assembly != NULL)
326 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
328 AssemblyPreLoadHook *hook;
330 g_return_if_fail (func != NULL);
332 hook = g_new0 (AssemblyPreLoadHook, 1);
334 hook->user_data = user_data;
335 hook->next = assembly_preload_hook;
336 assembly_preload_hook = hook;
340 absolute_dir (const gchar *filename)
351 if (g_path_is_absolute (filename))
352 return g_path_get_dirname (filename);
354 cwd = g_get_current_dir ();
355 mixed = g_build_filename (cwd, filename, NULL);
356 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
361 for (i = 0; (part = parts [i]) != NULL; i++) {
362 if (!strcmp (part, "."))
365 if (!strcmp (part, "..")) {
366 if (list && list->next) /* Don't remove root */
367 list = g_list_delete_link (list, list);
369 list = g_list_prepend (list, part);
373 result = g_string_new ("");
374 list = g_list_reverse (list);
376 /* Ignores last data pointer, which should be the filename */
377 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
379 g_string_append_printf (result, "%s%c", (char *) tmp->data,
383 g_string_free (result, FALSE);
388 return g_strdup (".");
395 do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
397 MonoImage *image = NULL;
400 char *name = g_path_get_basename (filename);
401 char *dot = strrchr (name, '.');
407 if (strcmp (name, "corlib") == 0) {
409 name = g_strdup ("mscorlib");
411 /* we do a very simple search for bundled assemblies: it's not a general
412 * purpose assembly loading mechanism.
414 EnterCriticalSection (&assemblies_mutex);
415 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
417 if (!ass->aname.name)
419 if (strcmp (name, ass->aname.name))
424 LeaveCriticalSection (&assemblies_mutex);
425 for (i = 0; !image && bundled_assemblies [i]; ++i) {
426 if (strcmp (bundled_assemblies [i]->name, name) == 0) {
427 image = mono_image_open_from_data ((char*)bundled_assemblies [i]->data, bundled_assemblies [i]->size, FALSE, status);
433 InterlockedIncrement (&image->ref_count);
437 image = mono_image_open (filename, status);
442 * mono_assembly_open:
443 * @filename: Opens the assembly pointed out by this name
444 * @status: where a status code can be returned
446 * mono_assembly_open opens the PE-image pointed by @filename, and
447 * loads any external assemblies referenced by it.
449 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
453 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
455 MonoAssembly *ass, *ass2;
458 MonoImageOpenStatus def_status;
462 g_return_val_if_fail (filename != NULL, NULL);
465 status = &def_status;
466 *status = MONO_IMAGE_OK;
468 if (strncmp (filename, "file://", 7) == 0) {
469 GError *error = NULL;
470 gchar *uri = (gchar *) filename;
473 * MS allows file://c:/... and fails on file://localhost/c:/...
474 * They also throw an IndexOutOfRangeException if "file://"
477 uri = g_strdup_printf ("file:///%s", uri + 7);
479 fname = g_filename_from_uri (uri, NULL, &error);
484 g_warning ("%s\n", error->message);
485 g_error_free (error);
486 fname = g_strdup (filename);
489 fname = g_strdup (filename);
492 /* g_print ("file loading %s\n", fname); */
493 image = do_mono_assembly_open (fname, status);
496 *status = MONO_IMAGE_ERROR_ERRNO;
501 #if defined (PLATFORM_WIN32)
506 tmp_fn = g_strdup (fname);
507 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
508 if (tmp_fn [i] == '/')
512 base_dir = absolute_dir (tmp_fn);
516 base_dir = absolute_dir (fname);
520 * Create assembly struct, and enter it into the assembly cache
522 ass = g_new0 (MonoAssembly, 1);
523 ass->basedir = base_dir;
529 mono_assembly_fill_assembly_name (image, &ass->aname);
532 * Atomically search the loaded list and add ourselves to it if necessary.
534 EnterCriticalSection (&assemblies_mutex);
536 /* avoid loading the same assembly twice for now... */
537 if ((ass2 = search_loaded (&ass->aname))) {
540 mono_image_close (image);
541 *status = MONO_IMAGE_OK;
542 LeaveCriticalSection (&assemblies_mutex);
545 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
546 loading = g_list_prepend (loading, ass);
547 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
548 LeaveCriticalSection (&assemblies_mutex);
550 image->assembly = ass;
553 * We load referenced assemblies outside the lock to prevent deadlocks
554 * with regards to preload hooks.
556 mono_assembly_load_references (image, status);
558 EnterCriticalSection (&assemblies_mutex);
560 loading = g_hash_table_lookup (assemblies_loading, GetCurrentThread ());
561 loading = g_list_remove (loading, ass);
563 /* Prevent memory leaks */
564 g_hash_table_remove (assemblies_loading, GetCurrentThread ());
566 g_hash_table_insert (assemblies_loading, GetCurrentThread (), loading);
567 if (*status != MONO_IMAGE_OK) {
568 LeaveCriticalSection (&assemblies_mutex);
569 mono_assembly_close (ass);
573 if (ass->aname.name) {
574 ass2 = search_loaded (&ass->aname);
576 /* Somebody else has loaded the assembly before us */
577 LeaveCriticalSection (&assemblies_mutex);
578 mono_assembly_close (ass);
583 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
584 LeaveCriticalSection (&assemblies_mutex);
586 mono_assembly_invoke_load_hook (ass);
592 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
594 MonoAssembly *result;
595 char *fullpath, *filename;
597 result = invoke_assembly_preload_hook (aname, assemblies_path);
601 /* g_print ("loading %s\n", aname->name); */
602 /* special case corlib */
603 if ((strcmp (aname->name, "mscorlib") == 0) || (strcmp (aname->name, "corlib") == 0)) {
605 /* g_print ("corlib already loaded\n"); */
608 /* g_print ("corlib load\n"); */
609 if (assemblies_path) {
610 corlib = load_in_path ("mscorlib.dll", (const char**)assemblies_path, status);
613 corlib = load_in_path ("corlib.dll", (const char**)assemblies_path, status);
617 corlib = load_in_path ("mscorlib.dll", default_path, status);
619 corlib = load_in_path ("corlib.dll", default_path, status);
622 result = search_loaded (aname);
625 /* g_print ("%s not found in cache\n", aname->name); */
626 if (strstr (aname->name, ".dll"))
627 filename = g_strdup (aname->name);
629 filename = g_strconcat (aname->name, ".dll", NULL);
631 fullpath = g_build_filename (basedir, filename, NULL);
632 result = mono_assembly_open (fullpath, status);
639 if (assemblies_path) {
640 result = load_in_path (filename, (const char**)assemblies_path, status);
646 result = load_in_path (filename, default_path, status);
652 mono_assembly_close (MonoAssembly *assembly)
657 g_return_if_fail (assembly != NULL);
659 EnterCriticalSection (&assemblies_mutex);
660 if (--assembly->ref_count != 0) {
661 LeaveCriticalSection (&assemblies_mutex);
664 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
665 LeaveCriticalSection (&assemblies_mutex);
666 image = assembly->image;
667 if (image->references) {
668 for (i = 0; image->references [i] != NULL; i++)
669 mono_image_close (image->references [i]->image);
670 g_free (image->references);
673 mono_image_close (assembly->image);
675 g_free (assembly->basedir);
680 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
682 MonoImageOpenStatus status;
685 module = mono_image_load_file_for_image (assembly->image, idx);
687 mono_assembly_load_references (module, &status);
693 mono_assembly_foreach (GFunc func, gpointer user_data)
698 * We make a copy of the list to avoid calling the callback inside the
699 * lock, which could lead to deadlocks.
701 EnterCriticalSection (&assemblies_mutex);
702 copy = g_list_copy (loaded_assemblies);
703 LeaveCriticalSection (&assemblies_mutex);
705 g_list_foreach (loaded_assemblies, func, user_data);
710 /* Holds the assembly of the application, for
711 * System.Diagnostics.Process::MainModule
713 static MonoAssembly *main_assembly=NULL;
716 mono_assembly_set_main (MonoAssembly *assembly)
718 main_assembly=assembly;
722 mono_assembly_get_main (void)
724 return(main_assembly);