3 * The main entry point for the mono executable
5 * The main entry point does a few things:
7 * * It probes whether the executable has a bundle appended
8 * at the end, and if so, registers the various bundled
9 * resources with Mono and executes the contained bundle
11 * * Parses the MONO_ENV_OPTIONS variable to treat the
12 * contents of the variable as command line arguments for
15 * * Launches Mono, by calling mono_main.
22 #include <mono/metadata/assembly.h>
23 #include <mono/metadata/mono-config.h>
24 #include <mono/utils/mono-mmap.h>
26 #include "mini-runtime.h"
34 # ifndef BUILDVER_INCLUDED
35 # include "buildver-boehm.h"
39 //#define TEST_ICALL_SYMBOL_MAP 1
42 * If the MONO_ENV_OPTIONS environment variable is set, it uses this as a
43 * source of command line arguments that are passed to Mono before the
44 * command line arguments specified in the command line.
47 mono_main_with_options (int argc
, char *argv
[])
49 mono_parse_env_options (&argc
, &argv
);
51 return mono_main (argc
, argv
);
55 * The Mono executable can initialize itself from a payload attached
56 * at the end of the main program. The payload contains the
57 * main assembly, one or more managed assemblies, configuration
58 * files and other assets that are used instead of launching a
59 * program from the command line.
61 * The startup sequence probes for a magical signature at the end of
62 * the executable, if the 16 characters "xmonkeysloveplay" are found,
63 * the code expects the 64-bits just before it to contain an offset
64 * within the executable with a directory of assets.
66 * All pointers in the file format are encoded as little-endian values
68 * The format of the file is thus:
72 * lenght-16 Optional "xmonkeysloveplay", indicating that a
73 * bundled payload is contained in the executable.
74 * length-24 pointer to the directory in the file, address DIR
76 * DIR 32-bit value with the number of entries in the directory
77 * DIR+4 First directory entry.
79 * Each directory entry is made up of:
80 * 4-bytes uint32_t containing the size of a string (STR)
81 * STRING UTF8 encoded and \0 terminated string
82 * 8-bytes uint64_t offset in the file with the payload associated with STRING
83 * 4-bytes uint32_t size of the asset
85 * The following are the known directory entries, without the quotes:
86 * "assembly:NAME" An assembly with the name NAME, assembly is in the payload
87 * "config:NAME" A configuration file (usually file.dll.config) in the payload that is
88 * loaded as the config file for an assembly
89 * "systemconfig:" Treats as a Mono system configuration, payload contains the config file.
90 * "options:" The payload contains command line options to initialize Mono, as if you
91 had set them on MONO_ENV_OPTIONS
92 * "config_dir:DIR" Configures the MONO_PATH to point to point to DIR
93 * "machineconfig:" The payload contains the machine.config file to use at runtime
94 * "env:" Sets the environment variable to the value encoded in the payload
95 * payload contains: 1-byte lenght for the \0 terminated variable,
96 * followed by the value.
97 * "library:NAME" Bundled dynamic library NAME, payload contains the dynamic library
99 #define STREAM_INT(x) GUINT32_TO_LE((*(uint32_t*)x))
100 #define STREAM_LONG(x) GUINT64_TO_LE((*(uint64_t*)x))
104 search_directories(const char *envPath
, const char *program
, char **new_program
)
106 gchar
**paths
= NULL
;
109 paths
= g_strsplit (envPath
, G_SEARCHPATH_SEPARATOR_S
, 0);
112 for (i
= 0; paths
[i
]; ++i
) {
113 gchar
*path
= paths
[i
];
114 gint path_len
= strlen (path
);
121 dir
= opendir (path
);
125 while ((ent
= readdir (dir
))){
126 if (!strcmp (ent
->d_name
, program
)){
127 *new_program
= g_strdup_printf ("%s%s%s", path
, path
[path_len
- 1] == '/' ? "" : "/", program
);
144 probe_embedded (const char *program
, int *ref_argc
, char **ref_argv
[])
146 MonoBundledAssembly last
= { NULL
, 0, 0 };
147 char sigbuffer
[16+sizeof (uint64_t)];
148 gboolean status
= FALSE
;
149 uint64_t directory_location
;
150 off_t sigstart
, baseline
= 0;
151 uint64_t directory_size
;
154 unsigned char *mapaddress
= NULL
;
155 void *maphandle
= NULL
;
157 char *entry_point
= NULL
;
161 int fd
= open (program
, O_RDONLY
);
164 // Also search through the PATH in case the program was run from a different directory
165 gchar
* envPath
= getenv ("PATH");
167 gchar
*new_program
= NULL
;
168 if (search_directories (envPath
, program
, &new_program
)){
169 fd
= open (new_program
, O_RDONLY
);
170 g_free (new_program
);
178 if ((sigstart
= lseek (fd
, -24, SEEK_END
)) == -1)
180 if (read (fd
, sigbuffer
, sizeof (sigbuffer
)) == -1)
182 if (memcmp (sigbuffer
+sizeof(uint64_t), "xmonkeysloveplay", 16) != 0)
184 directory_location
= GUINT64_FROM_LE ((*(uint64_t *) &sigbuffer
[0]));
185 if (lseek (fd
, directory_location
, SEEK_SET
) == -1)
187 directory_size
= sigstart
-directory_location
;
188 directory
= g_malloc (directory_size
);
189 if (directory
== NULL
)
191 if (read (fd
, directory
, directory_size
) == -1)
194 items
= STREAM_INT (directory
);
197 assemblies
= g_array_new (0, 0, sizeof (MonoBundledAssembly
*));
198 for (i
= 0; i
< items
; i
++){
200 int strsize
= STREAM_INT (p
);
205 offset
= STREAM_LONG(p
);
207 item_size
= STREAM_INT (p
);
210 if (mapaddress
== NULL
) {
211 char *error_message
= NULL
;
212 mapaddress
= (guchar
*)mono_file_map_error (directory_location
- offset
, MONO_MMAP_READ
| MONO_MMAP_PRIVATE
,
213 fd
, offset
, &maphandle
, program
, &error_message
);
214 if (mapaddress
== NULL
) {
216 fprintf (stderr
, "Error mapping file: %s\n", error_message
);
218 perror ("Error mapping file");
223 if (strncmp (kind
, "assembly:", strlen ("assembly:")) == 0){
224 char *aname
= kind
+ strlen ("assembly:");
225 MonoBundledAssembly mba
= { aname
, mapaddress
+ offset
- baseline
, item_size
}, *ptr
;
226 ptr
= g_new (MonoBundledAssembly
, 1);
227 memcpy (ptr
, &mba
, sizeof (MonoBundledAssembly
));
228 g_array_append_val (assemblies
, ptr
);
229 if (entry_point
== NULL
)
231 } else if (strncmp (kind
, "config:", strlen ("config:")) == 0){
232 char *config
= kind
+ strlen ("config:");
233 char *aname
= g_strdup (config
);
234 aname
[strlen(aname
)-strlen(".config")] = 0;
235 mono_register_config_for_assembly (aname
, g_str_from_file_region (fd
, offset
, item_size
));
236 } else if (strncmp (kind
, "systemconfig:", strlen ("systemconfig:")) == 0){
237 mono_config_parse_memory (g_str_from_file_region (fd
, offset
, item_size
));
238 } else if (strncmp (kind
, "options:", strlen ("options:")) == 0){
239 mono_parse_options_from (g_str_from_file_region (fd
, offset
, item_size
), ref_argc
, ref_argv
);
240 } else if (strncmp (kind
, "config_dir:", strlen ("config_dir:")) == 0){
241 char *mono_path_value
= g_getenv ("MONO_PATH");
242 mono_set_dirs (mono_path_value
, g_str_from_file_region (fd
, offset
, item_size
));
243 g_free (mono_path_value
);
244 } else if (strncmp (kind
, "machineconfig:", strlen ("machineconfig:")) == 0) {
245 mono_register_machine_config (g_str_from_file_region (fd
, offset
, item_size
));
246 } else if (strncmp (kind
, "env:", strlen ("env:")) == 0){
247 char *data
= g_str_from_file_region (fd
, offset
, item_size
);
248 uint8_t count
= *data
++;
249 char *value
= data
+ count
+ 1;
250 g_setenv (data
, value
, FALSE
);
251 } else if (strncmp (kind
, "library:", strlen ("library:")) == 0){
252 mono_loader_save_bundled_library (fd
, offset
, item_size
, kind
+ strlen ("library:"));
254 fprintf (stderr
, "Unknown stream on embedded package: %s\n", kind
);
258 g_array_append_val (assemblies
, last
);
260 mono_register_bundled_assemblies ((const MonoBundledAssembly
**) assemblies
->data
);
261 new_argv
= g_new (char *, (*ref_argc
)+1);
262 new_argv
[0] = (*ref_argv
)[0];
263 new_argv
[1] = entry_point
;
264 for (j
= 1; j
< *ref_argc
; j
++)
265 new_argv
[j
+1] = (*ref_argv
)[j
];
266 *ref_argv
= new_argv
;
279 #if TEST_ICALL_SYMBOL_MAP
282 mono_lookup_icall_symbol_internal (gpointer func
);
284 ICALL_EXPORT
int ves_icall_Interop_Sys_DoubleToString (double, char*, char*, int);
290 #include <shellapi.h>
294 wWinMain (HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPWSTR lpCmdLine
, int nCmdShow
)
297 main (int _argc
, char* _argv
[])
300 gunichar2
*module_file_name
;
307 argvw
= CommandLineToArgvW (GetCommandLineW (), &argc
);
308 argv
= g_new0 (gchar
*, argc
+ 1);
309 for (i
= 0; i
< argc
; i
++)
310 argv
[i
] = g_utf16_to_utf8 (argvw
[i
], -1, NULL
, NULL
, NULL
);
315 if (mono_get_module_filename (NULL
, &module_file_name
, &length
)) {
316 char *entry
= g_utf16_to_utf8 (module_file_name
, length
, NULL
, NULL
, NULL
);
317 g_free (module_file_name
);
318 probe_embedded (entry
, &argc
, &argv
);
321 return mono_main_with_options (argc
, argv
);
327 main (int argc
, char* argv
[])
329 mono_build_date
= build_date
;
331 #if TEST_ICALL_SYMBOL_MAP
332 const char *p
= mono_lookup_icall_symbol_internal (mono_lookup_icall_symbol_internal
);
333 printf ("%s\n", p
? p
: "null");
334 p
= mono_lookup_icall_symbol_internal (ves_icall_Interop_Sys_DoubleToString
);
335 printf ("%s\n", p
? p
: "null");
338 probe_embedded (argv
[0], &argc
, &argv
);
339 return mono_main_with_options (argc
, argv
);