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 /* the default search path is just MONO_ASSEMBLIES */
30 static char **assemblies_path = NULL;
31 static int env_checked = 0;
42 path = getenv ("MONO_PATH");
45 splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
47 g_strfreev (assemblies_path);
48 assemblies_path = splitted;
52 * keeps track of loaded assemblies
54 static GList *loaded_assemblies = NULL;
55 static MonoAssembly *corlib;
58 search_loaded (MonoAssemblyName* aname)
63 for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
65 /* we just compare the name, but later we'll do all the checks */
66 /* g_print ("compare %s %s\n", aname->name, ass->aname.name); */
67 if (strcmp (aname->name, ass->aname.name))
69 /* g_print ("success\n"); */
76 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
82 for (i = 0; search_path [i]; ++i) {
83 fullpath = g_build_filename (search_path [i], basename, NULL);
84 result = mono_assembly_open (fullpath, status);
93 * mono_assembly_setrootdir:
94 * @root_dir: The pathname of the root directory where we will locate assemblies
96 * This routine sets the internal default root directory for looking up
97 * assemblies. This is used by Windows installations to compute dynamically
98 * the place where the Mono assemblies are located.
102 mono_assembly_setrootdir (const char *root_dir)
105 * Override the MONO_ASSEMBLIES directory configured at compile time.
107 default_path [0] = g_strdup (root_dir);
111 load_references (MonoImage *image, MonoImageOpenStatus *status) {
113 guint32 cols [MONO_ASSEMBLYREF_SIZE];
117 if (image->references)
120 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
122 image->references = g_new0 (MonoAssembly *, t->rows + 1);
125 * Load any assemblies this image references
127 for (i = 0; i < t->rows; i++) {
128 MonoAssemblyName aname;
130 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
132 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
133 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
134 aname.hash_value = hash;
135 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
136 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
137 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
138 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
139 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
140 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
141 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
143 image->references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
145 if (image->references [i] == NULL){
148 for (j = 0; j < i; j++)
149 mono_assembly_close (image->references [j]);
150 g_free (image->references);
151 image->references = NULL;
153 g_warning ("Could not find assembly %s", aname.name);
154 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
158 image->references [i] = NULL;
162 typedef struct AssemblyLoadHook AssemblyLoadHook;
163 struct AssemblyLoadHook {
164 AssemblyLoadHook *next;
165 MonoAssemblyLoadFunc func;
169 AssemblyLoadHook *assembly_load_hook = NULL;
172 mono_assembly_invoke_load_hook (MonoAssembly *ass)
174 AssemblyLoadHook *hook;
176 for (hook = assembly_load_hook; hook; hook = hook->next) {
177 hook->func (ass, hook->user_data);
182 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
184 AssemblyLoadHook *hook;
186 g_return_if_fail (func != NULL);
188 hook = g_new0 (AssemblyLoadHook, 1);
190 hook->user_data = user_data;
191 hook->next = assembly_load_hook;
192 assembly_load_hook = hook;
195 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
196 struct AssemblyPreLoadHook {
197 AssemblyPreLoadHook *next;
198 MonoAssemblyPreLoadFunc func;
202 AssemblyPreLoadHook *assembly_preload_hook = NULL;
204 static MonoAssembly *
205 invoke_assembly_preload_hook (MonoAssemblyName *aname, gchar **assemblies_path)
207 AssemblyPreLoadHook *hook;
208 MonoAssembly *assembly;
210 for (hook = assembly_preload_hook; hook; hook = hook->next) {
211 assembly = hook->func (aname, assemblies_path, hook->user_data);
212 if (assembly != NULL)
220 mono_install_assembly_preload_hook (MonoAssemblyPreLoadFunc func, gpointer user_data)
222 AssemblyPreLoadHook *hook;
224 g_return_if_fail (func != NULL);
226 hook = g_new0 (AssemblyPreLoadHook, 1);
228 hook->user_data = user_data;
229 hook->next = assembly_preload_hook;
230 assembly_preload_hook = hook;
234 absolute_dir (const gchar *filename)
245 if (g_path_is_absolute (filename))
246 return g_path_get_dirname (filename);
248 cwd = g_get_current_dir ();
249 mixed = g_build_filename (cwd, filename, NULL);
250 parts = g_strsplit (mixed, G_DIR_SEPARATOR_S, 0);
255 for (i = 0; (part = parts [i]) != NULL; i++) {
256 if (!strcmp (part, "."))
259 if (!strcmp (part, "..")) {
260 if (list && list->next) /* Don't remove root */
261 list = g_slist_delete_link (list, list);
263 list = g_slist_prepend (list, part);
267 result = g_string_new ("");
268 list = g_slist_reverse (list);
270 /* Ignores last data pointer, which should be the filename */
271 for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
273 g_string_append_printf (result, "%s%c", (char *) tmp->data,
277 g_string_free (result, FALSE);
282 return g_strdup (".");
289 * mono_assembly_open:
290 * @filename: Opens the assembly pointed out by this name
291 * @status: where a status code can be returned
293 * mono_assembly_open opens the PE-image pointed by @filename, and
294 * loads any external assemblies referenced by it.
296 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
300 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
302 MonoAssembly *ass, *ass2;
305 guint32 cols [MONO_ASSEMBLY_SIZE];
307 char *base_dir, *aot_name;
308 MonoImageOpenStatus def_status;
310 g_return_val_if_fail (filename != NULL, NULL);
313 status = &def_status;
314 *status = MONO_IMAGE_OK;
316 /* g_print ("file loading %s\n", filename); */
317 image = mono_image_open (filename, status);
320 *status = MONO_IMAGE_ERROR_ERRNO;
324 #if defined (PLATFORM_WIN32)
327 tmp_fn = g_strdup (filename);
328 for (i = strlen (tmp_fn) - 1; i >= 0; i--) {
329 if (tmp_fn [i] == '/')
333 base_dir = absolute_dir (tmp_fn);
337 base_dir = absolute_dir (filename);
341 * Create assembly struct, and enter it into the assembly cache
343 ass = g_new0 (MonoAssembly, 1);
344 ass->basedir = base_dir;
347 /* load aot compiled module */
348 aot_name = g_strdup_printf ("%s.so", filename);
349 ass->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
352 if (ass->aot_module) {
353 char *saved_guid = NULL;
354 g_module_symbol (ass->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
356 if (!saved_guid || strcmp (image->guid, saved_guid)) {
357 g_module_close (ass->aot_module);
358 ass->aot_module = NULL;
362 t = &image->tables [MONO_TABLE_ASSEMBLY];
364 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
366 ass->aname.hash_len = 0;
367 ass->aname.hash_value = NULL;
368 ass->aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
369 ass->aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
370 ass->aname.flags = cols [MONO_ASSEMBLY_FLAGS];
371 ass->aname.major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
372 ass->aname.minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
373 ass->aname.build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
374 ass->aname.revision = cols [MONO_ASSEMBLY_REV_NUMBER];
376 /* avoid loading the same assembly twice for now... */
377 if ((ass2 = search_loaded (&ass->aname))) {
380 *status = MONO_IMAGE_OK;
385 image->assembly = ass;
387 /* register right away to prevent loops */
388 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
390 load_references (image, status);
391 if (*status != MONO_IMAGE_OK) {
392 mono_assembly_close (ass);
396 /* resolve assembly references for modules */
397 t = &image->tables [MONO_TABLE_MODULEREF];
398 for (i = 0; i < t->rows; i++){
399 if (image->modules [i]) {
400 image->modules [i]->assembly = ass;
401 load_references (image->modules [i], status);
404 * FIXME: what do we do here? it could be a native dll...
405 * We should probably do lazy-loading of modules.
407 *status = MONO_IMAGE_OK;
410 mono_assembly_invoke_load_hook (ass);
416 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
418 MonoAssembly *result;
419 char *fullpath, *filename;
423 result = invoke_assembly_preload_hook (aname, assemblies_path);
427 /* g_print ("loading %s\n", aname->name); */
428 /* special case corlib */
429 if ((strcmp (aname->name, "mscorlib") == 0) || (strcmp (aname->name, "corlib") == 0)) {
431 /* g_print ("corlib already loaded\n"); */
434 /* g_print ("corlib load\n"); */
435 if (assemblies_path) {
436 corlib = load_in_path (CORLIB_NAME, (const char**)assemblies_path, status);
440 corlib = load_in_path (CORLIB_NAME, default_path, status);
443 result = search_loaded (aname);
446 /* g_print ("%s not found in cache\n", aname->name); */
447 if (strstr (aname->name, ".dll"))
448 filename = g_strdup (aname->name);
450 filename = g_strconcat (aname->name, ".dll", NULL);
452 fullpath = g_build_filename (basedir, filename, NULL);
453 result = mono_assembly_open (fullpath, status);
460 if (assemblies_path) {
461 result = load_in_path (filename, (const char**)assemblies_path, status);
467 result = load_in_path (filename, default_path, status);
473 mono_assembly_close (MonoAssembly *assembly)
478 g_return_if_fail (assembly != NULL);
480 if (--assembly->ref_count != 0)
483 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
484 image = assembly->image;
485 if (image->references) {
486 for (i = 0; image->references [i] != NULL; i++)
487 mono_image_close (image->references [i]->image);
488 g_free (image->references);
491 mono_image_close (assembly->image);
493 g_free (assembly->basedir);
498 mono_assembly_foreach (GFunc func, gpointer user_data)
500 /* In the future this can do locking of loaded_assemblies */
502 g_list_foreach (loaded_assemblies, func, user_data);
505 /* Holds the assembly of the application, for
506 * System.Diagnostics.Process::MainModule
508 static MonoAssembly *main_assembly=NULL;
511 mono_assembly_set_main (MonoAssembly *assembly)
513 main_assembly=assembly;
517 mono_assembly_get_main (void)
519 return(main_assembly);