2 * aot.c: mono Ahead of Time compiler
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2002 Ximian, Inc.
12 #include <sys/types.h>
16 #ifndef PLATFORM_WIN32
25 #include <limits.h> /* for PAGESIZE */
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/class.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/tokentype.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/debug-helpers.h>
36 #include <mono/metadata/assembly.h>
37 #include <mono/metadata/metadata-internals.h>
38 #include <mono/metadata/marshal.h>
39 #include <mono/utils/mono-logger.h>
40 #include "mono/utils/mono-compiler.h"
47 #define SHARED_EXT ".dll"
48 #elif defined(__ppc__) && defined(__MACH__)
49 #define SHARED_EXT ".dylib"
51 #define SHARED_EXT ".so"
54 #if defined(sparc) || defined(__ppc__)
55 #define AS_STRING_DIRECTIVE ".asciz"
58 #define AS_STRING_DIRECTIVE ".string"
61 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
62 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
64 typedef struct MonoAotOptions {
67 gboolean write_symbols;
70 typedef struct MonoAotCompile {
74 GHashTable *patch_to_plt_offset;
75 GHashTable *plt_offset_to_patch;
76 GHashTable *image_hash;
77 GHashTable *method_to_cfg;
78 GPtrArray *image_table;
80 guint32 got_offset, plt_offset;
81 guint32 *method_got_offsets;
82 MonoAotOptions aot_opts;
85 int ccount, mcount, lmfcount, abscount, wrappercount, ocount;
86 int code_size, info_size, ex_info_size, got_size, class_info_size;
90 is_got_patch (MonoJumpInfoType patch_type)
94 #elif defined(__i386__)
102 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
104 #if defined(PLATFORM_WIN32)
105 fprintf (fp, ".section %s\n", section_name);
107 /* For solaris as, GNU as should accept the same */
108 fprintf (fp, ".section \"%s\"\n", section_name);
109 #elif defined(__ppc__) && defined(__MACH__)
110 /* This needs to be made more precise on mach. */
111 fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
113 fprintf (fp, "%s %d\n", section_name, subsection_index);
118 emit_symbol_type (FILE *fp, const char *name, gboolean func)
128 fprintf (fp, "\t.type %s,#%s\n", name, stype);
129 #elif defined(PLATFORM_WIN32)
131 #elif !(defined(__ppc__) && defined(__MACH__))
132 fprintf (fp, "\t.type %s,@%s\n", name, stype);
133 #elif defined(__x86_64__) || defined(__i386__)
134 fprintf (fp, "\t.type %s,@%s\n", name, stype);
139 emit_global (FILE *fp, const char *name, gboolean func)
141 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
142 // mach-o always uses a '_' prefix.
143 fprintf (fp, "\t.globl _%s\n", name);
145 fprintf (fp, "\t.globl %s\n", name);
148 emit_symbol_type (fp, name, func);
152 emit_label (FILE *fp, const char *name)
154 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
155 // mach-o always uses a '_' prefix.
156 fprintf (fp, "_%s:\n", name);
158 fprintf (fp, "%s:\n", name);
161 #if defined(PLATFORM_WIN32)
162 /* Emit a normal label too */
163 fprintf (fp, "%s:\n", name);
168 emit_string_symbol (FILE *fp, const char *name, const char *value)
170 emit_section_change (fp, ".text", 1);
171 emit_global(fp, name, FALSE);
172 emit_label(fp, name);
173 fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
176 #if defined(__ppc__) && defined(__MACH__)
178 ilog2(register int value)
181 while (value & ~0xf) count += 4, value >>= 4;
182 while (value) count++, value >>= 1;
188 emit_alignment(FILE *fp, int size)
190 #if defined(__ppc__) && defined(__MACH__)
191 // the mach-o assembler specifies alignments as powers of 2.
192 fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
193 #elif defined(__powerpc__)
194 /* ignore on linux/ppc */
196 fprintf (fp, "\t.align %d\n", size);
200 G_GNUC_UNUSED static void
201 emit_pointer (FILE *fp, const char *target)
203 emit_alignment (fp, sizeof (gpointer));
204 #if defined(__x86_64__)
205 fprintf (fp, "\t.quad %s\n", target);
206 #elif defined(sparc) && SIZEOF_VOID_P == 8
207 fprintf (fp, "\t.xword %s\n", target);
209 fprintf (fp, "\t.long %s\n", target);
214 mono_get_field_token (MonoClassField *field)
216 MonoClass *klass = field->parent;
219 for (i = 0; i < klass->field.count; ++i) {
220 if (field == &klass->fields [i])
221 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
224 g_assert_not_reached ();
229 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
233 //printf ("ENCODE: %d 0x%x.\n", value, value);
236 * Same encoding as the one used in the metadata, extended to handle values
237 * greater than 0x1fffffff.
239 if ((value >= 0) && (value <= 127))
241 else if ((value >= 0) && (value <= 16383)) {
242 p [0] = 0x80 | (value >> 8);
243 p [1] = value & 0xff;
245 } else if ((value >= 0) && (value <= 0x1fffffff)) {
246 p [0] = (value >> 24) | 0xc0;
247 p [1] = (value >> 16) & 0xff;
248 p [2] = (value >> 8) & 0xff;
249 p [3] = value & 0xff;
254 p [1] = (value >> 24) & 0xff;
255 p [2] = (value >> 16) & 0xff;
256 p [3] = (value >> 8) & 0xff;
257 p [4] = value & 0xff;
265 get_image_index (MonoAotCompile *cfg, MonoImage *image)
269 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
273 index = g_hash_table_size (cfg->image_hash);
274 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
275 g_ptr_array_add (cfg->image_table, image);
281 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
283 if (!klass->type_token) {
285 g_assert (klass->rank > 0);
286 g_assert (klass->element_class->type_token);
287 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
288 encode_value (get_image_index (cfg, klass->image), buf, &buf);
289 g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
290 encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
291 encode_value (klass->rank, buf, &buf);
294 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
295 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
296 encode_value (get_image_index (cfg, klass->image), buf, &buf);
302 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
304 guint32 token = mono_get_field_token (field);
306 encode_klass_info (cfg, field->parent, buf, &buf);
307 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
308 encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
313 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
315 guint32 image_index = get_image_index (acfg, method->klass->image);
316 guint32 token = method->token;
317 g_assert (image_index < 256);
318 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
320 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
325 compare_patches (gconstpointer a, gconstpointer b)
329 i = (*(MonoJumpInfo**)a)->ip.i;
330 j = (*(MonoJumpInfo**)b)->ip.i;
342 get_plt_index (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
347 switch (patch_info->type) {
348 case MONO_PATCH_INFO_METHOD:
349 case MONO_PATCH_INFO_WRAPPER:
350 case MONO_PATCH_INFO_INTERNAL_METHOD:
351 case MONO_PATCH_INFO_CLASS_INIT: {
352 MonoJumpInfo *new_ji = g_new0 (MonoJumpInfo, 1);
354 memcpy (new_ji, patch_info, sizeof (MonoJumpInfo));
356 /* First check for an existing patch */
357 switch (patch_info->type) {
358 case MONO_PATCH_INFO_METHOD:
359 idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info->data.method));
363 g_hash_table_insert (acfg->patch_to_plt_offset, patch_info->data.method, GUINT_TO_POINTER (acfg->plt_offset));
365 case MONO_PATCH_INFO_INTERNAL_METHOD:
366 idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info->data.name));
370 g_hash_table_insert (acfg->patch_to_plt_offset, (char*)patch_info->data.name, GUINT_TO_POINTER (acfg->plt_offset));
372 case MONO_PATCH_INFO_CLASS_INIT:
373 idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info->data.klass));
377 g_hash_table_insert (acfg->patch_to_plt_offset, (char*)patch_info->data.klass, GUINT_TO_POINTER (acfg->plt_offset));
385 res = acfg->plt_offset;
386 g_hash_table_insert (acfg->plt_offset_to_patch, GUINT_TO_POINTER (acfg->plt_offset), new_ji);
390 /* Nullify the patch */
391 patch_info->type = MONO_PATCH_INFO_NONE;
401 get_got_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
405 switch (patch_info->type) {
406 case MONO_PATCH_INFO_IMAGE:
407 if (patch_info->data.image == acfg->image)
410 res = acfg->got_offset;
415 res = acfg->got_offset;
424 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
428 int i, j, pindex, byte_index, method_index;
431 int func_alignment = 16;
433 MonoJumpInfo *patch_info;
434 MonoMethodHeader *header;
435 #ifdef MONO_ARCH_HAVE_PIC_AOT
441 method = cfg->method;
442 code = cfg->native_code;
443 header = mono_method_get_header (method);
445 method_index = mono_metadata_token_index (method->token);
447 /* Make the labels local */
448 symbol = g_strdup_printf (".Lm_%x", method_index);
450 emit_alignment(tmpfp, func_alignment);
451 emit_label(tmpfp, symbol);
452 if (acfg->aot_opts.write_symbols)
453 emit_global (tmpfp, symbol, TRUE);
455 if (cfg->verbose_level > 0)
456 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
458 acfg->code_size += cfg->code_len;
460 /* Collect and sort relocations */
461 patches = g_ptr_array_new ();
462 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
463 g_ptr_array_add (patches, patch_info);
464 g_ptr_array_sort (patches, compare_patches);
466 #ifdef MONO_ARCH_HAVE_PIC_AOT
467 acfg->method_got_offsets [method_index] = acfg->got_offset;
469 for (i = 0; i < cfg->code_len; i++) {
471 for (pindex = 0; pindex < patches->len; ++pindex) {
472 patch_info = g_ptr_array_index (patches, pindex);
473 if (patch_info->ip.i == i)
478 if (patch_info && (pindex < patches->len)) {
479 switch (patch_info->type) {
480 case MONO_PATCH_INFO_LABEL:
481 case MONO_PATCH_INFO_BB:
482 case MONO_PATCH_INFO_NONE:
484 case MONO_PATCH_INFO_GOT_OFFSET: {
485 guint32 offset = mono_arch_get_patch_offset (code + i);
486 fprintf (tmpfp, "\n.byte ");
487 for (j = 0; j < offset; ++j)
488 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
489 fprintf (tmpfp, "\n.int got - . + %d", offset);
497 char *direct_call_target;
499 if (!is_got_patch (patch_info->type))
503 * If this patch is a call, try emitting a direct call instead of
504 * through a PLT entry. This is possible if the called method is in
505 * the same assembly and requires no initialization.
507 direct_call_target = NULL;
508 if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == cfg->method->klass->image)) {
509 MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
511 if (callee_cfg && !callee_cfg->got_var && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)) {
512 //printf ("DIRECT: %s %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (callee_cfg->method, TRUE));
513 direct_call_target = g_strdup_printf (".Lm_%x", mono_metadata_token_index (callee_cfg->method->token));
514 patch_info->type = MONO_PATCH_INFO_NONE;
518 if (!direct_call_target) {
519 plt_index = get_plt_index (acfg, patch_info);
520 if (plt_index != -1) {
521 /* This patch has a PLT entry, so we must emit a call to the PLT entry */
522 direct_call_target = g_strdup_printf (".Lp_%d", plt_index);
526 if (direct_call_target) {
527 #if defined(__i386__) || defined(__x86_64__)
528 g_assert (code [i] == 0xe8);
529 /* Need to make sure this is exactly 5 bytes long */
530 fprintf (tmpfp, "\n.byte 0xe8");
531 fprintf (tmpfp, "\n.long %s - . - 4\n", direct_call_target);
534 g_assert_not_reached ();
537 got_slot = get_got_offset (acfg, patch_info);
539 fprintf (tmpfp, "\n.byte ");
540 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
541 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
543 fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
544 #elif defined(__i386__)
545 fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((got_slot * sizeof (gpointer))));
548 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
557 fprintf (tmpfp, "\n.byte ");
558 fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
559 byte_index = (byte_index + 1) % 32;
565 for (i = 0; i < cfg->code_len; i++) {
566 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
569 fprintf (tmpfp, "\n");
573 encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint8 **endbuf)
577 switch (patch_info->type) {
578 case MONO_PATCH_INFO_NONE:
580 case MONO_PATCH_INFO_IMAGE:
581 encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
583 case MONO_PATCH_INFO_METHOD_REL:
584 encode_value ((gint)patch_info->data.offset, p, &p);
586 case MONO_PATCH_INFO_SWITCH: {
587 gpointer *table = (gpointer *)patch_info->data.table->table;
590 encode_value (patch_info->data.table->table_size, p, &p);
591 for (k = 0; k < patch_info->data.table->table_size; k++)
592 encode_value ((int)(gssize)table [k], p, &p);
595 case MONO_PATCH_INFO_METHODCONST:
596 case MONO_PATCH_INFO_METHOD:
597 case MONO_PATCH_INFO_METHOD_JUMP:
598 encode_method_ref (acfg, patch_info->data.method, p, &p);
600 case MONO_PATCH_INFO_INTERNAL_METHOD: {
601 guint32 len = strlen (patch_info->data.name);
603 encode_value (len, p, &p);
605 memcpy (p, patch_info->data.name, len);
610 case MONO_PATCH_INFO_LDSTR: {
611 guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
612 guint32 token = patch_info->data.token->token;
613 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
615 * An optimization would be to emit shared code for ldstr
616 * statements followed by a throw.
618 encode_value (image_index, p, &p);
619 encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
622 case MONO_PATCH_INFO_DECLSEC:
623 case MONO_PATCH_INFO_LDTOKEN:
624 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
625 encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
626 encode_value (patch_info->data.token->token, p, &p);
628 case MONO_PATCH_INFO_EXC_NAME: {
632 mono_class_from_name (mono_defaults.exception_class->image,
633 "System", patch_info->data.target);
635 encode_klass_info (acfg, ex_class, p, &p);
638 case MONO_PATCH_INFO_R4:
639 encode_value (*((guint32 *)patch_info->data.target), p, &p);
641 case MONO_PATCH_INFO_R8:
642 encode_value (*((guint32 *)patch_info->data.target), p, &p);
643 encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
645 case MONO_PATCH_INFO_VTABLE:
646 case MONO_PATCH_INFO_CLASS_INIT:
647 case MONO_PATCH_INFO_CLASS:
648 case MONO_PATCH_INFO_IID:
649 case MONO_PATCH_INFO_ADJUSTED_IID:
650 encode_klass_info (acfg, patch_info->data.klass, p, &p);
652 case MONO_PATCH_INFO_FIELD:
653 case MONO_PATCH_INFO_SFLDA:
654 encode_field_info (acfg, patch_info->data.field, p, &p);
656 case MONO_PATCH_INFO_WRAPPER: {
657 encode_value (patch_info->data.method->wrapper_type, p, &p);
659 switch (patch_info->data.method->wrapper_type) {
660 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
665 m = mono_marshal_method_from_wrapper (patch_info->data.method);
666 image_index = get_image_index (acfg, m->klass->image);
668 g_assert (image_index < 256);
669 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
671 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
674 case MONO_WRAPPER_PROXY_ISINST:
675 case MONO_WRAPPER_LDFLD:
676 case MONO_WRAPPER_LDFLDA:
677 case MONO_WRAPPER_STFLD:
678 case MONO_WRAPPER_LDFLD_REMOTE:
679 case MONO_WRAPPER_STFLD_REMOTE:
680 case MONO_WRAPPER_ISINST: {
681 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
682 encode_klass_info (acfg, proxy_class, p, &p);
685 case MONO_WRAPPER_STELEMREF:
688 g_assert_not_reached ();
693 g_warning ("unable to handle jump info %d", patch_info->type);
694 g_assert_not_reached ();
701 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
706 int i, j, pindex, buf_size, n_patches;
710 MonoJumpInfo *patch_info;
711 MonoMethodHeader *header;
712 guint32 last_offset, method_idx;
714 #ifdef MONO_ARCH_HAVE_PIC_AOT
715 guint32 first_got_offset;
719 method = cfg->method;
720 code = cfg->native_code;
721 header = mono_method_get_header (method);
723 method_idx = mono_metadata_token_index (method->token);
725 /* Make the labels local */
726 symbol = g_strdup_printf (".Lm_%x_p", method_idx);
728 /* Sort relocations */
729 patches = g_ptr_array_new ();
730 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
731 g_ptr_array_add (patches, patch_info);
732 g_ptr_array_sort (patches, compare_patches);
734 #ifdef MONO_ARCH_HAVE_PIC_AOT
735 first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
738 /**********************/
739 /* Encode method info */
740 /**********************/
742 buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
743 p = buf = g_malloc (buf_size);
745 if (mono_class_get_cctor (method->klass))
746 encode_klass_info (acfg, method->klass, p, &p);
748 /* Not needed when loading the method */
749 encode_value (0, p, &p);
752 if (cfg->opt & MONO_OPT_SHARED) {
753 encode_value (g_list_length (cfg->ldstr_list), p, &p);
754 for (l = cfg->ldstr_list; l; l = l->next) {
755 encode_value ((long)l->data, p, &p);
759 /* Used only in shared mode */
760 g_assert (!cfg->ldstr_list);
763 for (pindex = 0; pindex < patches->len; ++pindex) {
764 patch_info = g_ptr_array_index (patches, pindex);
766 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
767 (patch_info->type == MONO_PATCH_INFO_BB) ||
768 (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
769 (patch_info->type == MONO_PATCH_INFO_NONE)) {
770 patch_info->type = MONO_PATCH_INFO_NONE;
775 if ((patch_info->type == MONO_PATCH_INFO_IMAGE) && (patch_info->data.image == acfg->image)) {
776 /* Stored in GOT slot 0 */
777 patch_info->type = MONO_PATCH_INFO_NONE;
784 encode_value (n_patches, p, &p);
786 #ifdef MONO_ARCH_HAVE_PIC_AOT
788 encode_value (first_got_offset, p, &p);
791 /* First encode the type+position table */
794 for (pindex = 0; pindex < patches->len; ++pindex) {
796 patch_info = g_ptr_array_index (patches, pindex);
798 if (patch_info->type == MONO_PATCH_INFO_NONE)
803 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
804 offset = patch_info->ip.i - last_offset;
805 last_offset = patch_info->ip.i;
807 #if defined(MONO_ARCH_HAVE_PIC_AOT)
808 /* Only the type is needed */
809 *p = patch_info->type;
812 /* Encode type+position compactly */
813 g_assert (patch_info->type < 64);
814 if (offset < 1024 - 1) {
815 *p = (patch_info->type << 2) + (offset >> 8);
817 *p = offset & ((1 << 8) - 1);
821 *p = (patch_info->type << 2) + 3;
825 encode_value (offset, p, &p);
830 /* Then encode the other info */
831 for (pindex = 0; pindex < patches->len; ++pindex) {
832 patch_info = g_ptr_array_index (patches, pindex);
834 encode_patch (acfg, patch_info, p, &p);
837 acfg->info_size += p - buf;
839 /* Emit method info */
841 emit_label (tmpfp, symbol);
843 g_assert (p - buf < buf_size);
844 for (i = 0; i < p - buf; ++i) {
846 fprintf (tmpfp, "\n.byte ");
847 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
849 fprintf (tmpfp, "\n");
856 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
861 guint32 debug_info_size;
864 MonoMethodHeader *header;
865 guint8 *p, *buf, *debug_info;
868 method = cfg->method;
869 code = cfg->native_code;
870 header = mono_method_get_header (method);
872 /* Make the labels local */
873 symbol = g_strdup_printf (".Le_%x_p", mono_metadata_token_index (method->token));
875 buf_size = header->num_clauses * 256 + 128;
876 p = buf = g_malloc (buf_size);
878 encode_value (cfg->code_len, p, &p);
879 encode_value (cfg->used_int_regs, p, &p);
881 /* Exception table */
882 if (header->num_clauses) {
883 MonoJitInfo *jinfo = cfg->jit_info;
885 for (k = 0; k < header->num_clauses; ++k) {
886 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
888 encode_value (ei->exvar_offset, p, &p);
890 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
891 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
893 encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
894 encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
895 encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
899 mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
901 encode_value (debug_info_size, p, &p);
902 if (debug_info_size) {
903 memcpy (p, debug_info, debug_info_size);
904 p += debug_info_size;
908 acfg->ex_info_size += p - buf;
912 emit_label (tmpfp, symbol);
914 g_assert (p - buf < buf_size);
915 for (i = 0; i < p - buf; ++i) {
917 fprintf (tmpfp, "\n.byte ");
918 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
920 fprintf (tmpfp, "\n");
927 emit_klass_info (MonoAotCompile *acfg, guint32 token)
929 MonoClass *klass = mono_class_get (acfg->image, token);
933 FILE *tmpfp = acfg->fp;
934 gboolean no_special_static;
937 p = buf = g_malloc (buf_size);
941 mono_class_init (klass);
944 * Emit all the information which is required for creating vtables so
945 * the runtime does not need to create the MonoMethod structures which
946 * take up a lot of space.
949 no_special_static = !mono_class_has_special_static_fields (klass);
952 encode_value (klass->vtable_size, p, &p);
953 encode_value ((no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (klass->nested_classes ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
954 if (klass->has_cctor)
955 encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
956 if (klass->has_finalize)
957 encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
959 encode_value (klass->instance_size, p, &p);
960 encode_value (klass->class_size, p, &p);
961 encode_value (klass->packing_size, p, &p);
962 encode_value (klass->min_align, p, &p);
964 for (i = 0; i < klass->vtable_size; ++i) {
965 MonoMethod *cm = klass->vtable [i];
968 encode_method_ref (acfg, cm, p, &p);
970 encode_value (0, p, &p);
974 acfg->class_info_size += p - buf;
977 label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
978 emit_label (tmpfp, label);
980 g_assert (p - buf < buf_size);
981 for (i = 0; i < p - buf; ++i) {
983 fprintf (tmpfp, "\n.byte ");
984 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
986 fprintf (tmpfp, "\n");
991 * Calls made from AOTed code are routed through a table of jumps similar to the
992 * ELF PLT (Program Linkage Table). The differences are the following:
993 * - the ELF PLT entries make an indirect jump though the GOT so they expect the
994 * GOT pointer to the in EBX. We want to avoid this, so our table contains direct
995 * jumps. This means the jumps need to be patched when the address of the callee is
996 * known. Initially the PLT entries jump to code which transfer control to the
997 * AOT runtime through the first PLT entry.
1000 emit_plt (MonoAotCompile *acfg)
1005 guint32 *plt_info_offsets;
1007 fprintf (acfg->fp, "\n");
1008 symbol = g_strdup_printf ("plt");
1010 /* This section will be made read-write by the AOT loader */
1011 emit_section_change (acfg->fp, ".text", 0);
1012 emit_global (acfg->fp, symbol, TRUE);
1013 emit_alignment (acfg->fp, PAGESIZE);
1014 emit_label (acfg->fp, symbol);
1017 * The first plt entry is used to transfer code to the AOT loader. It is filled up
1018 * during loading by the AOT loader.
1020 emit_label (acfg->fp, ".Lp_0");
1021 for (i = 0; i < 16; ++i)
1022 fprintf (acfg->fp, "\t.long 0\n");
1024 for (i = 1; i < acfg->plt_offset; ++i) {
1027 label = g_strdup_printf (".Lp_%d", i);
1028 emit_label (acfg->fp, label);
1030 #if defined(__i386__) || defined (__x86_64__)
1031 /* Need to make sure this is 5 bytes long */
1032 fprintf (acfg->fp, "\t.byte 0xe9\n");
1033 fprintf (acfg->fp, "\t.long .Lpd_%d - . - 4\n", i);
1035 g_assert_not_reached ();
1039 symbol = g_strdup_printf ("plt_end");
1040 emit_global (acfg->fp, symbol, TRUE);
1041 emit_label (acfg->fp, symbol);
1044 * Encode info need to resolve PLT entries.
1046 buf_size = acfg->plt_offset * 128;
1047 p = buf = g_malloc (buf_size);
1049 plt_info_offsets = g_new0 (guint32, acfg->plt_offset);
1051 for (i = 1; i < acfg->plt_offset; ++i) {
1052 MonoJumpInfo *patch_info = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
1054 plt_info_offsets [i] = p - buf;
1055 encode_value (patch_info->type, p, &p);
1056 encode_patch (acfg, patch_info, p, &p);
1060 * Emit the default targets for the PLT entries separately since these will not
1061 * be modified at runtime.
1064 for (i = 1; i < acfg->plt_offset; ++i) {
1067 label = g_strdup_printf (".Lpd_%d", i);
1068 emit_label (acfg->fp, label);
1071 /* Put the offset into the register expected by mono_aot_plt_trampoline */
1072 #if defined(__i386__)
1073 fprintf (acfg->fp, "\tmovl $%d, %%eax\n", plt_info_offsets [i]);
1074 fprintf (acfg->fp, "\tjmp .Lp_0\n");
1075 #elif defined(__x86_64__)
1076 fprintf (acfg->fp, "\tpush $%d\n", plt_info_offsets [i]);
1077 fprintf (acfg->fp, "\tjmp .Lp_0\n");
1079 g_assert_not_reached ();
1084 symbol = g_strdup_printf ("plt_info");
1085 emit_global (acfg->fp, symbol, FALSE);
1086 emit_label (acfg->fp, symbol);
1088 g_assert (p - buf < buf_size);
1089 for (i = 0; i < p - buf; ++i) {
1091 fprintf (acfg->fp, "\n.byte ");
1092 fprintf (acfg->fp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
1094 fprintf (acfg->fp, "\n");
1099 str_begins_with (const char *str1, const char *str2)
1101 int len = strlen (str2);
1102 return strncmp (str1, str2, len) == 0;
1106 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1108 gchar **args, **ptr;
1110 memset (opts, 0, sizeof (*opts));
1112 args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1113 for (ptr = args; ptr && *ptr; ptr ++) {
1114 const char *arg = *ptr;
1116 if (str_begins_with (arg, "outfile=")) {
1117 opts->outfile = g_strdup (arg + strlen ("outfile="));
1118 } else if (str_begins_with (arg, "save-temps")) {
1119 opts->save_temps = TRUE;
1120 } else if (str_begins_with (arg, "write-symbols")) {
1121 opts->write_symbols = TRUE;
1123 fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1130 compile_method (MonoAotCompile *acfg, int index)
1134 MonoJumpInfo *patch_info;
1136 guint32 token = MONO_TOKEN_METHOD_DEF | (index + 1);
1138 method = mono_get_method (acfg->image, token, NULL);
1140 /* fixme: maybe we can also precompile wrapper methods */
1141 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1142 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1143 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1144 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1145 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1151 /* fixme: we need to patch the IP for the LMF in that case */
1152 if (method->save_lmf) {
1153 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
1159 * Since these methods are the only ones which are compiled with
1160 * AOT support, and they are not used by runtime startup/shutdown code,
1161 * the runtime will not see AOT methods during AOT compilation,so it
1162 * does not need to support them by creating a fake GOT etc.
1164 cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
1165 if (cfg->exception_type != MONO_EXCEPTION_NONE) {
1166 /* Let the exception happen at runtime */
1170 if (cfg->disable_aot) {
1171 //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1173 mono_destroy_compile (cfg);
1178 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1179 if (patch_info->type == MONO_PATCH_INFO_ABS) {
1180 /* unable to handle this */
1181 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1189 mono_destroy_compile (cfg);
1193 /* some wrappers are very common */
1194 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1195 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1196 switch (patch_info->data.method->wrapper_type) {
1197 case MONO_WRAPPER_PROXY_ISINST:
1198 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1202 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1203 switch (patch_info->data.method->wrapper_type) {
1204 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1205 case MONO_WRAPPER_STFLD:
1206 case MONO_WRAPPER_LDFLD:
1207 case MONO_WRAPPER_LDFLDA:
1208 case MONO_WRAPPER_LDFLD_REMOTE:
1209 case MONO_WRAPPER_STFLD_REMOTE:
1210 case MONO_WRAPPER_STELEMREF:
1211 case MONO_WRAPPER_ISINST:
1212 case MONO_WRAPPER_PROXY_ISINST:
1213 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1220 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1221 switch (patch_info->type) {
1222 case MONO_PATCH_INFO_METHOD:
1223 case MONO_PATCH_INFO_METHODCONST:
1224 if (patch_info->data.method->wrapper_type) {
1225 /* unable to handle this */
1226 //printf ("Skip (wrapper call): %s %d -> %s\n", mono_method_full_name (method, TRUE), patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
1230 if (!patch_info->data.method->token)
1232 * The method is part of a constructed type like Int[,].Set (). It doesn't
1233 * have a token, and we can't make one, since the parent type is part of
1234 * assembly which contains the element type, and not the assembly which
1235 * referenced this type.
1239 case MONO_PATCH_INFO_VTABLE:
1240 case MONO_PATCH_INFO_CLASS_INIT:
1241 case MONO_PATCH_INFO_CLASS:
1242 case MONO_PATCH_INFO_IID:
1243 case MONO_PATCH_INFO_ADJUSTED_IID:
1244 if (!patch_info->data.klass->type_token)
1245 if (!patch_info->data.klass->element_class->type_token)
1254 acfg->wrappercount++;
1255 mono_destroy_compile (cfg);
1259 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
1261 acfg->cfgs [index] = cfg;
1263 g_hash_table_insert (acfg->method_to_cfg, cfg->method, cfg);
1269 load_profile_files (MonoAotCompile *acfg)
1273 int file_index, res, method_index, i;
1279 tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
1281 if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
1284 infile = fopen (tmp, "r");
1287 printf ("Using profile data file '%s'\n", tmp);
1291 res = fscanf (infile, "%32s\n", ver);
1292 if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
1293 printf ("Profile file has wrong version or invalid.\n");
1298 res = fscanf (infile, "%d\n", &token);
1302 method_index = mono_metadata_token_index (token) - 1;
1304 if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
1305 acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
1309 /* Add missing methods */
1310 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1311 if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (i)))
1312 acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (i));
1317 emit_code (MonoAotCompile *acfg)
1323 symbol = g_strdup_printf ("methods");
1324 emit_section_change (acfg->fp, ".text", 0);
1325 emit_global (acfg->fp, symbol, TRUE);
1326 emit_alignment (acfg->fp, 8);
1327 emit_label (acfg->fp, symbol);
1329 for (l = acfg->method_order; l != NULL; l = l->next) {
1330 i = GPOINTER_TO_UINT (l->data);
1333 emit_method_code (acfg, acfg->cfgs [i]);
1336 symbol = g_strdup_printf ("methods_end");
1337 emit_section_change (acfg->fp, ".text", 0);
1338 emit_global (acfg->fp, symbol, FALSE);
1339 emit_alignment (acfg->fp, 8);
1340 emit_label (acfg->fp, symbol);
1342 symbol = g_strdup_printf ("method_offsets");
1343 emit_section_change (acfg->fp, ".text", 1);
1344 emit_global (acfg->fp, symbol, FALSE);
1345 emit_alignment (acfg->fp, 8);
1346 emit_label(acfg->fp, symbol);
1348 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1350 if ((i % 32) == 0) {
1351 fprintf (acfg->fp, "\n.long ");
1356 if (acfg->cfgs [i]) {
1357 symbol = g_strdup_printf (".Lm_%x", i + 1);
1358 fprintf (acfg->fp, "%s%s-methods", sep, symbol);
1361 fprintf (acfg->fp, "%s0xffffffff", sep);
1363 fprintf (acfg->fp, "\n");
1367 emit_info (MonoAotCompile *acfg)
1373 /* Emit method info */
1374 symbol = g_strdup_printf ("method_infos");
1375 emit_section_change (acfg->fp, ".text", 1);
1376 emit_global (acfg->fp, symbol, FALSE);
1377 emit_alignment (acfg->fp, 8);
1378 emit_label (acfg->fp, symbol);
1380 /* To reduce size of generated assembly code */
1381 symbol = g_strdup_printf ("mi");
1382 emit_label (acfg->fp, symbol);
1384 for (l = acfg->method_order; l != NULL; l = l->next) {
1385 i = GPOINTER_TO_UINT (l->data);
1388 emit_method_info (acfg, acfg->cfgs [i]);
1391 symbol = g_strdup_printf ("method_info_offsets");
1392 emit_section_change (acfg->fp, ".text", 1);
1393 emit_global (acfg->fp, symbol, FALSE);
1394 emit_alignment (acfg->fp, 8);
1395 emit_label(acfg->fp, symbol);
1397 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1399 if ((i % 32) == 0) {
1400 fprintf (acfg->fp, "\n.long ");
1405 if (acfg->cfgs [i]) {
1406 symbol = g_strdup_printf (".Lm_%x_p", i + 1);
1407 fprintf (acfg->fp, "%s%s - mi", sep, symbol);
1410 fprintf (acfg->fp, "%s0", sep);
1412 fprintf (acfg->fp, "\n");
1416 emit_method_order (MonoAotCompile *acfg)
1422 symbol = g_strdup_printf ("method_order");
1423 emit_section_change (acfg->fp, ".text", 1);
1424 emit_global (acfg->fp, symbol, FALSE);
1425 emit_alignment (acfg->fp, 8);
1426 emit_label(acfg->fp, symbol);
1428 /* First emit an index table */
1431 for (l = acfg->method_order; l != NULL; l = l->next) {
1432 i = GPOINTER_TO_UINT (l->data);
1434 if (acfg->cfgs [i]) {
1435 if ((index % 1024) == 0) {
1436 fprintf (acfg->fp, ".long %d\n", i);
1444 fprintf (acfg->fp, ".long 0xffffff\n");
1446 /* Then emit the whole method order */
1447 for (l = acfg->method_order; l != NULL; l = l->next) {
1448 i = GPOINTER_TO_UINT (l->data);
1450 if (acfg->cfgs [i]) {
1451 fprintf (acfg->fp, ".long %d\n", i);
1454 fprintf (acfg->fp, "\n");
1456 symbol = g_strdup_printf ("method_order_end");
1457 emit_section_change (acfg->fp, ".text", 1);
1458 emit_global (acfg->fp, symbol, FALSE);
1459 emit_label(acfg->fp, symbol);
1463 emit_exception_info (MonoAotCompile *acfg)
1468 symbol = g_strdup_printf ("ex_infos");
1469 emit_section_change (acfg->fp, ".text", 1);
1470 emit_global (acfg->fp, symbol, FALSE);
1471 emit_alignment (acfg->fp, 8);
1472 emit_label (acfg->fp, symbol);
1474 /* To reduce size of generate assembly */
1475 symbol = g_strdup_printf ("ex");
1476 emit_label (acfg->fp, symbol);
1478 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1480 emit_exception_debug_info (acfg, acfg->cfgs [i]);
1483 symbol = g_strdup_printf ("ex_info_offsets");
1484 emit_section_change (acfg->fp, ".text", 1);
1485 emit_global (acfg->fp, symbol, FALSE);
1486 emit_alignment (acfg->fp, 8);
1487 emit_label(acfg->fp, symbol);
1489 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1491 if ((i % 32) == 0) {
1492 fprintf (acfg->fp, "\n.long ");
1497 if (acfg->cfgs [i]) {
1498 symbol = g_strdup_printf (".Le_%x_p", i + 1);
1499 fprintf (acfg->fp, "%s%s - ex", sep, symbol);
1502 fprintf (acfg->fp, "%s0", sep);
1504 fprintf (acfg->fp, "\n");
1508 emit_class_info (MonoAotCompile *acfg)
1513 symbol = g_strdup_printf ("class_infos");
1514 emit_section_change (acfg->fp, ".text", 1);
1515 emit_global (acfg->fp, symbol, FALSE);
1516 emit_alignment (acfg->fp, 8);
1517 emit_label (acfg->fp, symbol);
1519 for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
1520 emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
1522 symbol = g_strdup_printf ("class_info_offsets");
1523 emit_section_change (acfg->fp, ".text", 1);
1524 emit_global (acfg->fp, symbol, FALSE);
1525 emit_alignment (acfg->fp, 8);
1526 emit_label(acfg->fp, symbol);
1528 for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
1530 if ((i % 32) == 0) {
1531 fprintf (acfg->fp, "\n.long ");
1537 symbol = g_strdup_printf (".LK_I_%x", i);
1538 fprintf (acfg->fp, "%s%s - class_infos", sep, symbol);
1540 fprintf (acfg->fp, "\n");
1544 emit_image_table (MonoAotCompile *acfg)
1550 * The image table is small but referenced in a lot of places.
1551 * So we emit it at once, and reference its elements by an index.
1554 symbol = g_strdup_printf ("mono_image_table");
1555 emit_section_change (acfg->fp, ".text", 1);
1556 emit_global(acfg->fp, symbol, FALSE);
1557 emit_alignment(acfg->fp, 8);
1558 emit_label(acfg->fp, symbol);
1559 fprintf (acfg->fp, ".long %d\n", acfg->image_table->len);
1560 for (i = 0; i < acfg->image_table->len; i++) {
1561 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
1562 MonoAssemblyName *aname = &image->assembly->aname;
1564 /* FIXME: Support multi-module assemblies */
1565 g_assert (image->assembly->image == image);
1567 fprintf (acfg->fp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
1568 fprintf (acfg->fp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
1569 fprintf (acfg->fp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
1570 fprintf (acfg->fp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
1572 emit_alignment (acfg->fp, 8);
1573 fprintf (acfg->fp, ".long %d\n", aname->flags);
1574 fprintf (acfg->fp, ".long %d\n", aname->major);
1575 fprintf (acfg->fp, ".long %d\n", aname->minor);
1576 fprintf (acfg->fp, ".long %d\n", aname->build);
1577 fprintf (acfg->fp, ".long %d\n", aname->revision);
1582 emit_got (MonoAotCompile *acfg)
1586 /* Don't make GOT global so accesses to it don't need relocations */
1587 symbol = g_strdup_printf ("got");
1588 emit_section_change (acfg->fp, ".bss", 1);
1589 emit_alignment (acfg->fp, 8);
1590 emit_label(acfg->fp, symbol);
1591 if (acfg->got_offset > 0)
1592 fprintf (acfg->fp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1594 symbol = g_strdup_printf ("got_addr");
1595 emit_section_change (acfg->fp, ".data", 1);
1596 emit_global (acfg->fp, symbol, FALSE);
1597 emit_alignment (acfg->fp, 8);
1598 emit_label(acfg->fp, symbol);
1599 emit_pointer (acfg->fp, "got");
1601 symbol = g_strdup_printf ("got_size");
1602 emit_section_change (acfg->fp, ".data", 1);
1603 emit_global (acfg->fp, symbol, FALSE);
1604 emit_alignment (acfg->fp, 8);
1605 emit_label(acfg->fp, symbol);
1606 fprintf (acfg->fp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1610 emit_globals (MonoAotCompile *acfg)
1614 emit_string_symbol (acfg->fp, "mono_assembly_guid" , acfg->image->guid);
1616 emit_string_symbol (acfg->fp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1618 opts_str = g_strdup_printf ("%d", acfg->opts);
1619 emit_string_symbol (acfg->fp, "mono_aot_opt_flags", opts_str);
1624 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1626 MonoImage *image = ass->image;
1627 char *command, *objfile, *tmpfname, *symbol;
1629 MonoAotCompile *acfg;
1631 char *outfile_name, *tmp_outfile_name;
1633 printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1635 acfg = g_new0 (MonoAotCompile, 1);
1636 acfg->plt_offset_to_patch = g_hash_table_new (NULL, NULL);
1637 acfg->patch_to_plt_offset = g_hash_table_new (NULL, NULL);
1638 acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
1639 acfg->image_hash = g_hash_table_new (NULL, NULL);
1640 acfg->image_table = g_ptr_array_new ();
1641 acfg->image = image;
1644 mono_aot_parse_options (aot_options, &acfg->aot_opts);
1646 load_profile_files (acfg);
1648 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1649 acfg->fp = fdopen (i, "w+");
1650 g_assert (acfg->fp);
1652 cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
1654 acfg->nmethods = image->tables [MONO_TABLE_METHOD].rows;
1655 acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
1657 /* Slot 0 is reserved for the address of the current assembly */
1658 acfg->got_offset = 1;
1659 /* PLT offset 0 is reserved for the PLT trampoline */
1660 acfg->plt_offset = 1;
1662 /* Compile methods */
1663 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i)
1664 compile_method (acfg, i);
1670 emit_method_order (acfg);
1672 emit_exception_info (acfg);
1674 emit_class_info (acfg);
1678 emit_image_table (acfg);
1680 #ifdef MONO_ARCH_HAVE_PIC_AOT
1684 emit_globals (acfg);
1686 symbol = g_strdup_printf ("mem_end");
1687 emit_section_change (acfg->fp, ".text", 1);
1688 emit_global (acfg->fp, symbol, FALSE);
1689 emit_alignment (acfg->fp, 8);
1690 emit_label(acfg->fp, symbol);
1694 printf ("Code: %d Info: %d Ex Info: %d Class Info: %d PLT: %d GOT: %d\n", acfg->code_size, acfg->info_size, acfg->ex_info_size, acfg->class_info_size, acfg->plt_offset, (int)(acfg->got_offset * sizeof (gpointer)));
1696 #if defined(__x86_64__)
1697 command = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
1698 #elif defined(sparc) && SIZEOF_VOID_P == 8
1699 command = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1701 command = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1704 printf ("Executing the native assembler: %s\n", command);
1705 if (system (command) != 0) {
1712 if (acfg->aot_opts.outfile)
1713 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
1715 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1717 tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1720 command = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1721 #elif defined(__ppc__) && defined(__MACH__)
1722 command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
1723 #elif defined(PLATFORM_WIN32)
1724 command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, tmpfname);
1726 command = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
1728 printf ("Executing the native linker: %s\n", command);
1729 if (system (command) != 0) {
1730 g_free (tmp_outfile_name);
1731 g_free (outfile_name);
1737 objfile = g_strdup_printf ("%s.o", tmpfname);
1740 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1741 printf ("Stripping the binary: %s\n", com);
1745 rename (tmp_outfile_name, outfile_name);
1747 g_free (tmp_outfile_name);
1748 g_free (outfile_name);
1750 printf ("Compiled %d out of %d methods (%d%%)\n", acfg->ccount, acfg->mcount, acfg->mcount ? (acfg->ccount*100)/acfg->mcount : 100);
1751 printf ("%d methods contain absolute addresses (%d%%)\n", acfg->abscount, acfg->mcount ? (acfg->abscount*100)/acfg->mcount : 100);
1752 printf ("%d methods contain wrapper references (%d%%)\n", acfg->wrappercount, acfg->mcount ? (acfg->wrappercount*100)/acfg->mcount : 100);
1753 printf ("%d methods contain lmf pointers (%d%%)\n", acfg->lmfcount, acfg->mcount ? (acfg->lmfcount*100)/acfg->mcount : 100);
1754 printf ("%d methods have other problems (%d%%)\n", acfg->ocount, acfg->mcount ? (acfg->ocount*100)/acfg->mcount : 100);
1755 if (acfg->aot_opts.save_temps)
1756 printf ("Retained input file.\n");
1768 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)