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 * g_concat_dir_and_file:
77 * @dir: directory name
80 * returns a new allocated string that is the concatenation of dir and file,
81 * takes care of the exact details for concatenating them.
84 g_concat_dir_and_file (const char *dir, const char *file)
86 g_return_val_if_fail (dir != NULL, NULL);
87 g_return_val_if_fail (file != NULL, NULL);
90 * If the directory name doesn't have a / on the end, we need
91 * to add one so we get a proper path to the file
93 if (dir [strlen(dir) - 1] != G_DIR_SEPARATOR)
94 return g_strconcat (dir, G_DIR_SEPARATOR_S, file, NULL);
96 return g_strconcat (dir, file, NULL);
100 load_in_path (const char *basename, const char** search_path, MonoImageOpenStatus *status)
104 MonoAssembly *result;
106 for (i = 0; search_path [i]; ++i) {
107 fullpath = g_concat_dir_and_file (search_path [i], basename);
108 result = mono_assembly_open (fullpath, status);
117 * mono_assembly_setrootdir:
118 * @root_dir: The pathname of the root directory where we will locate assemblies
120 * This routine sets the internal default root directory for looking up
121 * assemblies. This is used by Windows installations to compute dynamically
122 * the place where the Mono assemblies are located.
126 mono_assembly_setrootdir (const char *root_dir)
129 * Override the MONO_ASSEMBLIES directory configured at compile time.
131 default_path [0] = g_strdup (root_dir);
135 load_references (MonoImage *image, MonoImageOpenStatus *status) {
137 guint32 cols [MONO_ASSEMBLYREF_SIZE];
141 if (image->references)
144 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
146 image->references = g_new0 (MonoAssembly *, t->rows + 1);
149 * Load any assemblies this image references
151 for (i = 0; i < t->rows; i++) {
152 MonoAssemblyName aname;
154 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
156 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
157 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
158 aname.hash_value = hash;
159 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
160 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
161 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
162 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
163 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
164 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
165 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
167 image->references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
169 if (image->references [i] == NULL){
172 for (j = 0; j < i; j++)
173 mono_assembly_close (image->references [j]);
174 g_free (image->references);
175 image->references = NULL;
177 g_warning ("Could not find assembly %s", aname.name);
178 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
182 image->references [i] = NULL;
186 typedef struct AssemblyLoadHook AssemblyLoadHook;
187 struct AssemblyLoadHook {
188 AssemblyLoadHook *next;
189 MonoAssemblyLoadFunc func;
193 AssemblyLoadHook *assembly_load_hook = NULL;
196 invoke_assembly_hook (MonoAssembly *ass)
198 AssemblyLoadHook *hook;
200 for (hook = assembly_load_hook; hook; hook = hook->next) {
201 hook->func (ass, hook->user_data);
206 mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
208 AssemblyLoadHook *hook;
210 g_return_if_fail (func != NULL);
212 hook = g_new0 (AssemblyLoadHook, 1);
214 hook->user_data = user_data;
215 hook->next = assembly_load_hook;
216 assembly_load_hook = hook;
220 * mono_assembly_open:
221 * @filename: Opens the assembly pointed out by this name
222 * @status: where a status code can be returned
224 * mono_assembly_open opens the PE-image pointed by @filename, and
225 * loads any external assemblies referenced by it.
227 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
231 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
233 MonoAssembly *ass, *ass2;
236 guint32 cols [MONO_ASSEMBLY_SIZE];
239 MonoImageOpenStatus def_status;
241 g_return_val_if_fail (filename != NULL, NULL);
244 status = &def_status;
245 *status = MONO_IMAGE_OK;
247 /* g_print ("file loading %s\n", filename); */
248 image = mono_image_open (filename, status);
251 *status = MONO_IMAGE_ERROR_ERRNO;
255 base_dir = g_path_get_dirname (filename);
258 * Create assembly struct, and enter it into the assembly cache
260 ass = g_new0 (MonoAssembly, 1);
261 ass->basedir = base_dir;
264 t = &image->tables [MONO_TABLE_ASSEMBLY];
266 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
268 ass->aname.hash_len = 0;
269 ass->aname.hash_value = NULL;
270 ass->aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
271 ass->aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
272 ass->aname.flags = cols [MONO_ASSEMBLY_FLAGS];
273 ass->aname.major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
274 ass->aname.minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
275 ass->aname.build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
276 ass->aname.revision = cols [MONO_ASSEMBLY_REV_NUMBER];
278 /* avoid loading the same assembly twixe for now... */
279 if ((ass2 = search_loaded (&ass->aname))) {
282 *status = MONO_IMAGE_OK;
287 image->assembly = ass;
289 /* register right away to prevent loops */
290 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
292 load_references (image, status);
293 if (*status != MONO_IMAGE_OK) {
294 mono_assembly_close (ass);
298 t = &image->tables [MONO_TABLE_MODULEREF];
299 ass->modules = g_new0 (MonoImage *, t->rows);
300 for (i = 0; i < t->rows; i++){
303 guint32 cols [MONO_MODULEREF_SIZE];
305 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
306 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
307 module_ref = g_concat_dir_and_file (base_dir, name);
308 ass->modules [i] = mono_image_open (module_ref, status);
309 if (ass->modules [i]) {
310 ass->modules [i]->assembly = ass;
311 load_references (ass->modules [i], status);
314 * FIXME: what do we do here? it could be a native dll...
315 * We should probably do lazy-loading of modules.
317 *status = MONO_IMAGE_OK;
321 invoke_assembly_hook (ass);
327 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
329 MonoAssembly *result;
330 char *fullpath, *filename;
334 /* g_print ("loading %s\n", aname->name); */
335 /* special case corlib */
336 if ((strcmp (aname->name, "mscorlib") == 0) || (strcmp (aname->name, "corlib") == 0)) {
338 /* g_print ("corlib already loaded\n"); */
341 /* g_print ("corlib load\n"); */
342 if (assemblies_path) {
343 corlib = load_in_path (CORLIB_NAME, (const char**)assemblies_path, status);
347 corlib = load_in_path (CORLIB_NAME, default_path, status);
350 result = search_loaded (aname);
353 /* g_print ("%s not found in cache\n", aname->name); */
354 if (strstr (aname->name, ".dll"))
355 filename = g_strdup (aname->name);
357 filename = g_strconcat (aname->name, ".dll", NULL);
359 fullpath = g_concat_dir_and_file (basedir, filename);
360 result = mono_assembly_open (fullpath, status);
367 if (assemblies_path) {
368 result = load_in_path (filename, (const char**)assemblies_path, status);
374 result = load_in_path (filename, default_path, status);
380 mono_assembly_close (MonoAssembly *assembly)
385 g_return_if_fail (assembly != NULL);
387 if (--assembly->ref_count != 0)
390 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
391 image = assembly->image;
392 if (image->references) {
393 for (i = 0; image->references [i] != NULL; i++)
394 mono_image_close (image->references [i]->image);
395 g_free (image->references);
398 mono_image_close (assembly->image);
400 g_free (assembly->basedir);
405 mono_assembly_foreach (GFunc func, gpointer user_data)
407 /* In the future this can do locking of loaded_assemblies */
409 g_list_foreach (loaded_assemblies, func, user_data);
412 /* Holds the assembly of the application, for
413 * System.Diagnostics.Process::MainModule
415 static MonoAssembly *main_assembly=NULL;
418 mono_assembly_set_main (MonoAssembly *assembly)
420 main_assembly=assembly;
424 mono_assembly_get_main (void)
426 return(main_assembly);