2004-12-29 Martin Baulig <martin@ximian.com>
[mono.git] / mono / metadata / assembly.c
index 972279bbe746c2b3f01ae98a02c8e730cfe75da6..1822bd8e4a2fbb61031b00aae2c8787a0475d6c7 100644 (file)
@@ -6,8 +6,6 @@
  *
  * (C) 2001 Ximian, Inc.  http://www.ximian.com
  *
- * TODO:
- *   Implement big-endian versions of the reading routines.
  */
 #include <config.h>
 #include <stdio.h>
 #include "image.h"
 #include "cil-coff.h"
 #include "rawbuffer.h"
-#ifdef WITH_BUNDLE
-#include "mono-bundle.h"
-#endif
 #include <mono/metadata/loader.h>
 #include <mono/metadata/tabledefs.h>
+#include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/domain-internals.h>
 #include <mono/io-layer/io-layer.h>
 #include <mono/utils/mono-uri.h>
 #include <mono/metadata/mono-config.h>
 #include <mono/utils/mono-digest.h>
+#include <mono/utils/mono-logger.h>
 #ifdef PLATFORM_WIN32
 #include <mono/os/util.h>
 #endif
@@ -39,8 +37,12 @@ default_path [] = {
        NULL
 };
 
+/* Contains the list of directories to be searched for assemblies (MONO_PATH) */
 static char **assemblies_path = NULL;
 
+/* Contains the list of directories that point to auxiliary GACs */
+static char **extra_gac_paths = NULL;
+
 /*
  * keeps track of loaded assemblies
  */
@@ -53,7 +55,8 @@ static CRITICAL_SECTION assemblies_mutex;
 /* A hastable of thread->assembly list mappings */
 static GHashTable *assemblies_loading;
 
-static char **extra_gac_paths = NULL;
+/* If defined, points to the bundled assembly information */
+const MonoBundledAssembly **bundles;
 
 static gchar*
 encode_public_tok (const guchar *token, gint32 len)
@@ -72,7 +75,8 @@ encode_public_tok (const guchar *token, gint32 len)
 }
 
 static void
