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;
187 * mono_assembly_open:
188 * @filename: Opens the assembly pointed out by this name
189 * @status: where a status code can be returned
191 * mono_assembly_open opens the PE-image pointed by @filename, and
192 * loads any external assemblies referenced by it.
194 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
198 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
200 MonoAssembly *ass, *ass2;
203 guint32 cols [MONO_ASSEMBLY_SIZE];
206 MonoImageOpenStatus def_status;
208 g_return_val_if_fail (filename != NULL, NULL);
211 status = &def_status;
212 *status = MONO_IMAGE_OK;
214 /* g_print ("file loading %s\n", filename); */
215 image = mono_image_open (filename, status);
218 *status = MONO_IMAGE_ERROR_ERRNO;
222 base_dir = g_path_get_dirname (filename);
225 * Create assembly struct, and enter it into the assembly cache
227 ass = g_new0 (MonoAssembly, 1);
228 ass->basedir = base_dir;
231 t = &image->tables [MONO_TABLE_ASSEMBLY];
233 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
235 ass->aname.hash_len = 0;
236 ass->aname.hash_value = NULL;
237 ass->aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
238 ass->aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
239 ass->aname.flags = cols [MONO_ASSEMBLY_FLAGS];
240 ass->aname.major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
241 ass->aname.minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
242 ass->aname.build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
243 ass->aname.revision = cols [MONO_ASSEMBLY_REV_NUMBER];
245 /* avoid loading the same assembly twixe for now... */
246 if ((ass2 = search_loaded (&ass->aname))) {
249 *status = MONO_IMAGE_OK;
254 image->assembly = ass;
256 /* register right away to prevent loops */
257 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
259 load_references (image, status);
260 if (*status != MONO_IMAGE_OK) {
261 mono_assembly_close (ass);
265 t = &image->tables [MONO_TABLE_MODULEREF];
266 ass->modules = g_new0 (MonoImage *, t->rows);
267 for (i = 0; i < t->rows; i++){
270 guint32 cols [MONO_MODULEREF_SIZE];
272 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
273 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
274 module_ref = g_concat_dir_and_file (base_dir, name);
275 ass->modules [i] = mono_image_open (module_ref, status);
276 if (ass->modules [i]) {
277 ass->modules [i]->assembly = ass;
278 load_references (ass->modules [i], status);
281 * FIXME: what do we do here? it could be a native dll...
282 * We should probably do lazy-loading of modules.
284 *status = MONO_IMAGE_OK;
292 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
294 MonoAssembly *result;
295 char *fullpath, *filename;
299 /* g_print ("loading %s\n", aname->name); */
300 /* special case corlib */
301 if ((strcmp (aname->name, "mscorlib") == 0) || (strcmp (aname->name, "corlib") == 0)) {
303 /* g_print ("corlib already loaded\n"); */
306 /* g_print ("corlib load\n"); */
307 if (assemblies_path) {
308 corlib = load_in_path (CORLIB_NAME, (const char**)assemblies_path, status);
312 corlib = load_in_path (CORLIB_NAME, default_path, status);
315 result = search_loaded (aname);
318 /* g_print ("%s not found in cache\n", aname->name); */
319 if (strstr (aname->name, ".dll"))
320 filename = g_strdup (aname->name);
322 filename = g_strconcat (aname->name, ".dll", NULL);
324 fullpath = g_concat_dir_and_file (basedir, filename);
325 result = mono_assembly_open (fullpath, status);
332 if (assemblies_path) {
333 result = load_in_path (filename, (const char**)assemblies_path, status);
339 result = load_in_path (filename, default_path, status);
345 mono_assembly_close (MonoAssembly *assembly)
350 g_return_if_fail (assembly != NULL);
352 if (--assembly->ref_count != 0)
355 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
356 image = assembly->image;
357 if (image->references) {
358 for (i = 0; image->references [i] != NULL; i++)
359 mono_image_close (image->references [i]->image);
360 g_free (image->references);
363 mono_image_close (assembly->image);
365 g_free (assembly->basedir);
370 mono_assembly_foreach (GFunc func, gpointer user_data)
372 /* In the future this can do locking of loaded_assemblies */
374 g_list_foreach (loaded_assemblies, func, user_data);
377 /* Holds the assembly of the application, for
378 * System.Diagnostics.Process::MainModule
380 static MonoAssembly *main_assembly=NULL;
383 mono_assembly_set_main (MonoAssembly *assembly)
385 main_assembly=assembly;
389 mono_assembly_get_main (void)
391 return(main_assembly);