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, 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_open:
118 * @filename: Opens the assembly pointed out by this name
119 * @status: where a status code can be returned
121 * mono_assembly_open opens the PE-image pointed by @filename, and
122 * loads any external assemblies referenced by it.
124 * NOTE: we could do lazy loading of the assemblies. Or maybe not worth
128 mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
130 MonoAssembly *ass, *ass2;
133 guint32 cols [MONO_ASSEMBLY_SIZE];
138 g_return_val_if_fail (filename != NULL, NULL);
140 /* g_print ("file loading %s\n", filename); */
141 image = mono_image_open (filename, status);
145 *status = MONO_IMAGE_ERROR_ERRNO;
149 base_dir = g_path_get_dirname (filename);
152 * Create assembly struct, and enter it into the assembly cache
154 ass = g_new0 (MonoAssembly, 1);
155 ass->basedir = base_dir;
158 image->assembly = ass;
160 t = &image->tables [MONO_TABLE_ASSEMBLY];
161 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
163 ass->aname.hash_len = 0;
164 ass->aname.hash_value = NULL;
165 ass->aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
166 ass->aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_CULTURE]);
167 ass->aname.flags = cols [MONO_ASSEMBLY_FLAGS];
168 ass->aname.major = cols [MONO_ASSEMBLY_MAJOR_VERSION];
169 ass->aname.minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
170 ass->aname.build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
171 ass->aname.revision = cols [MONO_ASSEMBLY_REV_NUMBER];
173 /* avoid loading the same assembly twixe for now... */
174 if ((ass2 = search_loaded (&ass->aname))) {
177 *status = MONO_IMAGE_OK;
181 /* register right away to prevent loops */
182 loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
184 t = &image->tables [MONO_TABLE_ASSEMBLYREF];
186 image->references = g_new0 (MonoAssembly *, t->rows + 1);
189 * Load any assemblies this image references
191 for (i = 0; i < t->rows; i++){
192 MonoAssemblyName aname;
194 mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
196 hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
197 aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
198 aname.hash_value = hash;
199 aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
200 aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
201 aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
202 aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
203 aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
204 aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
205 aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
207 image->references [i] = mono_assembly_load (&aname, base_dir, status);
209 if (image->references [i] == NULL){
212 for (j = 0; j < i; j++)
213 mono_assembly_close (image->references [j]);
214 g_free (image->references);
215 mono_image_close (image);
217 g_warning ("Could not find assembly %s", aname.name);
219 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
221 loaded_assemblies = g_list_remove (loaded_assemblies, ass);
226 image->references [i] = NULL;
228 t = &image->tables [MONO_TABLE_MODULEREF];
229 ass->modules = g_new0 (MonoImage *, t->rows);
230 for (i = 0; i < t->rows; i++){
233 guint32 cols [MONO_MODULEREF_SIZE];
235 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
236 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
237 module_ref = g_concat_dir_and_file (base_dir, name);
238 ass->modules [i] = mono_image_open (module_ref, status);
247 mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status)
249 MonoAssembly *result;
250 char *fullpath, *filename;
254 /* g_print ("loading %s\n", aname->name); */
255 /* special case corlib */
256 if ((strcmp (aname->name, "mscorlib") == 0) || (strcmp (aname->name, "corlib") == 0)) {
258 /* g_print ("corlib already loaded\n"); */
261 /* g_print ("corlib load\n"); */
262 if (assemblies_path) {
263 corlib = load_in_path (CORLIB_NAME, assemblies_path, status);
267 fullpath = g_concat_dir_and_file (MONO_ASSEMBLIES, CORLIB_NAME);
268 corlib = mono_assembly_open (fullpath, status);
272 result = search_loaded (aname);
275 /* g_print ("%s not found in cache\n", aname->name); */
276 if (strstr (aname->name, ".dll"))
277 filename = g_strdup (aname->name);
279 filename = g_strconcat (aname->name, ".dll", NULL);
281 fullpath = g_concat_dir_and_file (basedir, filename);
282 result = mono_assembly_open (fullpath, status);
289 if (assemblies_path) {
290 result = load_in_path (filename, assemblies_path, status);
296 result = load_in_path (filename, default_path, status);
302 mono_assembly_close (MonoAssembly *assembly)
307 g_return_if_fail (assembly != NULL);
309 if (--assembly->ref_count != 0)
312 loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
313 image = assembly->image;
314 for (i = 0; image->references [i] != NULL; i++)
315 mono_image_close (image->references [i]->image);
316 g_free (image->references);
318 mono_image_close (assembly->image);
320 g_free (assembly->basedir);