-check_path_env (void) {
+check_path_env (void)
+{
        const char *path;
        char **splitted;
        
@@ -119,7 +123,7 @@ check_extra_gac_path_env (void) {
        }
 }
 
-static gboolean
+gboolean
 mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
 {
        if (!l->name || !r->name)
@@ -128,46 +132,34 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
        if (strcmp (l->name, r->name))
                return FALSE;
 
-        /*
-         * simply compare names until some other issues are resolved
-         * (version info not getting set correctly for custom
-         * attributes).
-         */
-        /*
+       if (l->culture && r->culture && strcmp (l->culture, r->culture))
+               return FALSE;
+
        if (l->major != r->major || l->minor != r->minor ||
                        l->build != r->build || l->revision != r->revision)
-               return FALSE;
+               if (! ((l->major == 0 && l->minor == 0 && l->build == 0 && l->revision == 0) || (r->major == 0 && r->minor == 0 && r->build == 0 && r->revision == 0)))
+                       return FALSE;
 
-       if (!l->public_tok_value && !r->public_tok_value)
+       if (!l->public_key_token [0] || !r->public_key_token [0])
                return TRUE;
 
-       if ((l->public_tok_value && !r->public_tok_value) || (!l->public_tok_value && r->public_tok_value))
+       if (strcmp (l->public_key_token, r->public_key_token))
                return FALSE;
 
-       if (strcmp (l->public_tok_value, r->public_tok_value))
-               return FALSE;
-        */
        return TRUE;
 }
 
-/* assemblies_mutex must be held by the caller */
 static MonoAssembly*
 search_loaded (MonoAssemblyName* aname)
 {
        GList *tmp;
        MonoAssembly *ass;
        GList *loading;
-       
-       for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
-               ass = tmp->data;
-               /* g_print ("compare %s %s\n", aname->name, ass->aname.name); */
-               if (!mono_assembly_names_equal (aname, &ass->aname))
-                       continue;
-               /* g_print ("success\n"); */
 
+       ass = mono_assembly_invoke_search_hook (aname);
+       if (ass)
                return ass;
-       }
-
+       
        /*
         * The assembly might be under load by this thread. In this case, it is
         * safe to return an incomplete instance to prevent loops.
@@ -267,8 +259,29 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
        aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
        aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
        aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
-       if (cols [MONO_ASSEMBLY_PUBLIC_KEY])
+       if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
+               gchar* token = g_malloc (8);
+               gchar* encoded;
+               int len;
+
                aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
+               len = mono_metadata_decode_blob_size (aname->public_key, (const char**)&aname->public_key);
+
+               mono_digest_get_public_token (token, aname->public_key, len);
+               encoded = encode_public_tok (token, 8);
+               g_strlcpy (aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+
+               g_free (encoded);
+               g_free (token);
+       }
+       else {
+               aname->public_key = NULL;
+               memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+       }
+
+       if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
+               aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
+       }
        else
                aname->public_key = 0;
 
@@ -294,128 +307,123 @@ assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
 }
 
 void
-mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
+mono_assembly_load_reference (MonoImage *image, int index)
 {
        MonoTableInfo *t;
        guint32 cols [MONO_ASSEMBLYREF_SIZE];
        const char *hash;
-       int i;
-       MonoAssembly **references = NULL;
+       MonoAssembly *reference;
+       MonoAssemblyName aname;
+       MonoImageOpenStatus status;
 
-       *status = MONO_IMAGE_OK;
-       
        /*
         * image->references is shared between threads, so we need to access
         * it inside a critical section.
         */
        EnterCriticalSection (&assemblies_mutex);
-       references = image->references;
+       reference = image->references [index];
        LeaveCriticalSection (&assemblies_mutex);
-       if (references)
+       if (reference)
                return;
 
        t = &image->tables [MONO_TABLE_ASSEMBLYREF];
 
-       references = g_new0 (MonoAssembly *, t->rows + 1);
+       mono_metadata_decode_row (t, index, cols, MONO_ASSEMBLYREF_SIZE);
+               
+       hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
+       aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
+       aname.hash_value = hash;
+       aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
+       aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
+       aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
+       aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
+       aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
+       aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
+       aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
+
+       if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
+               gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname.flags);
+               g_strlcpy (aname.public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+               g_free (token);
+       } else {
+               memset (aname.public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+       } 
 
-       /*
-        * Load any assemblies this image references
-        */
-       for (i = 0; i < t->rows; i++) {
-               MonoAssemblyName aname;
+       reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
 
-               mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
-               
-               hash = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLYREF_HASH_VALUE]);
-               aname.hash_len = mono_metadata_decode_blob_size (hash, &hash);
-               aname.hash_value = hash;
-               aname.name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
-               aname.culture = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]);
-               aname.flags = cols [MONO_ASSEMBLYREF_FLAGS];
-               aname.major = cols [MONO_ASSEMBLYREF_MAJOR_VERSION];
-               aname.minor = cols [MONO_ASSEMBLYREF_MINOR_VERSION];
-               aname.build = cols [MONO_ASSEMBLYREF_BUILD_NUMBER];
-               aname.revision = cols [MONO_ASSEMBLYREF_REV_NUMBER];
-
-               if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
-                       aname.public_tok_value = assemblyref_public_tok (image,
-                                       cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname.flags);
-               } else {
-                       aname.public_tok_value = NULL;
-               } 
-
-               references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
-
-               if (references [i] == NULL){
-                       int j;
-
-                       /*
-                       ** Temporary work around: any System.* which are 3300 build, will get
-                       ** remapped, this is to keep old applications running that might have
-                       ** been linked against our 5000 API, before we were strongnamed, and
-                       ** hence were labeled as 3300 builds by reflection.c
-                       */
-                       if (aname.build == 3300 && strncmp (aname.name, "System", 6) == 0){
-                               aname.build = 5000;
+       if (reference == NULL){
+               /*
+               ** Temporary work around: any System.* which are 3300 build, will get
+               ** remapped, this is to keep old applications running that might have
+               ** been linked against our 5000 API, before we were strongnamed, and
+               ** hence were labeled as 3300 builds by reflection.c
+               */
+               if (aname.build == 3300 && strncmp (aname.name, "System", 6) == 0){
+                       aname.build = 5000;
                                
-                               references [i] = mono_assembly_load (&aname, image->assembly->basedir, status);
+                       reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
+               }
+               if (reference != NULL){
+                       if (g_getenv ("MONO_SILENT_WARNING") == NULL)
+                               g_printerr ("Compat mode: the request from %s to load %s was remapped (http://www.go-mono.com/remap.html)\n",
+                                                       image->name, aname.name);
+                       
+               } else {
+                       char *extra_msg = g_strdup ("");
+
+                       if (status == MONO_IMAGE_ERROR_ERRNO) {
+                               extra_msg = g_strdup_printf ("System error: %s\n", strerror (errno));
+                       } else if (status == MONO_IMAGE_MISSING_ASSEMBLYREF) {
+                               extra_msg = g_strdup ("Cannot find an assembly referenced from this one.\n");
+                       } else if (status == MONO_IMAGE_IMAGE_INVALID) {
+                               extra_msg = g_strdup ("The file exists but is not a valid assembly.\n");
                        }
-                       if (references [i] != NULL){
-                               if (g_getenv ("MONO_SILENT_WARNING") == NULL)
-                                       g_printerr ("Compat mode: the request from %s to load %s was remapped (http://www.go-mono.com/remap.html)\n",
-                                                image->name, aname.name);
-                               
-                       } else {
                        
-                               for (j = 0; j < i; j++)
-                                       mono_assembly_close (references [j]);
-                               g_free (references);
-                               
-                               g_warning ("Could not find assembly %s, references from %s (assemblyref_index=%d)\n"
+                       g_warning ("Could not find assembly %s, references from %s (assemblyref_index=%d)\n"
                                           "     Major/Minor: %d,%d\n"
                                           "     Build:       %d,%d\n"
-                                          "     Token:       %s\n",
-                                          aname.name, image->name, i,
+                                          "     Token:       %s\n%s",
+                                          aname.name, image->name, index,
                                           aname.major, aname.minor, aname.build, aname.revision,
-                                          aname.public_tok_value);
-                               g_free (aname.public_tok_value);
-                               *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
-                               return;
-                       }
+                                          aname.public_key_token, extra_msg);
+                       g_free (extra_msg);
                }
-               g_free (aname.public_tok_value);
+       }
 
-               /* 
-                * This check is disabled since lots of people seem to have an older
-                * corlib which triggers this.
-                */
-               /* 
-               if (image->references [i]->image == image)
-                       g_error ("Error: Assembly %s references itself", image->name);
-               */
+       if (reference == NULL)
+               /* Flag as not found */
+               reference = (gpointer)-1;
+
+       EnterCriticalSection (&assemblies_mutex);
+       if (!image->references [index])
+               image->references [index] = reference;
+       LeaveCriticalSection (&assemblies_mutex);
+
+       if (image->references [index] != reference) {
+               /* Somebody loaded it before us */
+               mono_assembly_close (reference);
        }
-       references [i] = NULL;
+}
+
+void
+mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
+{
+       MonoTableInfo *t;
+       int i;
+
+       *status = MONO_IMAGE_OK;
+
+       t = &image->tables [MONO_TABLE_ASSEMBLYREF];
+       
+       image->references = g_new0 (MonoAssembly *, t->rows + 1);
 
        /* resolve assembly references for modules */
-       t = &image->tables [MONO_TABLE_MODULEREF];
-       for (i = 0; i < t->rows; i++){
+       for (i = 0; i < image->module_count; i++){
                if (image->modules [i]) {
                        image->modules [i]->assembly = image->assembly;
                        mono_assembly_load_references (image->modules [i], status);
                }
        }
-
-       EnterCriticalSection (&assemblies_mutex);
-       if (!image->references)
-               image->references = references;
-       LeaveCriticalSection (&assemblies_mutex);
-
-       if (image->references != references) {
-               /* Somebody loaded it before us */
-               for (i = 0; i < t->rows; i++)
-                       mono_assembly_close (references [i]);
-               g_free (references);
-       }
 }
 
 typedef struct AssemblyLoadHook AssemblyLoadHook;
@@ -451,6 +459,43 @@ mono_install_assembly_load_hook (MonoAssemblyLoadFunc func, gpointer user_data)
        assembly_load_hook = hook;
 }
 
+typedef struct AssemblySearchHook AssemblySearchHook;
+struct AssemblySearchHook {
+       AssemblySearchHook *next;
+       MonoAssemblySearchFunc func;
+       gpointer user_data;
+};
+
+AssemblySearchHook *assembly_search_hook = NULL;
+
+MonoAssembly*
+mono_assembly_invoke_search_hook (MonoAssemblyName *aname)
+{
+       AssemblySearchHook *hook;
+
+       for (hook = assembly_search_hook; hook; hook = hook->next) {
+               MonoAssembly *ass = hook->func (aname, hook->user_data);
+               if (ass)
+                       return ass;
+       }
+
+       return NULL;
+}
+
+void          
+mono_install_assembly_search_hook (MonoAssemblySearchFunc func, gpointer user_data)
+{
+       AssemblySearchHook *hook;
+       
+       g_return_if_fail (func != NULL);
+
+       hook = g_new0 (AssemblySearchHook, 1);
+       hook->func = func;
+       hook->user_data = user_data;
+       hook->next = assembly_search_hook;
+       assembly_search_hook = hook;
+}      
+
 typedef struct AssemblyPreLoadHook AssemblyPreLoadHook;
 struct AssemblyPreLoadHook {
        AssemblyPreLoadHook *next;
@@ -544,36 +589,30 @@ absolute_dir (const gchar *filename)
        return res;
 }
 
-static MonoImage*
-do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
+/** 
+ * mono_assembly_open_from_bundle:
+ * @filename: Filename requested
+ * @status: return value
+ *
+ * This routine tries to open the assembly specified by `filename' from the
+ * defined bundles, if found, returns the MonoImage for it, if not found
+ * returns NULL
+ */
+static MonoImage *
+mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status)
 {
-       MonoImage *image = NULL;
-#ifdef WITH_BUNDLE
        int i;
        char *name = g_path_get_basename (filename);
-       char *dot = strrchr (name, '.');
-       GList *tmp;
-       MonoAssembly *ass;
-       
-       if (dot)
-               *dot = 0;
-       /* we do a very simple search for bundled assemblies: it's not a general 
+       MonoImage *image = NULL;
+
+       /*
+        * we do a very simple search for bundled assemblies: it's not a general 
         * purpose assembly loading mechanism.
         */
        EnterCriticalSection (&assemblies_mutex);
-       for (tmp = loaded_assemblies; tmp; tmp = tmp->next) {
-               ass = tmp->data;
-               if (!ass->aname.name)
-                       continue;
-               if (strcmp (name, ass->aname.name))
-                       continue;
-               image = ass->image;
-               break;
-       }
-
-       for (i = 0; !image && bundled_assemblies [i]; ++i) {
-               if (strcmp (bundled_assemblies [i]->name, name) == 0) {
-                       image = mono_image_open_from_data ((char*)bundled_assemblies [i]->data, bundled_assemblies [i]->size, FALSE, status);
+       for (i = 0; !image && bundles [i]; ++i) {
+               if (strcmp (bundles [i]->name, name) == 0) {
+                       image = mono_image_open_from_data ((char*)bundles [i]->data, bundles [i]->size, FALSE, status);
                        break;
                }
        }
@@ -583,11 +622,24 @@ do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
                mono_image_addref (image);
                return image;
        }
-#endif
+       return NULL;
+}
+
+static MonoImage*
+do_mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
+{
+       MonoImage *image = NULL;
+
+       if (bundles != NULL){
+               image = mono_assembly_open_from_bundle (filename, status);
+
+               if (image != NULL)
+                       return image;
+       }
        EnterCriticalSection (&assemblies_mutex);
        image = mono_image_open (filename, status);
        LeaveCriticalSection (&assemblies_mutex);
-       
+
        return image;
 }
 
@@ -645,7 +697,8 @@ mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
                fname = g_strdup (filename);
        }
 
-       /* g_print ("file loading %s\n", fname); */
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
+                       "Assembly Loader probing location: '%s'.", filename);
        image = do_mono_assembly_open (fname, status);
 
        if (!image){
@@ -656,7 +709,11 @@ mono_assembly_open (const char *filename, MonoImageOpenStatus *status)
 
        ass = mono_assembly_load_from (image, fname, status);
 
-       mono_config_for_assembly (ass->image);
+       if (ass) {
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY,
+                               "Assembly Loader loaded assembly from location: '%s'.", filename);
+               mono_config_for_assembly (ass->image);
+       }
 
        g_free (fname);
 
@@ -727,10 +784,6 @@ mono_assembly_load_from (MonoImage *image, const char*fname,
 
        image->assembly = ass;
 
-       /*
-        * We load referenced assemblies outside the lock to prevent deadlocks
-        * with regards to preload hooks.
-        */
        mono_assembly_load_references (image, status);
 
        EnterCriticalSection (&assemblies_mutex);
@@ -801,16 +854,16 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta
        memset (&aname, 0, sizeof (MonoAssemblyName));
        aname.name = name;
 
+       res = mono_assembly_loaded (&aname);
+       if (res)
+               return res;
+
        res = invoke_assembly_preload_hook (&aname, assemblies_path);
        if (res) {
                res->in_gac = FALSE;
                return res;
        }
 
-       res = mono_assembly_loaded (&aname);
-       if (res)
-               return res;
-
        fullname = g_strdup_printf ("%s.dll", name);
 
        if (extra_gac_paths) {
@@ -855,7 +908,7 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImag
        gint32 len;
        gchar **paths;
 
-       if (!aname->public_tok_value) {
+       if (aname->public_key_token [0] == 0) {
                return NULL;
        }
 
@@ -876,7 +929,7 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImag
 
        version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
                        aname->minor, aname->build, aname->revision,
-                       culture, aname->public_tok_value);
+                       culture, aname->public_key_token);
        
        subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
        g_free (name);
@@ -919,19 +972,20 @@ mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenS
        MonoAssembly *result;
        char *fullpath, *filename;
 
+       result = mono_assembly_loaded (aname);
+       if (result)
+               return result;
+
        result = invoke_assembly_preload_hook (aname, assemblies_path);
        if (result) {
                result->in_gac = FALSE;
                return result;
        }
 
-       result = mono_assembly_loaded (aname);
-       if (result)
-               return result;
-
        /* g_print ("loading %s\n", aname->name); */
        /* special case corlib */
        if (strcmp (aname->name, "mscorlib") == 0) {
+               char *corlib_file;
                if (corlib) {
                        /* g_print ("corlib already loaded\n"); */
                        return corlib;
@@ -943,6 +997,23 @@ mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenS
                                return corlib;
                }
                corlib = load_in_path ("mscorlib.dll", default_path, status);
+
+               if (corlib)
+                       return corlib;
+       
+               /* Load corlib from mono/<version> */
+               
+               corlib_file = g_build_filename ("mono", mono_get_framework_version (), "mscorlib.dll", NULL);
+               if (assemblies_path) {
+                       corlib = load_in_path (corlib_file, (const char**)assemblies_path, status);
+                       if (corlib) {
+                               g_free (corlib_file);
+                               return corlib;
+                       }
+               }
+               corlib = load_in_path (corlib_file, default_path, status);
+               g_free (corlib_file);
+       
                return corlib;
        }
 
@@ -1005,7 +1076,8 @@ mono_assembly_close (MonoAssembly *assembly)
        image = assembly->image;
        if (image->references) {
                for (i = 0; image->references [i] != NULL; i++)
-                       mono_image_close (image->references [i]->image);
+                       if (image->references [i] && (image->references [i] != (gpointer)-1))
+                               mono_image_close (image->references [i]->image);
                g_free (image->references);
        }
 
@@ -1034,7 +1106,7 @@ mono_assembly_foreach (GFunc func, gpointer user_data)
        GList *copy;
 
        /*
-     * We make a copy of the list to avoid calling the callback inside the 
+        * We make a copy of the list to avoid calling the callback inside the 
         * lock, which could lead to deadlocks.
         */
        EnterCriticalSection (&assemblies_mutex);
@@ -1046,7 +1118,8 @@ mono_assembly_foreach (GFunc func, gpointer user_data)
        g_list_free (copy);
 }
 
-/* Holds the assembly of the application, for
+/*
+ * Holds the assembly of the application, for
  * System.Diagnostics.Process::MainModule
  */
 static MonoAssembly *main_assembly=NULL;
@@ -1063,4 +1136,14 @@ mono_assembly_get_main (void)
        return(main_assembly);
 }
 
+MonoImage*
+mono_assembly_get_image (MonoAssembly *assembly)
+{
+       return assembly->image;
+}
 
+void
+mono_register_bundled_assemblies (const MonoBundledAssembly **assemblies)
+{
+       bundles = assemblies;
+}