2007-06-22 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mono / mini / aot-compiler.c
1 /*
2  * aot.c: mono Ahead of Time compiler
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Zoltan Varga (vargaz@gmail.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include "config.h"
12 #include <sys/types.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <fcntl.h>
17 #include <string.h>
18 #ifndef PLATFORM_WIN32
19 #include <sys/mman.h>
20 #else
21 #include <winsock2.h>
22 #include <windows.h>
23 #endif
24
25 #include <errno.h>
26 #include <sys/stat.h>
27 #include <limits.h>    /* for PAGESIZE */
28 #ifndef PAGESIZE
29 #define PAGESIZE 4096
30 #endif
31
32 #include <mono/metadata/tabledefs.h>
33 #include <mono/metadata/class.h>
34 #include <mono/metadata/object.h>
35 #include <mono/metadata/tokentype.h>
36 #include <mono/metadata/appdomain.h>
37 #include <mono/metadata/debug-helpers.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/metadata-internals.h>
40 #include <mono/metadata/marshal.h>
41 #include <mono/utils/mono-logger.h>
42 #include "mono/utils/mono-compiler.h"
43
44 #include "mini.h"
45
46 #ifndef DISABLE_AOT
47
48 #ifdef PLATFORM_WIN32
49 #define SHARED_EXT ".dll"
50 #elif defined(__ppc__) && defined(__MACH__)
51 #define SHARED_EXT ".dylib"
52 #else
53 #define SHARED_EXT ".so"
54 #endif
55
56 #if defined(sparc) || defined(__ppc__)
57 #define AS_STRING_DIRECTIVE ".asciz"
58 #else
59 /* GNU as */
60 #define AS_STRING_DIRECTIVE ".string"
61 #endif
62
63 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
64 #define ROUND_DOWN(VALUE,SIZE)  ((VALUE) & ~((SIZE) - 1))
65
66 typedef struct MonoAotOptions {
67         char *outfile;
68         gboolean save_temps;
69         gboolean write_symbols;
70         gboolean metadata_only;
71 } MonoAotOptions;
72
73 typedef struct MonoAotStats {
74         int ccount, mcount, lmfcount, abscount, wrappercount, gcount, ocount, genericcount;
75         int code_size, info_size, ex_info_size, got_size, class_info_size, got_info_size, got_info_offsets_size;
76         int methods_without_got_slots, direct_calls, all_calls;
77         int got_slots;
78         int got_slot_types [MONO_PATCH_INFO_NONE];
79 } MonoAotStats;
80
81 /*#define USE_ELF_WRITER 1*/
82
83 #if defined(USE_ELF_WRITER)
84 #define USE_BIN_WRITER 1
85 #endif
86
87 #ifdef USE_BIN_WRITER
88
89 typedef struct _BinSymbol BinSymbol;
90 typedef struct _BinReloc BinReloc;
91 typedef struct _BinSection BinSection;
92
93 #else
94
95 /* emit mode */
96 enum {
97         EMIT_NONE,
98         EMIT_BYTE,
99         EMIT_WORD,
100         EMIT_LONG
101 };
102
103 #endif
104
105 typedef struct MonoAotCompile {
106         MonoImage *image;
107         MonoCompile **cfgs;
108         GHashTable *patch_to_plt_offset;
109         GHashTable *plt_offset_to_patch;
110         GHashTable *patch_to_shared_got_offset;
111         GPtrArray *shared_patches;
112         GHashTable *image_hash;
113         GHashTable *method_to_cfg;
114         GHashTable *token_info_hash;
115         GPtrArray *image_table;
116         GList *method_order;
117         guint32 got_offset, plt_offset;
118         guint32 *method_got_offsets;
119         gboolean *has_got_slots;
120         MonoAotOptions aot_opts;
121         guint32 nmethods;
122         guint32 opts;
123         MonoMemPool *mempool;
124         MonoAotStats stats;
125 #ifdef USE_BIN_WRITER
126         BinSymbol *symbols;
127         BinSection *sections;
128         BinSection *cur_section;
129         BinReloc *relocations;
130         GHashTable *labels;
131         int num_relocs;
132 #else
133         FILE *fp;
134         char *tmpfname;
135         int mode; /* emit mode */
136         int col_count; /* bytes emitted per .byte line */
137 #endif
138 } MonoAotCompile;
139
140 #ifdef HAVE_ARRAY_ELEM_INIT
141 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
142 #define MSGSTRFIELD1(line) str##line
143 static const struct msgstr_t {
144 #define PATCH_INFO(a,b) char MSGSTRFIELD(__LINE__) [sizeof (b)];
145 #include "patch-info.h"
146 #undef PATCH_INFO
147 } opstr = {
148 #define PATCH_INFO(a,b) b,
149 #include "patch-info.h"
150 #undef PATCH_INFO
151 };
152 static const gint16 opidx [] = {
153 #define PATCH_INFO(a,b) [MONO_PATCH_INFO_ ## a] = offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__)),
154 #include "patch-info.h"
155 #undef PATCH_INFO
156 };
157
158 static const char*
159 get_patch_name (int info)
160 {
161         return (const char*)&opstr + opidx [info];
162 }
163
164 #else
165 #define PATCH_INFO(a,b) b,
166 static const char* const
167 patch_types [MONO_PATCH_INFO_NUM + 1] = {
168 #include "patch-info.h"
169         NULL
170 };
171
172 static const char*
173 get_patch_name (int info)
174 {
175         return patch_types [info];
176 }
177
178 #endif
179
180 static gboolean 
181 is_got_patch (MonoJumpInfoType patch_type)
182 {
183 #ifdef __x86_64__
184         return TRUE;
185 #elif defined(__i386__)
186         return TRUE;
187 #else
188         return FALSE;
189 #endif
190 }
191
192 #if defined(__ppc__) && defined(__MACH__)
193 static int
194 ilog2(register int value)
195 {
196         int count = -1;
197         while (value & ~0xf) count += 4, value >>= 4;
198         while (value) count++, value >>= 1;
199         return count;
200 }
201 #endif
202
203 #ifdef USE_BIN_WRITER
204
205 typedef struct _BinLabel BinLabel;
206 struct _BinLabel {
207         char *name;
208         BinSection *section;
209         int offset;
210 };
211
212 struct _BinReloc {
213         BinReloc *next;
214         char *val1;
215         char *val2;
216         BinSection *val2_section;
217         int val2_offset;
218         int offset;
219         BinSection *section;
220         int section_offset;
221 };
222
223 struct _BinSymbol {
224         BinSymbol *next;
225         char *name;
226         BinSection *section;
227         int offset;
228         gboolean is_function;
229         gboolean is_global;
230 };
231
232 struct _BinSection {
233         BinSection *next;
234         BinSection *parent;
235         char *name;
236         int subsection;
237         guint8 *data;
238         int data_len;
239         int cur_offset;
240         int file_offset;
241         int virt_offset;
242         int shidx;
243 };
244
245 static void
246 emit_start (MonoAotCompile *acfg)
247 {
248         acfg->labels = g_hash_table_new (g_str_hash, g_str_equal);
249 }
250
251 static void
252 emit_section_change (MonoAotCompile *acfg, const char *section_name, int subsection_index)
253 {
254         BinSection *section;
255
256         if (acfg->cur_section && acfg->cur_section->subsection == subsection_index
257                         && strcmp (acfg->cur_section->name, section_name) == 0)
258                 return;
259         for (section = acfg->sections; section; section = section->next) {
260                 if (section->subsection == subsection_index && strcmp (section->name, section_name) == 0) {
261                         acfg->cur_section = section;
262                         return;
263                 }
264         }
265         if (!section) {
266                 section = g_new0 (BinSection, 1);
267                 section->name = g_strdup (section_name);
268                 section->subsection = subsection_index;
269                 section->next = acfg->sections;
270                 acfg->sections = section;
271                 acfg->cur_section = section;
272         }
273 }
274
275 static void
276 emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
277 {
278         BinSymbol *symbol = g_new0 (BinSymbol, 1);
279         symbol->name = g_strdup (name);
280         symbol->is_function = func;
281         symbol->is_global = TRUE;
282         symbol->section = acfg->cur_section;
283         /* FIXME: we align after this call... */
284         symbol->offset = symbol->section->cur_offset;
285         symbol->next = acfg->symbols;
286         acfg->symbols = symbol;
287 }
288
289 static void
290 emit_label (MonoAotCompile *acfg, const char *name)
291 {
292         BinLabel *label = g_new0 (BinLabel, 1);
293         label->name = g_strdup (name);
294         label->section = acfg->cur_section;
295         label->offset = acfg->cur_section->cur_offset;
296         g_hash_table_insert (acfg->labels, label->name, label);
297 }
298
299 static void
300 emit_ensure_buffer (BinSection *section, int size)
301 {
302         int new_offset = section->cur_offset + size;
303         if (new_offset >= section->data_len) {
304                 int new_size = section->data_len? section->data_len * 2: 256;
305                 guint8 *data;
306                 while (new_size <= new_offset)
307                         new_size *= 2;
308                 data = g_malloc0 (new_size);
309                 memcpy (data, section->data, section->data_len);
310                 g_free (section->data);
311                 section->data = data;
312                 section->data_len = new_size;
313         }
314 }
315
316 static void
317 emit_bytes (MonoAotCompile *acfg, const guint8* buf, int size)
318 {
319         emit_ensure_buffer (acfg->cur_section, size);
320         memcpy (acfg->cur_section->data + acfg->cur_section->cur_offset, buf, size);
321         acfg->cur_section->cur_offset += size;
322 }
323
324 static void
325 emit_string (MonoAotCompile *acfg, const char *value)
326 {
327         int size = strlen (value) + 1;
328         emit_bytes (acfg, (const guint8*)value, size);
329 }
330
331 static void
332 emit_line (MonoAotCompile *acfg)
333 {
334         /* Nothing to do in binary writer */
335 }
336
337 static void
338 emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
339 {
340         emit_section_change (acfg, ".text", 1);
341         emit_global (acfg, name, FALSE);
342         emit_label (acfg, name);
343         emit_string (acfg, value);
344 }
345
346 static void 
347 emit_alignment (MonoAotCompile *acfg, int size)
348 {
349         int offset = acfg->cur_section->cur_offset;
350         int add;
351         offset += (size - 1);
352         offset &= ~(size - 1);
353         add = offset - acfg->cur_section->cur_offset;
354         if (add) {
355                 emit_ensure_buffer (acfg->cur_section, add);
356                 acfg->cur_section->cur_offset += add;
357         }
358 }
359
360 static void
361 emit_pointer (MonoAotCompile *acfg, const char *target)
362 {
363         BinReloc *reloc;
364         emit_alignment (acfg, sizeof (gpointer));
365         reloc = g_new0 (BinReloc, 1);
366         reloc->val1 = g_strdup (target);
367         reloc->section = acfg->cur_section;
368         reloc->section_offset = acfg->cur_section->cur_offset;
369         reloc->next = acfg->relocations;
370         acfg->relocations = reloc;
371         if (strcmp (reloc->section->name, ".data") == 0) {
372                 acfg->num_relocs++;
373                 g_print ("reloc: %s at %d\n", target, acfg->cur_section->cur_offset);
374         }
375         acfg->cur_section->cur_offset += sizeof (gpointer);
376 }
377
378 static void
379 emit_int16 (MonoAotCompile *acfg, int value)
380 {
381         guint8 *data;
382         emit_ensure_buffer (acfg->cur_section, 2);
383         data = acfg->cur_section->data + acfg->cur_section->cur_offset;
384         acfg->cur_section->cur_offset += 2;
385         /* FIXME: little endian */
386         data [0] = value;
387         data [1] = value >> 8;
388 }
389
390 static void
391 emit_int32 (MonoAotCompile *acfg, int value)
392 {
393         guint8 *data;
394         emit_ensure_buffer (acfg->cur_section, 4);
395         data = acfg->cur_section->data + acfg->cur_section->cur_offset;
396         acfg->cur_section->cur_offset += 4;
397         /* FIXME: little endian */
398         data [0] = value;
399         data [1] = value >> 8;
400         data [2] = value >> 16;
401         data [3] = value >> 24;
402 }
403
404 static void
405 emit_symbol_diff (MonoAotCompile *acfg, const char *end, const char* start, int offset)
406 {
407         BinReloc *reloc;
408         reloc = g_new0 (BinReloc, 1);
409         reloc->val1 = g_strdup (end);
410         if (strcmp (start, ".") == 0) {
411                 reloc->val2_section = acfg->cur_section;
412                 reloc->val2_offset = acfg->cur_section->cur_offset;
413         } else {
414                 reloc->val2 = g_strdup (start);
415         }
416         reloc->offset = offset;
417         reloc->section = acfg->cur_section;
418         reloc->section_offset = acfg->cur_section->cur_offset;
419         reloc->next = acfg->relocations;
420         acfg->relocations = reloc;
421         acfg->cur_section->cur_offset += 4;
422         /*if (strcmp (reloc->section->name, ".data") == 0) {
423                 acfg->num_relocs++;
424                 g_print ("reloc: %s - %s + %d at %d\n", end, start, offset, acfg->cur_section->cur_offset - 4);
425         }*/
426 }
427
428 static void
429 emit_zero_bytes (MonoAotCompile *acfg, int num)
430 {
431         emit_ensure_buffer (acfg->cur_section, num);
432         acfg->cur_section->cur_offset += num;
433 }
434
435 #ifdef USE_ELF_WRITER
436 enum {
437         SYM_LOCAL = 0 << 4,
438         SYM_GLOBAL = 1 << 4,
439         SYM_OBJECT = 1,
440         SYM_FUNC = 2,
441         SYM_SECTION = 3
442 };
443
444 enum {
445         SECT_NULL,
446         SECT_HASH,
447         SECT_DYNSYM,
448         SECT_DYNSTR,
449         SECT_REL_DYN,
450         SECT_TEXT,
451         SECT_DYNAMIC,
452         SECT_GOT_PLT,
453         SECT_DATA,
454         SECT_BSS,
455         SECT_SHSTRTAB,
456         SECT_SYMTAB,
457         SECT_STRTAB,
458         SECT_NUM
459 };
460
461 enum {
462         DYN_HASH = 4,
463         DYN_STRTAB = 5,
464         DYN_SYMTAB = 6,
465         DYN_STRSZ = 10,
466         DYN_SYMENT = 11,
467         DYN_REL = 17,
468         DYN_RELSZ = 18,
469         DYN_RELENT = 19,
470         DYN_RELCOUNT = 0x6ffffffa
471 };
472
473 static const char* section_names [] = {
474         "",
475         ".hash",
476         ".dynsym",
477         ".dynstr",
478         ".rel.dyn",
479         ".text",
480         ".dynamic",
481         ".got.plt",
482         ".data",
483         ".bss",
484         ".shstrtab",
485         ".symtab",
486         ".strtab"
487 };
488
489 static const guint8 section_type [] = {
490         0, 5, 11, 3, 9, 1,
491         6, 1, 1, 8, 3, 2, 3
492 };
493
494 static const guint8 section_link [] = {
495         0, 2, 3, 0, 2, 0, 3, 0, 0, 0, 0, 12, 0
496 };
497
498 static const guint8 section_esize [] = {
499         0, 4, 16, 0, 8, 0, 8, 4, 0, 0, 0, 16, 0
500 };
501
502 static const guint8 section_flags [] = {
503         0, 2, 2, 2, 2, 6, 3, 3, 3, 3, 0, 0, 0
504 };
505
506 static const guint16 section_align [] = {
507         0, 4, 4, 1, 4, 4096, 4, 4, 8, 8, 1, 4, 1
508 };
509
510 struct ElfHeader {
511         guint8  e_ident [16];
512         guint16 e_type;
513         guint16 e_machine;
514         guint32 e_version;
515         gsize   e_entry;
516         gsize   e_phoff;
517         gsize   e_shoff;
518         guint32 e_flags;
519         guint16 e_ehsize;
520         guint16 e_phentsize;
521         guint16 e_phnum;
522         guint16 e_shentsize;
523         guint16 e_shnum;
524         guint16 e_shstrndx;
525 };
526
527 struct ElfSectHeader {
528         guint32 sh_name;
529         guint32 sh_type;
530         gsize   sh_flags;
531         gsize   sh_addr;
532         gsize   sh_offset;
533         gsize   sh_size;
534         guint32 sh_link;
535         guint32 sh_info;
536         gsize   sh_addralign;
537         gsize   sh_entsize;
538 };
539
540 #if SIZEOF_VOID_P == 4
541
542 struct ElfProgHeader {
543         guint32 p_type;
544         guint32 p_offset;
545         guint32 p_vaddr;
546         guint32 p_paddr;
547         guint32 p_filesz;
548         guint32 p_memsz;
549         guint32 p_flags;
550         guint32 p_align;
551 };
552
553 typedef struct {
554         guint32 st_name;
555         guint32 st_value;
556         guint32 st_size;
557         guint8  st_info;
558         guint8  st_other;
559         guint16 st_shndx;
560 } ElfSymbol;
561
562 typedef struct {
563         guint32 addr;
564         guint32 value;
565 } ElfReloc;
566
567 typedef struct {
568         guint32 d_tag;
569         guint32 d_val;
570 } ElfDynamic;
571
572 #else
573
574 struct ElfProgHeader {
575         guint32 p_type;
576         guint32 p_flags;
577         guint64 p_offset;
578         guint64 p_vaddr;
579         guint64 p_paddr;
580         guint64 p_filesz;
581         guint64 p_memsz;
582         guint64 p_align;
583 };
584
585 typedef struct {
586         guint32 st_name;
587         guint8  st_info;
588         guint8  st_other;
589         guint16 st_shndx;
590         guint64 st_value;
591         guint64 st_size;
592 } ElfSymbol;
593
594 typedef struct {
595         guint64 addr;
596         guint64 value;
597 } ElfReloc;
598
599 typedef struct {
600         guint64 addr;
601         guint64 value;
602         guint64 addend;
603 } ElfRelocA;
604
605 typedef struct {
606         guint64 d_tag;
607         guint64 d_val;
608 } ElfDynamic;
609
610 #endif
611
612 typedef struct {
613         GString *data;
614         GHashTable *hash;
615 } ElfStrTable;
616
617 static int
618 str_table_add (ElfStrTable *table, const char* value)
619 {
620         int idx;
621         if (!table->data) {
622                 table->data = g_string_new_len ("", 1);
623                 table->hash = g_hash_table_new (g_str_hash, g_str_equal);
624         }
625         idx = GPOINTER_TO_UINT (g_hash_table_lookup (table->hash, value));
626         if (idx)
627                 return idx;
628         idx = table->data->len;
629         g_string_append (table->data, value);
630         g_string_append_c (table->data, 0);
631         g_hash_table_insert (table->hash, (void*)value, GUINT_TO_POINTER (idx));
632         return idx;
633 }
634
635 static void
636 append_subsection (MonoAotCompile *acfg, struct ElfSectHeader *sheaders, BinSection *sect, BinSection *add)
637 {
638         int offset = sect->cur_offset;
639         /*offset += (sheaders [sect->shidx].sh_addralign - 1);
640         offset &= ~(sheaders [sect->shidx].sh_addralign - 1);*/
641         offset += (8 - 1);
642         offset &= ~(8 - 1);
643         emit_ensure_buffer (sect, offset);
644         g_print ("section %s aligned to %d from %d\n", sect->name, offset, sect->cur_offset);
645         sect->cur_offset = offset;
646
647         emit_ensure_buffer (sect, add->cur_offset);
648         memcpy (sect->data + sect->cur_offset, add->data, add->cur_offset);
649         add->parent = sect;
650         sect->cur_offset += add->cur_offset;
651         add->cur_offset = offset; /* it becomes the offset in the parent section */
652         g_print ("subsection %d of %s added at offset %d (align: %d)\n", add->subsection, sect->name, add->cur_offset, sheaders [sect->shidx].sh_addralign);
653         add->data = NULL;
654         add->data_len = 0;
655 }
656
657 /* merge the subsections */
658 static int
659 collect_sections (MonoAotCompile *acfg, struct ElfSectHeader *sheaders, BinSection **out, int num)
660 {
661         int i, j, maxs, num_sections;
662         BinSection *sect;
663
664         num_sections = 0;
665         maxs = 0;
666         for (sect = acfg->sections; sect; sect = sect->next) {
667                 if (sect->subsection == 0) {
668                         out [num_sections++] = sect;
669                         g_assert (num_sections < num);
670                         if (strcmp (sect->name, ".text") == 0) {
671                                 sect->shidx = SECT_TEXT;
672                         } else if (strcmp (sect->name, ".data") == 0) {
673                                 sect->shidx = SECT_DATA;
674                         } else if (strcmp (sect->name, ".bss") == 0) {
675                                 sect->shidx = SECT_BSS;
676                         }
677                 }
678                 maxs = MAX (maxs, sect->subsection);
679         }
680         for (i = 0; i < num_sections; i++) {
681                 for (j = 1; j <= maxs; ++j) {
682                         for (sect = acfg->sections; sect; sect = sect->next) {
683                                 if (sect->subsection == j && strcmp (out [i]->name, sect->name) == 0) {
684                                         append_subsection (acfg, sheaders, out [i], sect);
685                                 }
686                         }
687                 }
688         }
689         return num_sections;
690 }
691
692 static unsigned long
693 elf_hash (const unsigned char *name)
694 {
695         unsigned long h = 0, g;
696         while (*name) {
697                 h = (h << 4) + *name++;
698                 if ((g = h & 0xf0000000))
699                         h ^= g >> 24;
700                 h &= ~g;
701         }
702         return h;
703 }
704
705 #define NUM_BUCKETS 17
706
707 static int*
708 build_hash (MonoAotCompile *acfg, int num_sections, ElfStrTable *dynstr)
709 {
710         int *data;
711         int num_symbols = 1 + num_sections + 3;
712         BinSymbol *symbol;
713
714         for (symbol = acfg->symbols; symbol; symbol = symbol->next) {
715                 if (!symbol->is_global)
716                         continue;
717                 num_symbols++;
718                 str_table_add (dynstr, symbol->name);
719                 /*g_print ("adding sym: %s\n", symbol->name);*/
720         }
721         str_table_add (dynstr, "__bss_start");
722         str_table_add (dynstr, "_edata");
723         str_table_add (dynstr, "_end");
724
725         data = g_new0 (int, num_symbols + 2 + NUM_BUCKETS);
726         data [0] = NUM_BUCKETS;
727         data [1] = num_symbols;
728
729         return data;
730 }
731
732 static gsize
733 get_label_addr (MonoAotCompile *acfg, const char *name)
734 {
735         int offset;
736         BinLabel *lab;
737         BinSection *section;
738         gsize value;
739
740         lab = g_hash_table_lookup (acfg->labels, name);
741         section = lab->section;
742         offset = lab->offset;
743         if (section->parent) {
744                 value = section->parent->file_offset + section->cur_offset + offset;
745         } else {
746                 value = section->file_offset + offset;
747         }
748         return value;
749 }
750
751 static ElfSymbol*
752 collect_syms (MonoAotCompile *acfg, int *hash, ElfStrTable *strtab, struct ElfSectHeader *sheaders, int *num_syms)
753 {
754         ElfSymbol *symbols;
755         BinSymbol *symbol;
756         BinSection *section;
757         int i;
758         int *bucket;
759         int *chain;
760         unsigned long hashc;
761
762         if (hash)
763                 symbols = g_new0 (ElfSymbol, hash [1]);
764         else
765                 symbols = g_new0 (ElfSymbol, *num_syms + SECT_NUM + 10); /* FIXME */
766
767         /* the first symbol is undef, all zeroes */
768         i = 1;
769         if (sheaders) {
770                 int j;
771                 for (j = 1; j < SECT_NUM; ++j) {
772                         symbols [i].st_info = SYM_LOCAL | SYM_SECTION;
773                         symbols [i].st_shndx = j;
774                         symbols [i].st_value = sheaders [j].sh_addr;
775                         ++i;
776                 }
777         } else {
778                 for (section = acfg->sections; section; section = section->next) {
779                         if (section->parent)
780                                 continue;
781                         symbols [i].st_info = SYM_LOCAL | SYM_SECTION;
782                         if (strcmp (section->name, ".text") == 0) {
783                                 symbols [i].st_shndx = SECT_TEXT;
784                                 section->shidx = SECT_TEXT;
785                                 section->file_offset = 4096;
786                                 symbols [i].st_value = section->file_offset;
787                         } else if (strcmp (section->name, ".data") == 0) {
788                                 symbols [i].st_shndx = SECT_DATA;
789                                 section->shidx = SECT_DATA;
790                                 section->file_offset = 4096 + 28; /* FIXME */
791                                 symbols [i].st_value = section->file_offset;
792                         } else if (strcmp (section->name, ".bss") == 0) {
793                                 symbols [i].st_shndx = SECT_BSS;
794                                 section->shidx = SECT_BSS;
795                                 section->file_offset = 4096 + 28 + 8; /* FIXME */
796                                 symbols [i].st_value = section->file_offset;
797                         }
798                         ++i;
799                 }
800         }
801         for (symbol = acfg->symbols; symbol; symbol = symbol->next) {
802                 int offset;
803                 BinLabel *lab;
804                 if (!symbol->is_global)
805                         continue;
806                 symbols [i].st_info = (symbol->is_function? SYM_FUNC : SYM_OBJECT) | SYM_GLOBAL;
807                 symbols [i].st_name = str_table_add (strtab, symbol->name);
808                 /*g_print ("sym name %s tabled to %d\n", symbol->name, symbols [i].st_name);*/
809                 section = symbol->section;
810                 symbols [i].st_shndx = section->parent? section->parent->shidx: section->shidx;
811                 lab = g_hash_table_lookup (acfg->labels, symbol->name);
812                 offset = lab->offset;
813                 if (section->parent) {
814                         symbols [i].st_value = section->parent->file_offset + section->cur_offset + offset;
815                 } else {
816                         symbols [i].st_value = section->file_offset + offset;
817                 }
818                 ++i;
819         }
820         /* add special symbols */
821         symbols [i].st_name = str_table_add (strtab, "__bss_start");
822         symbols [i].st_shndx = 0xfff1;
823         symbols [i].st_info = SYM_GLOBAL;
824         ++i;
825         symbols [i].st_name = str_table_add (strtab, "_edata");
826         symbols [i].st_shndx = 0xfff1;
827         symbols [i].st_info = SYM_GLOBAL;
828         ++i;
829         symbols [i].st_name = str_table_add (strtab, "_end");
830         symbols [i].st_shndx = 0xfff1;
831         symbols [i].st_info = SYM_GLOBAL;
832         ++i;
833
834         if (num_syms)
835                 *num_syms = i;
836
837         /* add to hash table */
838         if (hash) {
839                 bucket = hash + 2;
840                 chain = hash + 2 + hash [0];
841                 for (i = 0; i < hash [1]; ++i) {
842                         int slot;
843                         /*g_print ("checking %d '%s' (sym %d)\n", symbols [i].st_name, strtab->data->str + symbols [i].st_name, i);*/
844                         if (!symbols [i].st_name)
845                                 continue;
846                         hashc = elf_hash ((guint8*)strtab->data->str + symbols [i].st_name);
847                         slot = hashc % hash [0];
848                         /*g_print ("hashing '%s' at slot %d (sym %d)\n", strtab->data->str + symbols [i].st_name, slot, i);*/
849                         if (bucket [slot]) {
850                                 chain [i] = bucket [slot];
851                                 bucket [slot] = i;
852                         } else {
853                                 bucket [slot] = i;
854                         }
855                 }
856         }
857         return symbols;
858 }
859
860 static void
861 reloc_symbols (MonoAotCompile *acfg, ElfSymbol *symbols, struct ElfSectHeader *sheaders, ElfStrTable *strtab, gboolean dynamic)
862 {
863         BinSection *section;
864         BinSymbol *symbol;
865         int i;
866
867         i = 1;
868         if (dynamic) {
869                 for (section = acfg->sections; section; section = section->next) {
870                         if (section->parent)
871                                 continue;
872                         symbols [i].st_value = sheaders [section->shidx].sh_addr;
873                         ++i;
874                 }
875         } else {
876                 for (i = 1; i < SECT_NUM; ++i) {
877                         symbols [i].st_value = sheaders [i].sh_addr;
878                 }
879         }
880         for (symbol = acfg->symbols; symbol; symbol = symbol->next) {
881                 int offset;
882                 BinLabel *lab;
883                 if (dynamic && !symbol->is_global)
884                         continue;
885                 section = symbol->section;
886                 lab = g_hash_table_lookup (acfg->labels, symbol->name);
887                 offset = lab->offset;
888                 if (section->parent) {
889                         symbols [i].st_value = sheaders [section->parent->shidx].sh_addr + section->cur_offset + offset;
890                 } else {
891                         symbols [i].st_value = sheaders [section->shidx].sh_addr + offset;
892                 }
893                 ++i;
894         }
895         /* __bss_start */
896         symbols [i].st_value = sheaders [SECT_BSS].sh_addr;
897         ++i;
898         /* _edata */
899         symbols [i].st_value = sheaders [SECT_DATA].sh_addr + sheaders [SECT_DATA].sh_size;
900         ++i;
901         /* _end */
902         symbols [i].st_value = sheaders [SECT_BSS].sh_addr + sheaders [SECT_BSS].sh_size;
903         ++i;
904 }
905
906 static ElfReloc*
907 resolve_relocations (MonoAotCompile *acfg)
908 {
909         BinReloc *reloc;
910         guint8 *data;
911         gsize end_val, start_val;
912         ElfReloc *rr;
913         int i;
914         gsize vaddr;
915
916         rr = g_new0 (ElfReloc, acfg->num_relocs);
917         i = 0;
918
919         for (reloc = acfg->relocations; reloc; reloc = reloc->next) {
920                 end_val = get_label_addr (acfg, reloc->val1);
921                 if (reloc->val2) {
922                         start_val = get_label_addr (acfg, reloc->val2);
923                 } else if (reloc->val2_section) {
924                         start_val = reloc->val2_offset;
925                         if (reloc->val2_section->parent)
926                                 start_val += reloc->val2_section->parent->file_offset + reloc->val2_section->cur_offset;
927                         else
928                                 start_val += reloc->val2_section->file_offset;
929                 } else {
930                         start_val = 0;
931                 }
932                 end_val = end_val - start_val + reloc->offset;
933                 if (reloc->section->parent) {
934                         data = reloc->section->parent->data;
935                         data += reloc->section->cur_offset;
936                         data += reloc->section_offset;
937                         vaddr = reloc->section->parent->file_offset;
938                         vaddr += reloc->section->cur_offset;
939                         vaddr += reloc->section_offset;
940                 } else {
941                         data = reloc->section->data;
942                         data += reloc->section_offset;
943                         vaddr = reloc->section->file_offset;
944                         vaddr += reloc->section_offset;
945                 }
946                 /* FIXME: little endian */
947                 data [0] = end_val;
948                 data [1] = end_val >> 8;
949                 data [2] = end_val >> 16;
950                 data [3] = end_val >> 24;
951                 if (start_val == 0) {
952                         rr [i].addr = vaddr;
953                         rr [i].value = 8; /* FIXME: 386_RELATIVE */
954                         ++i;
955                         g_assert (i <= acfg->num_relocs);
956                 }
957         }
958         return rr;
959 }
960
961 static void
962 emit_writeout (MonoAotCompile *acfg)
963 {
964         char *outfile_name, *tmp_outfile_name;
965         FILE *file;
966         struct ElfHeader header;
967         struct ElfProgHeader progh [3];
968         struct ElfSectHeader secth [SECT_NUM];
969         ElfReloc *relocs;
970         ElfStrTable str_table = {NULL, NULL};
971         ElfStrTable sh_str_table = {NULL, NULL};
972         ElfStrTable dyn_str_table = {NULL, NULL};
973         BinSection* sections [6];
974         BinSection *text_section = NULL, *data_section = NULL, *bss_section = NULL;
975         ElfSymbol *dynsym;
976         ElfSymbol *symtab;
977         ElfDynamic dynamic [14];
978         int *hash;
979         int i, num_sections, file_offset, virt_offset, size, num_symtab;
980         int num_local_syms;
981
982         if (acfg->aot_opts.outfile)
983                 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
984         else
985                 outfile_name = g_strdup_printf ("%s%s", acfg->image->name, SHARED_EXT);
986
987         tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
988
989         unlink (tmp_outfile_name);
990         file = fopen (tmp_outfile_name, "w");
991         g_assert (file);
992
993         /* Section headers */
994         memset (&secth, 0, sizeof (secth));
995         memset (&dynamic, 0, sizeof (dynamic));
996         memset (&header, 0, sizeof (header));
997
998         for (i = 1; i < SECT_NUM; ++i) {
999                 secth [i].sh_name = str_table_add (&sh_str_table, section_names [i]);
1000                 secth [i].sh_type = section_type [i];
1001                 secth [i].sh_link = section_link [i];
1002                 secth [i].sh_addralign = section_align [i];
1003                 secth [i].sh_flags = section_flags [i];
1004                 secth [i].sh_entsize = section_esize [i];
1005         }
1006         secth [SECT_DYNSYM].sh_info = 4;
1007         secth [SECT_SYMTAB].sh_info = 20;
1008
1009         num_sections = collect_sections (acfg, secth, sections, 6);
1010         hash = build_hash (acfg, num_sections, &dyn_str_table);
1011         num_symtab = hash [1]; /* FIXME */
1012         g_print ("num_sections: %d\n", num_sections);
1013         g_print ("dynsym: %d, dynstr size: %d\n", hash [1], dyn_str_table.data->len);
1014         for (i = 0; i < num_sections; ++i) {
1015                 g_print ("section %s, size: %d, %x\n", sections [i]->name, sections [i]->cur_offset, sections [i]->cur_offset);
1016         }
1017
1018         /* at this point we know where in the file the first segment sections go */
1019         dynsym = collect_syms (acfg, hash, &dyn_str_table, NULL, NULL);
1020         num_local_syms = hash [1];
1021         symtab = collect_syms (acfg, NULL, &str_table, secth, &num_local_syms);
1022
1023         for (i = 0; i < num_sections; ++i) {
1024                 if (sections [i]->shidx == SECT_TEXT) {
1025                         text_section = sections [i];
1026                 } else if (sections [i]->shidx == SECT_DATA) {
1027                         data_section = sections [i];
1028                 } else if (sections [i]->shidx == SECT_BSS) {
1029                         bss_section = sections [i];
1030                 }
1031         }
1032
1033         file_offset = virt_offset = sizeof (header) + sizeof (progh);
1034         secth [SECT_HASH].sh_addr = secth [SECT_HASH].sh_offset = file_offset;
1035         size = sizeof (int) * (2 + hash [0] + hash [1]);
1036         virt_offset = (file_offset += size);
1037         secth [SECT_HASH].sh_size = size;
1038         secth [SECT_DYNSYM].sh_addr = secth [SECT_DYNSYM].sh_offset = file_offset;
1039         size = sizeof (ElfSymbol) * hash [1];
1040         virt_offset = (file_offset += size);
1041         secth [SECT_DYNSYM].sh_size = size;
1042         secth [SECT_DYNSTR].sh_addr = secth [SECT_DYNSTR].sh_offset = file_offset;
1043         size = dyn_str_table.data->len;
1044         virt_offset = (file_offset += size);
1045         secth [SECT_DYNSTR].sh_size = size;
1046         file_offset += 4-1;
1047         file_offset &= ~(4-1);
1048         secth [SECT_REL_DYN].sh_addr = secth [SECT_REL_DYN].sh_offset = file_offset;
1049         size = sizeof (ElfReloc) * acfg->num_relocs;
1050         secth [SECT_REL_DYN].sh_size = size;
1051         virt_offset = (file_offset += size);
1052         secth [SECT_REL_DYN].sh_size = size;
1053         file_offset += 4096-1;
1054         file_offset &= ~(4096-1);
1055         virt_offset = file_offset;
1056         secth [SECT_TEXT].sh_addr = secth [SECT_TEXT].sh_offset = file_offset;
1057         size = text_section->cur_offset;
1058         secth [SECT_TEXT].sh_size = size;
1059         file_offset += size;
1060         file_offset += 4-1;
1061         file_offset &= ~(4-1);
1062         virt_offset = file_offset;
1063         /* .dynamic, .got.plt, .data, .bss here */
1064         secth [SECT_DYNAMIC].sh_addr = virt_offset;
1065         secth [SECT_DYNAMIC].sh_offset = file_offset;
1066         size = sizeof (dynamic);
1067         secth [SECT_DYNAMIC].sh_size = size;
1068         size += 4-1;
1069         size &= ~(4-1);
1070         file_offset += size;
1071         virt_offset += size;
1072         secth [SECT_GOT_PLT].sh_addr = virt_offset;
1073         secth [SECT_GOT_PLT].sh_offset = file_offset;
1074         size = 12;
1075         secth [SECT_GOT_PLT].sh_size = size;
1076         size += 8-1;
1077         size &= ~(8-1);
1078         file_offset += size;
1079         virt_offset += size;
1080         secth [SECT_DATA].sh_addr = virt_offset;
1081         secth [SECT_DATA].sh_offset = file_offset;
1082         size = data_section->cur_offset;
1083         secth [SECT_DATA].sh_size = size;
1084         size += 8-1;
1085         size &= ~(8-1);
1086         file_offset += size;
1087         virt_offset += size;
1088         secth [SECT_BSS].sh_addr = virt_offset;
1089         secth [SECT_BSS].sh_offset = file_offset;
1090         size = bss_section->cur_offset;
1091         secth [SECT_BSS].sh_size = size;
1092
1093         /* virtual doesn't matter anymore */
1094         secth [SECT_SHSTRTAB].sh_offset = file_offset;
1095         size = sh_str_table.data->len;
1096         secth [SECT_SHSTRTAB].sh_size = size;
1097         size += 4-1;
1098         size &= ~(4-1);
1099         file_offset += size;
1100         secth [SECT_SYMTAB].sh_offset = file_offset;
1101         size = sizeof (ElfSymbol) * num_local_syms;
1102         secth [SECT_SYMTAB].sh_size = size;
1103         file_offset += size;
1104         secth [SECT_STRTAB].sh_offset = file_offset;
1105         size = str_table.data->len;
1106         secth [SECT_STRTAB].sh_size = size;
1107         file_offset += size;
1108         file_offset += 4-1;
1109         file_offset &= ~(4-1);
1110
1111         text_section->file_offset = secth [SECT_TEXT].sh_offset;
1112         data_section->file_offset = secth [SECT_DATA].sh_offset;
1113         bss_section->file_offset = secth [SECT_BSS].sh_offset;
1114
1115         header.e_ident [0] = 0x7f; header.e_ident [1] = 'E';
1116         header.e_ident [2] = 'L'; header.e_ident [3] = 'F';
1117         header.e_ident [4] = SIZEOF_VOID_P == 4? 1: 2;
1118         header.e_ident [5] = 1; /* FIXME: little endian, bigendian is 2 */
1119         header.e_ident [6] = 1; /* version */
1120         header.e_ident [7] = 0; /* FIXME: */
1121         header.e_ident [8] = 0; /* FIXME: */
1122         for (i = 9; i < 16; ++i)
1123                 header.e_ident [i] = 0;
1124
1125         header.e_type = 3; /* shared library */
1126         header.e_machine = 3; /* FIXME: 386 */
1127         header.e_version = 1; /* FIXME:  */
1128
1129         header.e_phoff = sizeof (header);
1130         header.e_ehsize = sizeof (header);
1131         header.e_phentsize = sizeof (struct ElfProgHeader);
1132         header.e_phnum = 3;
1133         header.e_entry = secth [SECT_TEXT].sh_addr;
1134         header.e_shstrndx = 10;
1135         header.e_shentsize = sizeof (struct ElfSectHeader);
1136         header.e_shnum = SECT_NUM;
1137         header.e_shoff = file_offset;
1138
1139         /* dynamic data */
1140         i = 0;
1141         dynamic [i].d_tag = DYN_HASH;
1142         dynamic [i].d_val = secth [SECT_HASH].sh_offset;
1143         ++i;
1144         dynamic [i].d_tag = DYN_STRTAB;
1145         dynamic [i].d_val = secth [SECT_DYNSTR].sh_offset;
1146         ++i;
1147         dynamic [i].d_tag = DYN_SYMTAB;
1148         dynamic [i].d_val = secth [SECT_DYNSYM].sh_offset;
1149         ++i;
1150         dynamic [i].d_tag = DYN_STRSZ;
1151         dynamic [i].d_val = dyn_str_table.data->len;
1152         ++i;
1153         dynamic [i].d_tag = DYN_SYMENT;
1154         dynamic [i].d_val = sizeof (ElfSymbol);
1155         ++i;
1156         dynamic [i].d_tag = DYN_REL;
1157         dynamic [i].d_val = secth [SECT_REL_DYN].sh_offset;
1158         ++i;
1159         dynamic [i].d_tag = DYN_RELSZ;
1160         dynamic [i].d_val = secth [SECT_REL_DYN].sh_size;
1161         ++i;
1162         dynamic [i].d_tag = DYN_RELENT;
1163         dynamic [i].d_val = sizeof (ElfReloc);
1164         ++i;
1165         dynamic [i].d_tag = DYN_RELCOUNT;
1166         dynamic [i].d_val = acfg->num_relocs;
1167         ++i;
1168
1169         /* Program header */
1170         memset (&progh, 0, sizeof (progh));
1171         progh [0].p_type = 1; /* LOAD */
1172         progh [0].p_filesz = progh [0].p_memsz = secth [SECT_DYNAMIC].sh_offset;
1173         progh [0].p_align = 4096;
1174         progh [0].p_flags = 5;
1175
1176         progh [1].p_type = 1;
1177         progh [1].p_offset = secth [SECT_DYNAMIC].sh_offset;
1178         progh [1].p_vaddr = progh [1].p_paddr = secth [SECT_DYNAMIC].sh_addr;
1179         progh [1].p_filesz = secth [SECT_BSS].sh_offset  - secth [SECT_DYNAMIC].sh_offset;
1180         progh [1].p_memsz = secth [SECT_BSS].sh_addr + secth [SECT_BSS].sh_size - secth [SECT_DYNAMIC].sh_addr;
1181         progh [1].p_align = 4096;
1182         progh [1].p_flags = 6;
1183
1184         progh [2].p_type = 2; /* DYNAMIC */
1185         progh [2].p_offset = secth [SECT_DYNAMIC].sh_offset;
1186         progh [2].p_vaddr = progh [2].p_paddr = secth [SECT_DYNAMIC].sh_addr;
1187         progh [2].p_filesz = progh [2].p_memsz = secth [SECT_DYNAMIC].sh_size;
1188         progh [2].p_align = 4;
1189         progh [2].p_flags = 6;
1190
1191         reloc_symbols (acfg, dynsym, secth, &dyn_str_table, TRUE);
1192         reloc_symbols (acfg, symtab, secth, &str_table, FALSE);
1193         relocs = resolve_relocations (acfg);
1194
1195         fwrite (&header, sizeof (header), 1, file);
1196         fwrite (&progh, sizeof (progh), 1, file);
1197         fwrite (hash, sizeof (int) * (hash [0] + hash [1] + 2), 1, file);
1198         fwrite (dynsym, sizeof (ElfSymbol) * hash [1], 1, file);
1199         fwrite (dyn_str_table.data->str, dyn_str_table.data->len, 1, file);
1200         /* .rel.dyn */
1201         fseek (file, secth [SECT_REL_DYN].sh_offset, SEEK_SET);
1202         fwrite (relocs, sizeof (ElfReloc), acfg->num_relocs, file);
1203
1204         fseek (file, secth [SECT_TEXT].sh_offset, SEEK_SET);
1205         /* write .text, .data, .bss sections */
1206         fwrite (text_section->data, text_section->cur_offset, 1, file);
1207
1208         /* .dynamic */
1209         fwrite (dynamic, sizeof (dynamic), 1, file);
1210         /* .got.plt */
1211         size = secth [SECT_DYNAMIC].sh_addr;
1212         fwrite (&size, sizeof (size), 1, file);
1213         fseek (file, secth [SECT_DATA].sh_offset, SEEK_SET);
1214         fwrite (data_section->data, data_section->cur_offset, 1, file);
1215
1216         fseek (file, secth [SECT_SHSTRTAB].sh_offset, SEEK_SET);
1217         fwrite (sh_str_table.data->str, sh_str_table.data->len, 1, file);
1218         fseek (file, secth [SECT_SYMTAB].sh_offset, SEEK_SET);
1219         fwrite (symtab, sizeof (ElfSymbol) * num_local_syms, 1, file);
1220         fseek (file, secth [SECT_STRTAB].sh_offset, SEEK_SET);
1221         fwrite (str_table.data->str, str_table.data->len, 1, file);
1222         /*g_print ("file_offset %d vs %d\n", file_offset, ftell (file));*/
1223         /*g_assert (file_offset >= ftell (file));*/
1224         fseek (file, file_offset, SEEK_SET);
1225         fwrite (&secth, sizeof (secth), 1, file);
1226         fclose (file);
1227         rename (tmp_outfile_name, outfile_name);
1228
1229         g_free (tmp_outfile_name);
1230         g_free (outfile_name);
1231 }
1232
1233 #endif /* USE_ELF_WRITER */
1234
1235 #else
1236
1237 static void
1238 emit_start (MonoAotCompile *acfg)
1239 {
1240         int i = g_file_open_tmp ("mono_aot_XXXXXX", &acfg->tmpfname, NULL);
1241         acfg->fp = fdopen (i, "w+");
1242         g_assert (acfg->fp);
1243 }
1244
1245 static void
1246 emit_unset_mode (MonoAotCompile *acfg)
1247 {
1248         if (acfg->mode == EMIT_NONE)
1249                 return;
1250         fprintf (acfg->fp, "\n");
1251         acfg->mode = EMIT_NONE;
1252 }
1253
1254 static void
1255 emit_section_change (MonoAotCompile *acfg, const char *section_name, int subsection_index)
1256 {
1257         emit_unset_mode (acfg);
1258 #if defined(PLATFORM_WIN32)
1259         fprintf (acfg->fp, ".section %s\n", section_name);
1260 #elif defined(sparc)
1261         /* For solaris as, GNU as should accept the same */
1262         fprintf (acfg->fp, ".section \"%s\"\n", section_name);
1263 #elif defined(__ppc__) && defined(__MACH__)
1264         /* This needs to be made more precise on mach. */
1265         fprintf (acfg->fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1266 #else
1267         fprintf (acfg->fp, "%s %d\n", section_name, subsection_index);
1268 #endif
1269 }
1270
1271 static void
1272 emit_symbol_type (MonoAotCompile *acfg, const char *name, gboolean func)
1273 {
1274         const char *stype;
1275
1276         if (func)
1277                 stype = "function";
1278         else
1279                 stype = "object";
1280
1281         emit_unset_mode (acfg);
1282 #if defined(sparc)
1283         fprintf (acfg->fp, "\t.type %s,#%s\n", name, stype);
1284 #elif defined(PLATFORM_WIN32)
1285
1286 #elif !(defined(__ppc__) && defined(__MACH__))
1287         fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
1288 #elif defined(__x86_64__) || defined(__i386__)
1289         fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
1290 #endif
1291 }
1292
1293 static void
1294 emit_global (MonoAotCompile *acfg, const char *name, gboolean func)
1295 {
1296         emit_unset_mode (acfg);
1297 #if  (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1298     // mach-o always uses a '_' prefix.
1299         fprintf (acfg->fp, "\t.globl _%s\n", name);
1300 #else
1301         fprintf (acfg->fp, "\t.globl %s\n", name);
1302 #endif
1303
1304         emit_symbol_type (acfg, name, func);
1305 }
1306
1307 static void
1308 emit_label (MonoAotCompile *acfg, const char *name)
1309 {
1310         emit_unset_mode (acfg);
1311 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1312     // mach-o always uses a '_' prefix.
1313         fprintf (acfg->fp, "_%s:\n", name);
1314 #else
1315         fprintf (acfg->fp, "%s:\n", name);
1316 #endif
1317
1318 #if defined(PLATFORM_WIN32)
1319         /* Emit a normal label too */
1320         fprintf (acfg->fp, "%s:\n", name);
1321 #endif
1322 }
1323
1324 static void
1325 emit_string (MonoAotCompile *acfg, const char *value)
1326 {
1327         emit_unset_mode (acfg);
1328         fprintf (acfg->fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1329 }
1330
1331 static void
1332 emit_line (MonoAotCompile *acfg)
1333 {
1334         emit_unset_mode (acfg);
1335         fprintf (acfg->fp, "\n");
1336 }
1337
1338 static void
1339 emit_string_symbol (MonoAotCompile *acfg, const char *name, const char *value)
1340 {
1341         emit_unset_mode (acfg);
1342         emit_section_change (acfg, ".text", 1);
1343         emit_global (acfg, name, FALSE);
1344         emit_label (acfg, name);
1345         emit_string (acfg, value);
1346 }
1347
1348 static void 
1349 emit_alignment (MonoAotCompile *acfg, int size)
1350 {
1351         emit_unset_mode (acfg);
1352 #if defined(__ppc__) && defined(__MACH__)
1353         // the mach-o assembler specifies alignments as powers of 2.
1354         fprintf (acfg->fp, "\t.align %d\t; ilog2\n", ilog2(size));
1355 #elif defined(__powerpc__)
1356         /* ignore on linux/ppc */
1357 #else
1358         fprintf (acfg->fp, "\t.align %d\n", size);
1359 #endif
1360 }
1361
1362 static void
1363 emit_pointer (MonoAotCompile *acfg, const char *target)
1364 {
1365         emit_unset_mode (acfg);
1366         emit_alignment (acfg, sizeof (gpointer));
1367 #if defined(__x86_64__)
1368         fprintf (acfg->fp, "\t.quad %s\n", target);
1369 #elif defined(sparc) && SIZEOF_VOID_P == 8
1370         fprintf (acfg->fp, "\t.xword %s\n", target);
1371 #else
1372         fprintf (acfg->fp, "\t.long %s\n", target);
1373 #endif
1374 }
1375
1376 static void
1377 emit_bytes (MonoAotCompile *acfg, const guint8* buf, int size)
1378 {
1379         int i;
1380         if (acfg->mode != EMIT_BYTE) {
1381                 acfg->mode = EMIT_BYTE;
1382                 acfg->col_count = 0;
1383         }
1384         for (i = 0; i < size; ++i, ++acfg->col_count) {
1385                 if ((acfg->col_count % 32) == 0)
1386                         fprintf (acfg->fp, "\n\t.byte ");
1387                 else
1388                         fprintf (acfg->fp, ", ");
1389                 fprintf (acfg->fp, "0x%x", buf [i]);
1390         }
1391 }
1392
1393 static inline void
1394 emit_int16 (MonoAotCompile *acfg, int value)
1395 {
1396         if (acfg->mode != EMIT_WORD) {
1397                 acfg->mode = EMIT_WORD;
1398                 acfg->col_count = 0;
1399         }
1400         if ((acfg->col_count++ % 8) == 0)
1401                 fprintf (acfg->fp, "\n\t.word ");
1402         else
1403                 fprintf (acfg->fp, ", ");
1404         fprintf (acfg->fp, "%d", value);
1405 }
1406
1407 static inline void
1408 emit_int32 (MonoAotCompile *acfg, int value)
1409 {
1410         if (acfg->mode != EMIT_LONG) {
1411                 acfg->mode = EMIT_LONG;
1412                 acfg->col_count = 0;
1413         }
1414         if ((acfg->col_count++ % 8) == 0)
1415                 fprintf (acfg->fp, "\n\t.long ");
1416         else
1417                 fprintf (acfg->fp, ", ");
1418         fprintf (acfg->fp, "%d", value);
1419 }
1420
1421 static void
1422 emit_symbol_diff (MonoAotCompile *acfg, const char *end, const char* start, int offset)
1423 {
1424         if (acfg->mode != EMIT_LONG) {
1425                 acfg->mode = EMIT_LONG;
1426                 acfg->col_count = 0;
1427         }
1428         if ((acfg->col_count++ % 8) == 0)
1429                 fprintf (acfg->fp, "\n\t.long ");
1430         else
1431                 fprintf (acfg->fp, ", ");
1432         if (offset)
1433                 fprintf (acfg->fp, "%s - %s %c %d", end, start, offset < 0? ' ': '+', offset);
1434         else
1435                 fprintf (acfg->fp, "%s - %s", end, start);
1436 }
1437
1438 static void
1439 emit_zero_bytes (MonoAotCompile *acfg, int num)
1440 {
1441         emit_unset_mode (acfg);
1442         fprintf (acfg->fp, "\t.skip %d\n", num);
1443 }
1444
1445 static void
1446 emit_writeout (MonoAotCompile *acfg)
1447 {
1448         char *command, *objfile;
1449         char *outfile_name, *tmp_outfile_name;
1450
1451         fclose (acfg->fp);
1452
1453 #if defined(__x86_64__)
1454 #define AS_OPTIONS "--64"
1455 #elif defined(sparc) && SIZEOF_VOID_P == 8
1456 #define AS_OPTIONS "-xarch=v9"
1457 #else
1458 #define AS_OPTIONS ""
1459 #endif
1460         command = g_strdup_printf ("as %s %s -o %s.o", AS_OPTIONS, acfg->tmpfname, acfg->tmpfname);
1461         printf ("Executing the native assembler: %s\n", command);
1462         if (system (command) != 0) {
1463                 g_free (command);
1464                 return;
1465         }
1466
1467         g_free (command);
1468
1469         if (acfg->aot_opts.outfile)
1470                 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
1471         else
1472                 outfile_name = g_strdup_printf ("%s%s", acfg->image->name, SHARED_EXT);
1473
1474         tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1475
1476 #if defined(sparc)
1477         command = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, acfg->tmpfname);
1478 #elif defined(__ppc__) && defined(__MACH__)
1479         command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, acfg->tmpfname);
1480 #elif defined(PLATFORM_WIN32)
1481         command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, acfg->tmpfname);
1482 #else
1483         command = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, acfg->tmpfname);
1484 #endif
1485         printf ("Executing the native linker: %s\n", command);
1486         if (system (command) != 0) {
1487                 g_free (tmp_outfile_name);
1488                 g_free (outfile_name);
1489                 g_free (command);
1490                 return;
1491         }
1492
1493         g_free (command);
1494         objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
1495         unlink (objfile);
1496         g_free (objfile);
1497         /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, SHARED_EXT);
1498         printf ("Stripping the binary: %s\n", com);
1499         system (com);
1500         g_free (com);*/
1501
1502         rename (tmp_outfile_name, outfile_name);
1503
1504         g_free (tmp_outfile_name);
1505         g_free (outfile_name);
1506
1507         if (acfg->aot_opts.save_temps)
1508                 printf ("Retained input file.\n");
1509         else
1510                 unlink (acfg->tmpfname);
1511
1512 }
1513
1514 #endif /* ASM_WRITER */
1515
1516 static void
1517 emit_byte (MonoAotCompile *acfg, guint8 val)
1518 {
1519         emit_bytes (acfg, &val, 1);
1520 }
1521
1522 static guint32
1523 mono_get_field_token (MonoClassField *field) 
1524 {
1525         MonoClass *klass = field->parent;
1526         int i;
1527
1528         for (i = 0; i < klass->field.count; ++i) {
1529                 if (field == &klass->fields [i])
1530                         return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1531         }
1532
1533         g_assert_not_reached ();
1534         return 0;
1535 }
1536
1537 static inline void
1538 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
1539 {
1540         guint8 *p = buf;
1541
1542         //printf ("ENCODE: %d 0x%x.\n", value, value);
1543
1544         /* 
1545          * Same encoding as the one used in the metadata, extended to handle values
1546          * greater than 0x1fffffff.
1547          */
1548         if ((value >= 0) && (value <= 127))
1549                 *p++ = value;
1550         else if ((value >= 0) && (value <= 16383)) {
1551                 p [0] = 0x80 | (value >> 8);
1552                 p [1] = value & 0xff;
1553                 p += 2;
1554         } else if ((value >= 0) && (value <= 0x1fffffff)) {
1555                 p [0] = (value >> 24) | 0xc0;
1556                 p [1] = (value >> 16) & 0xff;
1557                 p [2] = (value >> 8) & 0xff;
1558                 p [3] = value & 0xff;
1559                 p += 4;
1560         }
1561         else {
1562                 p [0] = 0xff;
1563                 p [1] = (value >> 24) & 0xff;
1564                 p [2] = (value >> 16) & 0xff;
1565                 p [3] = (value >> 8) & 0xff;
1566                 p [4] = value & 0xff;
1567                 p += 5;
1568         }
1569         if (endbuf)
1570                 *endbuf = p;
1571 }
1572
1573 static guint32
1574 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1575 {
1576         guint32 index;
1577
1578         index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1579         if (index)
1580                 return index - 1;
1581         else {
1582                 index = g_hash_table_size (cfg->image_hash);
1583                 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1584                 g_ptr_array_add (cfg->image_table, image);
1585                 return index;
1586         }
1587 }
1588
1589 static guint32
1590 find_typespec_for_class (MonoAotCompile *acfg, MonoClass *klass)
1591 {
1592         int i;
1593         MonoClass *k = NULL;
1594
1595         /* FIXME: Search referenced images as well */
1596         for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows; ++i) {
1597                 /* Since we don't compile generic methods, the context is empty */
1598                 k = mono_class_get_full (acfg->image, MONO_TOKEN_TYPE_SPEC | (i + 1), NULL);
1599                 if (k == klass)
1600                         break;
1601         }
1602
1603         g_assert (i < acfg->image->tables [MONO_TABLE_TYPESPEC].rows);
1604
1605         return MONO_TOKEN_TYPE_SPEC | (i + 1);
1606 }
1607
1608 static void
1609 encode_klass_info (MonoAotCompile *acfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
1610 {
1611         if (klass->generic_class) {
1612                 g_assert (klass->type_token);
1613
1614                 encode_value (find_typespec_for_class (acfg, klass), buf, &buf);
1615                 encode_value (get_image_index (acfg, acfg->image), buf, &buf);
1616         } else if (!klass->type_token) {
1617                 guint32 token;
1618
1619                 /* Array class */
1620                 g_assert (klass->rank > 0);
1621                 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
1622                 encode_value (get_image_index (acfg, klass->image), buf, &buf);
1623                 token = klass->element_class->type_token;
1624                 if (!token) {
1625                         /* <Type>[][] */
1626                         g_assert (klass->element_class->rank);
1627                         encode_value (0, buf, &buf);
1628                         encode_value (klass->element_class->rank, buf, &buf);
1629                         token = klass->element_class->element_class->type_token;
1630                 }
1631                 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_TYPE_DEF);
1632                 encode_value (token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1633                 encode_value (klass->rank, buf, &buf);
1634         }
1635         else {
1636                 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
1637                 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1638                 encode_value (get_image_index (acfg, klass->image), buf, &buf);
1639         }
1640         *endbuf = buf;
1641 }
1642
1643 static void
1644 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
1645 {
1646         guint32 token = mono_get_field_token (field);
1647
1648         encode_klass_info (cfg, field->parent, buf, &buf);
1649         g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
1650         encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
1651         *endbuf = buf;
1652 }
1653
1654 #if 0
1655 static guint32
1656 find_methodspec_for_method (MonoAotCompile *acfg, MonoMethod *method)
1657 {
1658         int i;
1659         MonoMethod *m = NULL;
1660
1661         /* FIXME: Search referenced images as well */
1662         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows; ++i) {
1663                 /* Since we don't compile generic methods, the context is empty */
1664                 m = mono_get_method_full (acfg->image, MONO_TOKEN_METHOD_SPEC | (i + 1), NULL, NULL);
1665                 if (m == method)
1666                         break;
1667         }
1668
1669         g_assert (i < acfg->image->tables [MONO_TABLE_METHODSPEC].rows);
1670
1671         return MONO_TOKEN_METHOD_SPEC | (i + 1);
1672 }
1673 #endif
1674
1675 static void
1676 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
1677 {
1678         guint32 image_index = get_image_index (acfg, method->klass->image);
1679         guint32 token = method->token;
1680         MonoJumpInfoToken *ji;
1681
1682         g_assert (image_index < 255);
1683
1684         if (method->klass->generic_class || mono_method_signature (method)->is_inflated) {
1685                 /* 
1686                  * This is a generic method, find the original token which referenced it and
1687                  * encode that.
1688                  */
1689                 /* This doesn't work for some reason */
1690                 /*
1691                 image_index = get_image_index (acfg, acfg->image);
1692                 g_assert (image_index < 255);
1693                 token = find_methodspec_for_method (acfg, method);
1694                 */
1695                 /* Obtain the token from information recorded by the JIT */
1696                 ji = g_hash_table_lookup (acfg->token_info_hash, method);
1697                 image_index = get_image_index (acfg, ji->image);
1698                 g_assert (image_index < 255);
1699                 token = ji->token;
1700
1701                 encode_value ((255 << 24), buf, &buf);
1702                 encode_value (image_index, buf, &buf);
1703                 encode_value (token, buf, &buf);
1704         } else {
1705                 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1706                 encode_value ((image_index << 24) | mono_metadata_token_index (token), buf, &buf);
1707         }
1708         *endbuf = buf;
1709 }
1710
1711 static gint
1712 compare_patches (gconstpointer a, gconstpointer b)
1713 {
1714         int i, j;
1715
1716         i = (*(MonoJumpInfo**)a)->ip.i;
1717         j = (*(MonoJumpInfo**)b)->ip.i;
1718
1719         if (i < j)
1720                 return -1;
1721         else
1722                 if (i > j)
1723                         return 1;
1724         else
1725                 return 0;
1726 }
1727
1728 static int
1729 get_plt_index (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
1730 {
1731         int res = -1;
1732         int idx;
1733
1734         switch (patch_info->type) {
1735         case MONO_PATCH_INFO_METHOD:
1736         case MONO_PATCH_INFO_WRAPPER:
1737         case MONO_PATCH_INFO_INTERNAL_METHOD:
1738         case MONO_PATCH_INFO_CLASS_INIT: {
1739                 MonoJumpInfo *new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
1740                 gpointer patch_id = NULL;
1741
1742                 /* First check for an existing patch */
1743                 switch (patch_info->type) {
1744                 case MONO_PATCH_INFO_METHOD:
1745                         patch_id = patch_info->data.method;
1746                         break;
1747                 case MONO_PATCH_INFO_INTERNAL_METHOD:
1748                         patch_id = (gpointer)patch_info->data.name;
1749                         break;
1750                 case MONO_PATCH_INFO_CLASS_INIT:
1751                         patch_id = patch_info->data.klass;
1752                         break;
1753                 case MONO_PATCH_INFO_WRAPPER:
1754                         /* A bit ugly, but works */
1755                         g_assert (patch_info->data.method->wrapper_type < sizeof (MonoMethod));
1756                         patch_id = (gpointer)(((guint8*)patch_info->data.method) + patch_info->data.method->wrapper_type);
1757                         break;
1758                 default:
1759                         g_assert_not_reached ();
1760                 }
1761
1762                 if (patch_id) {
1763                         idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_id));
1764                         if (idx)
1765                                 res = idx;
1766                         else
1767                                 g_hash_table_insert (acfg->patch_to_plt_offset, patch_id, GUINT_TO_POINTER (acfg->plt_offset));
1768                 }
1769
1770                 if (res == -1) {
1771                         res = acfg->plt_offset;
1772                         g_hash_table_insert (acfg->plt_offset_to_patch, GUINT_TO_POINTER (acfg->plt_offset), new_ji);
1773                         acfg->plt_offset ++;
1774                 }
1775
1776                 /* Nullify the patch */
1777                 patch_info->type = MONO_PATCH_INFO_NONE;
1778
1779                 return res;
1780         }
1781         default:
1782                 return -1;
1783         }
1784 }
1785
1786 /**
1787  * get_got_offset:
1788  *
1789  *   Returns the offset of the GOT slot where the runtime object resulting from resolving
1790  * JI could be found if it exists, otherwise allocates a new one.
1791  */
1792 static guint32
1793 get_got_offset (MonoAotCompile *acfg, MonoJumpInfo *ji)
1794 {
1795         guint32 got_offset;
1796
1797         got_offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_shared_got_offset, ji));
1798         if (got_offset)
1799                 return got_offset - 1;
1800
1801         got_offset = acfg->got_offset;
1802         acfg->got_offset ++;
1803
1804         acfg->stats.got_slots ++;
1805         acfg->stats.got_slot_types [ji->type] ++;
1806
1807         return got_offset;
1808 }
1809
1810 static guint32
1811 get_shared_got_offset (MonoAotCompile *acfg, MonoJumpInfo *ji)
1812 {
1813         MonoJumpInfo *copy;
1814         guint32 got_offset;
1815
1816         if (!g_hash_table_lookup (acfg->patch_to_shared_got_offset, ji)) {
1817                 got_offset = get_got_offset (acfg, ji);
1818                 copy = mono_patch_info_dup_mp (acfg->mempool, ji);
1819                 g_hash_table_insert (acfg->patch_to_shared_got_offset, copy, GUINT_TO_POINTER (got_offset + 1));
1820                 g_ptr_array_add (acfg->shared_patches, copy);
1821         }
1822
1823         return get_got_offset (acfg, ji);
1824 }
1825
1826 static void
1827 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
1828 {
1829         MonoMethod *method;
1830         int i, pindex, method_index;
1831         guint8 *code;
1832         char *symbol;
1833         int func_alignment = 16;
1834         GPtrArray *patches;
1835         MonoJumpInfo *patch_info;
1836         MonoMethodHeader *header;
1837         gboolean skip;
1838         guint32 got_slot;
1839
1840         method = cfg->method;
1841         code = cfg->native_code;
1842         header = mono_method_get_header (method);
1843
1844         method_index = mono_metadata_token_index (method->token);
1845
1846         /* Make the labels local */
1847         symbol = g_strdup_printf (".Lm_%x", method_index);
1848
1849         emit_alignment (acfg, func_alignment);
1850         emit_label (acfg, symbol);
1851         if (acfg->aot_opts.write_symbols)
1852                 emit_global (acfg, symbol, TRUE);
1853
1854         if (cfg->verbose_level > 0)
1855                 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
1856
1857         acfg->stats.code_size += cfg->code_len;
1858
1859         /* Collect and sort relocations */
1860         patches = g_ptr_array_new ();
1861         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1862                 g_ptr_array_add (patches, patch_info);
1863         g_ptr_array_sort (patches, compare_patches);
1864
1865         acfg->method_got_offsets [method_index] = acfg->got_offset;
1866         for (i = 0; i < cfg->code_len; i++) {
1867                 patch_info = NULL;
1868                 for (pindex = 0; pindex < patches->len; ++pindex) {
1869                         patch_info = g_ptr_array_index (patches, pindex);
1870                         if (patch_info->ip.i == i)
1871                                 break;
1872                 }
1873
1874 #ifdef MONO_ARCH_HAVE_PIC_AOT
1875
1876                 skip = FALSE;
1877                 if (patch_info && (pindex < patches->len)) {
1878                         switch (patch_info->type) {
1879                         case MONO_PATCH_INFO_LABEL:
1880                         case MONO_PATCH_INFO_BB:
1881                         case MONO_PATCH_INFO_NONE:
1882                                 break;
1883                         case MONO_PATCH_INFO_GOT_OFFSET: {
1884                                 guint32 offset = mono_arch_get_patch_offset (code + i);
1885                                 emit_bytes (acfg, code + i, offset);
1886                                 emit_symbol_diff (acfg, "got", ".", offset);
1887
1888                                 i += offset + 4 - 1;
1889                                 skip = TRUE;
1890                                 break;
1891                         }
1892                         default: {
1893                                 int plt_index;
1894                                 char *direct_call_target;
1895
1896                                 if (!is_got_patch (patch_info->type))
1897                                         break;
1898
1899                                 /*
1900                                  * If this patch is a call, try emitting a direct call instead of
1901                                  * through a PLT entry. This is possible if the called method is in
1902                                  * the same assembly and requires no initialization.
1903                                  */
1904                                 direct_call_target = NULL;
1905                                 if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == cfg->method->klass->image)) {
1906                                         MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
1907                                         if (callee_cfg) {
1908                                                 guint32 callee_idx = mono_metadata_token_index (callee_cfg->method->token);
1909                                                 if (!acfg->has_got_slots [callee_idx] && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)) {
1910                                                         //printf ("DIRECT: %s %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (callee_cfg->method, TRUE));
1911                                                         direct_call_target = g_strdup_printf (".Lm_%x", mono_metadata_token_index (callee_cfg->method->token));
1912                                                         patch_info->type = MONO_PATCH_INFO_NONE;
1913                                                         acfg->stats.direct_calls ++;
1914                                                 }
1915                                         }
1916
1917                                         acfg->stats.all_calls ++;
1918                                 }
1919
1920                                 if (!direct_call_target) {
1921                                         plt_index = get_plt_index (acfg, patch_info);
1922                                         if (plt_index != -1) {
1923                                                 /* This patch has a PLT entry, so we must emit a call to the PLT entry */
1924                                                 direct_call_target = g_strdup_printf (".Lp_%d", plt_index);
1925                                         }
1926                                 }
1927
1928                                 if (direct_call_target) {
1929 #if defined(__i386__) || defined(__x86_64__)
1930                                         g_assert (code [i] == 0xe8);
1931                                         /* Need to make sure this is exactly 5 bytes long */
1932                                         emit_byte (acfg, '\xe8');
1933                                         emit_symbol_diff (acfg, direct_call_target, ".", -4);
1934                                         i += 4;
1935 #else
1936                                         g_assert_not_reached ();
1937 #endif
1938                                 } else {
1939                                         got_slot = get_got_offset (acfg, patch_info);
1940
1941                                         emit_bytes (acfg, code + i, mono_arch_get_patch_offset (code + i));
1942 #ifdef __x86_64__
1943                                         emit_symbol_diff (acfg, "got", ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
1944 #elif defined(__i386__)
1945                                         emit_int32 (acfg, (unsigned int) ((got_slot * sizeof (gpointer))));
1946 #endif
1947                                         
1948                                         i += mono_arch_get_patch_offset (code + i) + 4 - 1;
1949                                 }
1950                                 skip = TRUE;
1951                         }
1952                         }
1953                 }
1954 #endif /* MONO_ARCH_HAVE_PIC_AOT */
1955
1956                 if (!skip)
1957                         emit_bytes (acfg, code + i, 1);
1958         }
1959         emit_line (acfg);
1960 }
1961
1962 /**
1963  * encode_patch:
1964  *
1965  *  Encode PATCH_INFO into its disk representation. If SHARED is true, encode some types
1966  * of patches by allocating a GOT entry for them, and encode the GOT offset instead.
1967  */
1968 static void
1969 encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint8 **endbuf, gboolean shared)
1970 {
1971         guint8 *p = buf;
1972
1973         switch (patch_info->type) {
1974         case MONO_PATCH_INFO_NONE:
1975                 break;
1976         case MONO_PATCH_INFO_IMAGE:
1977                 encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
1978                 break;
1979         case MONO_PATCH_INFO_METHOD_REL:
1980                 encode_value ((gint)patch_info->data.offset, p, &p);
1981                 break;
1982         case MONO_PATCH_INFO_SWITCH: {
1983                 gpointer *table = (gpointer *)patch_info->data.table->table;
1984                 int k;
1985
1986                 encode_value (patch_info->data.table->table_size, p, &p);
1987                 for (k = 0; k < patch_info->data.table->table_size; k++)
1988                         encode_value ((int)(gssize)table [k], p, &p);
1989                 break;
1990         }
1991         case MONO_PATCH_INFO_METHODCONST:
1992         case MONO_PATCH_INFO_METHOD:
1993         case MONO_PATCH_INFO_METHOD_JUMP:
1994                 encode_method_ref (acfg, patch_info->data.method, p, &p);
1995                 break;
1996         case MONO_PATCH_INFO_INTERNAL_METHOD: {
1997                 guint32 len = strlen (patch_info->data.name);
1998
1999                 encode_value (len, p, &p);
2000
2001                 memcpy (p, patch_info->data.name, len);
2002                 p += len;
2003                 *p++ = '\0';
2004                 break;
2005         }
2006         case MONO_PATCH_INFO_LDSTR: {
2007                 guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
2008                 guint32 token = patch_info->data.token->token;
2009                 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
2010                 encode_value (image_index, p, &p);
2011                 encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
2012                 break;
2013         }
2014         case MONO_PATCH_INFO_RVA:
2015         case MONO_PATCH_INFO_DECLSEC:
2016         case MONO_PATCH_INFO_LDTOKEN:
2017         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
2018                 if (shared) {
2019                         guint32 offset = get_got_offset (acfg, patch_info);
2020                         encode_value (offset, p, &p);
2021                 } else {
2022                         encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
2023                         encode_value (patch_info->data.token->token, p, &p);
2024                 }
2025                 break;
2026         case MONO_PATCH_INFO_EXC_NAME: {
2027                 MonoClass *ex_class;
2028
2029                 ex_class =
2030                         mono_class_from_name (mono_defaults.exception_class->image,
2031                                                                   "System", patch_info->data.target);
2032                 g_assert (ex_class);
2033                 encode_klass_info (acfg, ex_class, p, &p);
2034                 break;
2035         }
2036         case MONO_PATCH_INFO_R4:
2037                 encode_value (*((guint32 *)patch_info->data.target), p, &p);
2038                 break;
2039         case MONO_PATCH_INFO_R8:
2040                 encode_value (*((guint32 *)patch_info->data.target), p, &p);
2041                 encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
2042                 break;
2043         case MONO_PATCH_INFO_VTABLE:
2044         case MONO_PATCH_INFO_CLASS:
2045         case MONO_PATCH_INFO_IID:
2046         case MONO_PATCH_INFO_ADJUSTED_IID:
2047                 if (shared) {
2048                         guint32 offset = get_got_offset (acfg, patch_info);
2049                         encode_value (offset, p, &p);
2050                 } else {
2051                         encode_klass_info (acfg, patch_info->data.klass, p, &p);
2052                 }
2053                 break;
2054         case MONO_PATCH_INFO_CLASS_INIT:
2055                 encode_klass_info (acfg, patch_info->data.klass, p, &p);
2056                 break;
2057         case MONO_PATCH_INFO_FIELD:
2058         case MONO_PATCH_INFO_SFLDA:
2059                 if (shared) {
2060                         guint32 offset = get_got_offset (acfg, patch_info);
2061                         encode_value (offset, p, &p);
2062                 } else {
2063                         encode_field_info (acfg, patch_info->data.field, p, &p);
2064                 }
2065                 break;
2066         case MONO_PATCH_INFO_WRAPPER: {
2067                 encode_value (patch_info->data.method->wrapper_type, p, &p);
2068
2069                 switch (patch_info->data.method->wrapper_type) {
2070                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
2071                         MonoMethod *m;
2072                         guint32 image_index;
2073                         guint32 token;
2074
2075                         m = mono_marshal_method_from_wrapper (patch_info->data.method);
2076                         image_index = get_image_index (acfg, m->klass->image);
2077                         token = m->token;
2078                         g_assert (image_index < 256);
2079                         g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
2080
2081                         encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
2082                         break;
2083                 }
2084                 case MONO_WRAPPER_PROXY_ISINST:
2085                 case MONO_WRAPPER_LDFLD:
2086                 case MONO_WRAPPER_LDFLDA:
2087                 case MONO_WRAPPER_STFLD:
2088                 case MONO_WRAPPER_LDFLD_REMOTE:
2089                 case MONO_WRAPPER_STFLD_REMOTE:
2090                 case MONO_WRAPPER_ISINST: {
2091                         MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
2092                         encode_klass_info (acfg, proxy_class, p, &p);
2093                         break;
2094                 }
2095                 case MONO_WRAPPER_STELEMREF:
2096                         break;
2097                 default:
2098                         g_assert_not_reached ();
2099                 }
2100                 break;
2101         }
2102         default:
2103                 g_warning ("unable to handle jump info %d", patch_info->type);
2104                 g_assert_not_reached ();
2105         }
2106
2107         *endbuf = p;
2108 }
2109
2110 static void
2111 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
2112 {
2113         MonoMethod *method;
2114         GList *l;
2115         int j, pindex, buf_size, n_patches;
2116         guint8 *code;
2117         char *symbol;
2118         GPtrArray *patches;
2119         MonoJumpInfo *patch_info;
2120         MonoMethodHeader *header;
2121         guint32 last_offset, method_idx;
2122         guint8 *p, *buf;
2123         guint32 first_got_offset;
2124
2125         method = cfg->method;
2126         code = cfg->native_code;
2127         header = mono_method_get_header (method);
2128
2129         method_idx = mono_metadata_token_index (method->token);
2130
2131         /* Make the labels local */
2132         symbol = g_strdup_printf (".Lm_%x_p", method_idx);
2133
2134         /* Sort relocations */
2135         patches = g_ptr_array_new ();
2136         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
2137                 g_ptr_array_add (patches, patch_info);
2138         g_ptr_array_sort (patches, compare_patches);
2139
2140         first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
2141
2142         /**********************/
2143         /* Encode method info */
2144         /**********************/
2145
2146         buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
2147         p = buf = g_malloc (buf_size);
2148
2149         if (mono_class_get_cctor (method->klass))
2150                 encode_klass_info (acfg, method->klass, p, &p);
2151         else
2152                 /* Not needed when loading the method */
2153                 encode_value (0, p, &p);
2154
2155         /* String table */
2156         if (cfg->opt & MONO_OPT_SHARED) {
2157                 encode_value (g_list_length (cfg->ldstr_list), p, &p);
2158                 for (l = cfg->ldstr_list; l; l = l->next) {
2159                         encode_value ((long)l->data, p, &p);
2160                 }
2161         }
2162         else
2163                 /* Used only in shared mode */
2164                 g_assert (!cfg->ldstr_list);
2165
2166         n_patches = 0;
2167         for (pindex = 0; pindex < patches->len; ++pindex) {
2168                 patch_info = g_ptr_array_index (patches, pindex);
2169                 
2170                 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
2171                         (patch_info->type == MONO_PATCH_INFO_BB) ||
2172                         (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
2173                         (patch_info->type == MONO_PATCH_INFO_NONE)) {
2174                         patch_info->type = MONO_PATCH_INFO_NONE;
2175                         /* Nothing to do */
2176                         continue;
2177                 }
2178
2179                 if ((patch_info->type == MONO_PATCH_INFO_IMAGE) && (patch_info->data.image == acfg->image)) {
2180                         /* Stored in a GOT slot initialized at module load time */
2181                         patch_info->type = MONO_PATCH_INFO_NONE;
2182                         continue;
2183                 }
2184
2185                 if ((patch_info->type == MONO_PATCH_INFO_METHOD) ||
2186                         (patch_info->type == MONO_PATCH_INFO_INTERNAL_METHOD) ||
2187                         (patch_info->type == MONO_PATCH_INFO_WRAPPER) ||
2188                         (patch_info->type == MONO_PATCH_INFO_CLASS_INIT)) {
2189                         /* Calls are made through the PLT */
2190                         patch_info->type = MONO_PATCH_INFO_NONE;
2191                         continue;
2192                 }
2193
2194                 n_patches ++;
2195         }
2196
2197         if (n_patches)
2198                 g_assert (acfg->has_got_slots [method_idx]);
2199
2200         encode_value (n_patches, p, &p);
2201
2202         if (n_patches)
2203                 encode_value (first_got_offset, p, &p);
2204
2205         /* First encode the type+position table */
2206         last_offset = 0;
2207         j = 0;
2208         for (pindex = 0; pindex < patches->len; ++pindex) {
2209                 guint32 offset;
2210                 patch_info = g_ptr_array_index (patches, pindex);
2211                 
2212                 if (patch_info->type == MONO_PATCH_INFO_NONE)
2213                         /* Nothing to do */
2214                         continue;
2215
2216                 j ++;
2217                 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
2218                 offset = patch_info->ip.i - last_offset;
2219                 last_offset = patch_info->ip.i;
2220
2221                 /* Only the type is needed */
2222                 *p = patch_info->type;
2223                 p++;
2224         }
2225
2226         /*
2227         if (n_patches) {
2228                 printf ("%s:\n", mono_method_full_name (cfg->method, TRUE));
2229                 for (pindex = 0; pindex < patches->len; ++pindex) {
2230                         patch_info = g_ptr_array_index (patches, pindex);
2231                         if (patch_info->type != MONO_PATCH_INFO_NONE) {
2232                                 printf ("\t%s", get_patch_name (patch_info->type));
2233                                 if (patch_info->type == MONO_PATCH_INFO_VTABLE)
2234                                         printf (": %s\n", patch_info->data.klass->name);
2235                                 else
2236                                         printf ("\n");
2237                         }
2238                 }
2239         }
2240         */
2241
2242         /* Then encode the other info */
2243         for (pindex = 0; pindex < patches->len; ++pindex) {
2244                 patch_info = g_ptr_array_index (patches, pindex);
2245
2246                 encode_patch (acfg, patch_info, p, &p, TRUE);
2247         }
2248
2249         acfg->stats.info_size += p - buf;
2250
2251         /* Emit method info */
2252
2253         emit_label (acfg, symbol);
2254
2255         g_assert (p - buf < buf_size);
2256         emit_bytes (acfg, buf, p - buf);
2257         g_free (buf);
2258
2259         g_free (symbol);
2260 }
2261
2262 static void
2263 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
2264 {
2265         MonoMethod *method;
2266         int k, buf_size;
2267         guint32 debug_info_size;
2268         guint8 *code;
2269         char *symbol;
2270         MonoMethodHeader *header;
2271         guint8 *p, *buf, *debug_info;
2272
2273         method = cfg->method;
2274         code = cfg->native_code;
2275         header = mono_method_get_header (method);
2276
2277         /* Make the labels local */
2278         symbol = g_strdup_printf (".Le_%x_p", mono_metadata_token_index (method->token));
2279
2280         buf_size = header->num_clauses * 256 + 128;
2281         p = buf = g_malloc (buf_size);
2282
2283         encode_value (cfg->code_len, p, &p);
2284         encode_value (cfg->used_int_regs, p, &p);
2285
2286         /* Exception table */
2287         if (header->num_clauses) {
2288                 MonoJitInfo *jinfo = cfg->jit_info;
2289
2290                 for (k = 0; k < header->num_clauses; ++k) {
2291                         MonoJitExceptionInfo *ei = &jinfo->clauses [k];
2292
2293                         encode_value (ei->exvar_offset, p, &p);
2294
2295                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
2296                                 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
2297
2298                         encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
2299                         encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
2300                         encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
2301                 }
2302         }
2303
2304         mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
2305
2306         encode_value (debug_info_size, p, &p);
2307         if (debug_info_size) {
2308                 memcpy (p, debug_info, debug_info_size);
2309                 p += debug_info_size;
2310                 g_free (debug_info);
2311         }
2312
2313         acfg->stats.ex_info_size += p - buf;
2314
2315         /* Emit info */
2316
2317         emit_label (acfg, symbol);
2318
2319         g_assert (p - buf < buf_size);
2320         emit_bytes (acfg, buf, p - buf);
2321         g_free (buf);
2322
2323         g_free (symbol);
2324 }
2325
2326 static void
2327 emit_klass_info (MonoAotCompile *acfg, guint32 token)
2328 {
2329         MonoClass *klass = mono_class_get (acfg->image, token);
2330         guint8 *p, *buf;
2331         int i, buf_size;
2332         char *label;
2333         gboolean no_special_static;
2334
2335         buf_size = 10240;
2336         p = buf = g_malloc (buf_size);
2337
2338         g_assert (klass);
2339
2340         mono_class_init (klass);
2341
2342         /* 
2343          * Emit all the information which is required for creating vtables so
2344          * the runtime does not need to create the MonoMethod structures which
2345          * take up a lot of space.
2346          */
2347
2348         no_special_static = !mono_class_has_special_static_fields (klass);
2349
2350         if (klass->generic_container) {
2351                 encode_value (-1, p, &p);
2352         } else {
2353                 encode_value (klass->vtable_size, p, &p);
2354                 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);
2355                 if (klass->has_cctor)
2356                         encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
2357                 if (klass->has_finalize)
2358                         encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
2359  
2360                 encode_value (klass->instance_size, p, &p);
2361                 encode_value (mono_class_data_size (klass), p, &p);
2362                 encode_value (klass->packing_size, p, &p);
2363                 encode_value (klass->min_align, p, &p);
2364
2365                 for (i = 0; i < klass->vtable_size; ++i) {
2366                         MonoMethod *cm = klass->vtable [i];
2367
2368                         if (cm)
2369                                 encode_method_ref (acfg, cm, p, &p);
2370                         else
2371                                 encode_value (0, p, &p);
2372                 }
2373         }
2374
2375         acfg->stats.class_info_size += p - buf;
2376
2377         /* Emit the info */
2378         label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
2379         emit_label (acfg, label);
2380
2381         g_assert (p - buf < buf_size);
2382         emit_bytes (acfg, buf, p - buf);
2383         g_free (buf);
2384 }
2385
2386 /*
2387  * Calls made from AOTed code are routed through a table of jumps similar to the
2388  * ELF PLT (Program Linkage Table). The differences are the following:
2389  * - the ELF PLT entries make an indirect jump though the GOT so they expect the
2390  *   GOT pointer to be in EBX. We want to avoid this, so our table contains direct
2391  *   jumps. This means the jumps need to be patched when the address of the callee is
2392  *   known. Initially the PLT entries jump to code which transfer control to the
2393  *   AOT runtime through the first PLT entry.
2394  */
2395 static void
2396 emit_plt (MonoAotCompile *acfg)
2397 {
2398         char *symbol;
2399         int i, buf_size;
2400         guint8 *p, *buf;
2401         guint32 *plt_info_offsets;
2402
2403         /*
2404          * Encode info need to resolve PLT entries.
2405          */
2406         buf_size = acfg->plt_offset * 128;
2407         p = buf = g_malloc (buf_size);
2408
2409         plt_info_offsets = g_new0 (guint32, acfg->plt_offset);
2410
2411         for (i = 1; i < acfg->plt_offset; ++i) {
2412                 MonoJumpInfo *patch_info = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
2413
2414                 plt_info_offsets [i] = p - buf;
2415                 encode_value (patch_info->type, p, &p);
2416                 encode_patch (acfg, patch_info, p, &p, FALSE);
2417         }
2418
2419         emit_line (acfg);
2420         symbol = g_strdup_printf ("plt");
2421
2422         /* This section will be made read-write by the AOT loader */
2423         emit_section_change (acfg, ".text", 0);
2424         emit_global (acfg, symbol, TRUE);
2425         emit_alignment (acfg, PAGESIZE);
2426         emit_label (acfg, symbol);
2427
2428         /* 
2429          * The first plt entry is used to transfer code to the AOT loader. 
2430          */
2431         emit_label (acfg, ".Lp_0");
2432 #if defined(__i386__)
2433         /* It is filled up during loading by the AOT loader. */
2434         emit_zero_bytes (acfg, 16);
2435 #elif defined(__x86_64__)
2436         /* This should be exactly 16 bytes long */
2437         /* jmpq *<offset>(%rip) */
2438         emit_byte (acfg, '\xff');
2439         emit_byte (acfg, '\x25');
2440         emit_symbol_diff (acfg, "plt_jump_table", ".", -4);
2441         emit_zero_bytes (acfg, 10);
2442 #else
2443         g_assert_not_reached ();
2444 #endif
2445
2446         for (i = 1; i < acfg->plt_offset; ++i) {
2447                 char *label;
2448
2449                 label = g_strdup_printf (".Lp_%d", i);
2450                 emit_label (acfg, label);
2451                 g_free (label);
2452 #if defined(__i386__)
2453                 /* Need to make sure this is 5 bytes long */
2454                 emit_byte (acfg, '\xe9');
2455                 label = g_strdup_printf (".Lpd_%d", i);
2456                 emit_symbol_diff (acfg, label, ".", -4);
2457                 g_free (label);
2458 #elif defined(__x86_64__)
2459                 /*
2460                  * We can't emit jumps because they are 32 bits only so they can't be patched.
2461                  * So we emit a jump table instead whose entries are patched by the AOT loader to
2462                  * point to .Lpd entries. ELF stores these in the GOT too, but we don't, since
2463                  * methods with GOT entries can't be called directly.
2464                  * We also emit the default PLT code here since the PLT code will not be patched.
2465                  * An x86_64 plt entry is 16 bytes long, init_plt () depends on this.
2466                  */
2467                 /* jmpq *<offset>(%rip) */
2468                 emit_byte (acfg, '\xff');
2469                 emit_byte (acfg, '\x25');
2470                 emit_symbol_diff (acfg, "plt_jump_table", ".", (i * sizeof (gpointer)) -4);
2471                 /* mov <plt info offset>, %eax */
2472                 emit_byte (acfg, '\xb8');
2473                 emit_int32 (acfg, plt_info_offsets [i]);
2474                 /* jmp .Lp_0 */
2475                 emit_byte (acfg, '\xe9');
2476                 emit_symbol_diff (acfg, ".Lp_0", ".", -4);
2477 #else
2478                 g_assert_not_reached ();
2479 #endif
2480         }
2481
2482         symbol = g_strdup_printf ("plt_end");
2483         emit_global (acfg, symbol, TRUE);
2484         emit_label (acfg, symbol);
2485
2486         /* 
2487          * Emit the default targets for the PLT entries separately since these will not
2488          * be modified at runtime.
2489          */
2490         for (i = 1; i < acfg->plt_offset; ++i) {
2491                 char *label;
2492
2493                 label = g_strdup_printf (".Lpd_%d", i);
2494                 emit_label (acfg, label);
2495                 g_free (label);
2496
2497                 /* Put the offset into the register expected by mono_aot_plt_trampoline */
2498 #if defined(__i386__)
2499                 /* movl $const, %eax */
2500                 emit_byte (acfg, '\xb8');
2501                 emit_int32 (acfg, plt_info_offsets [i]);
2502                 /* jmp .Lp_0 */
2503                 emit_byte (acfg, '\xe9');
2504                 emit_symbol_diff (acfg, ".Lp_0", ".", -4);
2505 #elif defined(__x86_64__)
2506                 /* Emitted along with the PLT entries since they will not be patched */
2507 #else
2508                 g_assert_not_reached ();
2509 #endif
2510         }
2511
2512         /* Emit PLT info */
2513         symbol = g_strdup_printf ("plt_info");
2514         emit_global (acfg, symbol, FALSE);
2515         emit_label (acfg, symbol);
2516
2517         g_assert (p - buf < buf_size);
2518         emit_bytes (acfg, buf, p - buf);
2519         g_free (buf);
2520
2521         symbol = g_strdup_printf ("plt_jump_table_addr");
2522         emit_section_change (acfg, ".data", 0);
2523         emit_global (acfg, symbol, FALSE);
2524         emit_alignment (acfg, 8);
2525         emit_label (acfg, symbol);
2526         emit_pointer (acfg, "plt_jump_table");
2527
2528         symbol = g_strdup_printf ("plt_jump_table_size");
2529         emit_section_change (acfg, ".data", 0);
2530         emit_global (acfg, symbol, FALSE);
2531         emit_alignment (acfg, 8);
2532         emit_label (acfg, symbol);
2533         emit_symbol_diff (acfg, "plt_jump_table_end", "plt_jump_table", 0);
2534
2535         /* Don't make this a global so accesses don't need relocations */
2536         symbol = g_strdup_printf ("plt_jump_table");
2537         emit_section_change (acfg, ".bss", 0);
2538         emit_label (acfg, symbol);
2539
2540 #ifdef __x86_64__
2541         emit_zero_bytes (acfg, (int)(acfg->plt_offset * sizeof (gpointer)));
2542 #endif  
2543
2544         symbol = g_strdup_printf ("plt_jump_table_end");
2545         emit_label (acfg, symbol);
2546 }
2547
2548 static gboolean
2549 str_begins_with (const char *str1, const char *str2)
2550 {
2551         int len = strlen (str2);
2552         return strncmp (str1, str2, len) == 0;
2553 }
2554
2555 static void
2556 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
2557 {
2558         gchar **args, **ptr;
2559
2560         memset (opts, 0, sizeof (*opts));
2561
2562         args = g_strsplit (aot_options ? aot_options : "", ",", -1);
2563         for (ptr = args; ptr && *ptr; ptr ++) {
2564                 const char *arg = *ptr;
2565
2566                 if (str_begins_with (arg, "outfile=")) {
2567                         opts->outfile = g_strdup (arg + strlen ("outfile="));
2568                 } else if (str_begins_with (arg, "save-temps")) {
2569                         opts->save_temps = TRUE;
2570                 } else if (str_begins_with (arg, "keep-temps")) {
2571                         opts->save_temps = TRUE;
2572                 } else if (str_begins_with (arg, "write-symbols")) {
2573                         opts->write_symbols = TRUE;
2574                 } else if (str_begins_with (arg, "metadata-only")) {
2575                         opts->metadata_only = TRUE;
2576                 } else {
2577                         fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
2578                         exit (1);
2579                 }
2580         }
2581 }
2582
2583 static void
2584 add_token_info_hash (gpointer key, gpointer value, gpointer user_data)
2585 {
2586         MonoMethod *method = (MonoMethod*)key;
2587         MonoJumpInfoToken *ji = (MonoJumpInfoToken*)value;
2588         MonoJumpInfoToken *new_ji = g_new0 (MonoJumpInfoToken, 1);
2589         MonoAotCompile *acfg = user_data;
2590
2591         new_ji->image = ji->image;
2592         new_ji->token = ji->token;
2593         g_hash_table_insert (acfg->token_info_hash, method, new_ji);
2594 }
2595
2596 static void
2597 compile_method (MonoAotCompile *acfg, int index)
2598 {
2599         MonoCompile *cfg;
2600         MonoMethod *method;
2601         MonoJumpInfo *patch_info;
2602         gboolean skip;
2603         guint32 token = MONO_TOKEN_METHOD_DEF | (index + 1);
2604         guint32 method_idx;
2605
2606         if (acfg->aot_opts.metadata_only)
2607                 return;
2608
2609         method = mono_get_method (acfg->image, token, NULL);
2610
2611         method_idx = mono_metadata_token_index (method->token); 
2612                 
2613         /* fixme: maybe we can also precompile wrapper methods */
2614         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2615                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2616                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2617                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
2618                 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
2619                 return;
2620         }
2621
2622         acfg->stats.mcount++;
2623
2624         /* fixme: we need to patch the IP for the LMF in that case */
2625         if (method->save_lmf) {
2626                 //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
2627                 acfg->stats.lmfcount++;
2628                 return;
2629         }
2630
2631         if (mono_method_signature (method)->has_type_parameters || method->klass->generic_container) {
2632                 acfg->stats.genericcount ++;
2633                 return;
2634         }
2635
2636         /*
2637          * Since these methods are the only ones which are compiled with
2638          * AOT support, and they are not used by runtime startup/shutdown code,
2639          * the runtime will not see AOT methods during AOT compilation,so it
2640          * does not need to support them by creating a fake GOT etc.
2641          */
2642         cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
2643         if (cfg->exception_type != MONO_EXCEPTION_NONE) {
2644                 /* Let the exception happen at runtime */
2645                 return;
2646         }
2647
2648         if (cfg->disable_aot) {
2649                 //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
2650                 acfg->stats.ocount++;
2651                 mono_destroy_compile (cfg);
2652                 return;
2653         }
2654
2655         /* Collect method->token associations from the cfg */
2656         g_hash_table_foreach (cfg->token_info_hash, add_token_info_hash, acfg);
2657
2658         skip = FALSE;
2659         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2660                 switch (patch_info->type) {
2661                 case MONO_PATCH_INFO_ABS:
2662                         /* unable to handle this */
2663                         //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
2664                         skip = TRUE;    
2665                         break;
2666                 default:
2667                         break;
2668                 }
2669         }
2670
2671         if (skip) {
2672                 acfg->stats.abscount++;
2673                 mono_destroy_compile (cfg);
2674                 return;
2675         }
2676
2677         skip = FALSE;
2678         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2679                 if (patch_info->type == MONO_PATCH_INFO_METHOD_JUMP) {
2680                         /* 
2681                          * FIXME: We can't handle this because mono_jit_compile_method_inner will try
2682                          * to patch the AOT code when the target of the jump is compiled.
2683                          */
2684                         skip = TRUE;
2685                         break;
2686                 }
2687         }
2688
2689         if (skip) {
2690                 acfg->stats.ocount++;
2691                 mono_destroy_compile (cfg);
2692                 return;
2693         }
2694
2695         /* some wrappers are very common */
2696         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2697                 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
2698                         switch (patch_info->data.method->wrapper_type) {
2699                         case MONO_WRAPPER_PROXY_ISINST:
2700                                 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2701                         }
2702                 }
2703
2704                 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
2705                         switch (patch_info->data.method->wrapper_type) {
2706                         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
2707                         case MONO_WRAPPER_STFLD:
2708                         case MONO_WRAPPER_LDFLD:
2709                         case MONO_WRAPPER_LDFLDA:
2710                         case MONO_WRAPPER_LDFLD_REMOTE:
2711                         case MONO_WRAPPER_STFLD_REMOTE:
2712                         case MONO_WRAPPER_STELEMREF:
2713                         case MONO_WRAPPER_ISINST:
2714                         case MONO_WRAPPER_PROXY_ISINST:
2715                                 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2716                                 break;
2717                         }
2718                 }
2719         }
2720
2721         skip = FALSE;
2722         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2723                 switch (patch_info->type) {
2724                 case MONO_PATCH_INFO_METHOD:
2725                 case MONO_PATCH_INFO_METHODCONST:
2726                         if (patch_info->data.method->wrapper_type) {
2727                                 /* unable to handle this */
2728                                 //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));
2729                                 skip = TRUE;
2730                                 break;
2731                         }
2732                         if (!patch_info->data.method->token)
2733                                 /*
2734                                  * The method is part of a constructed type like Int[,].Set (). It doesn't
2735                                  * have a token, and we can't make one, since the parent type is part of
2736                                  * assembly which contains the element type, and not the assembly which
2737                                  * referenced this type.
2738                                  */
2739                                 skip = TRUE;
2740                         break;
2741                 case MONO_PATCH_INFO_VTABLE:
2742                 case MONO_PATCH_INFO_CLASS_INIT:
2743                 case MONO_PATCH_INFO_CLASS:
2744                 case MONO_PATCH_INFO_IID:
2745                 case MONO_PATCH_INFO_ADJUSTED_IID:
2746                         if (!patch_info->data.klass->type_token)
2747                                 if (!patch_info->data.klass->element_class->type_token && !(patch_info->data.klass->element_class->rank && patch_info->data.klass->element_class->element_class->type_token))
2748                                         skip = TRUE;
2749                         break;
2750                 default:
2751                         break;
2752                 }
2753         }
2754
2755         if (skip) {
2756                 acfg->stats.wrappercount++;
2757                 mono_destroy_compile (cfg);
2758                 return;
2759         }
2760
2761         /* Determine whenever the method has GOT slots */
2762         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2763                 switch (patch_info->type) {
2764                 case MONO_PATCH_INFO_LABEL:
2765                 case MONO_PATCH_INFO_BB:
2766                 case MONO_PATCH_INFO_GOT_OFFSET:
2767                 case MONO_PATCH_INFO_NONE:
2768                 case MONO_PATCH_INFO_METHOD:
2769                 case MONO_PATCH_INFO_INTERNAL_METHOD:
2770                 case MONO_PATCH_INFO_WRAPPER:
2771                         break;
2772                 case MONO_PATCH_INFO_IMAGE:
2773                         if (patch_info->data.image == acfg->image)
2774                                 /* Stored in GOT slot 0 */
2775                                 break;
2776                         /* Fall through */
2777                 default:
2778                         acfg->has_got_slots [method_idx] = TRUE;
2779                         break;
2780                 }
2781         }
2782
2783         if (!acfg->has_got_slots [method_idx])
2784                 acfg->stats.methods_without_got_slots ++;
2785
2786         /* Make a copy of the patch info which is in the mempool */
2787         {
2788                 MonoJumpInfo *patches = NULL, *patches_end = NULL;
2789
2790                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2791                         MonoJumpInfo *new_patch_info = mono_patch_info_dup_mp (acfg->mempool, patch_info);
2792
2793                         if (!patches)
2794                                 patches = new_patch_info;
2795                         else
2796                                 patches_end->next = new_patch_info;
2797                         patches_end = new_patch_info;
2798                 }
2799                 cfg->patch_info = patches;
2800         }
2801
2802         /* Free some fields used by cfg to conserve memory */
2803         mono_mempool_destroy (cfg->mempool);
2804         cfg->mempool = NULL;
2805         g_free (cfg->varinfo);
2806         cfg->varinfo = NULL;
2807         g_free (cfg->vars);
2808         cfg->vars = NULL;
2809         if (cfg->rs) {
2810                 mono_regstate_free (cfg->rs);
2811                 cfg->rs = NULL;
2812         }
2813
2814         //printf ("Compile:           %s\n", mono_method_full_name (method, TRUE));
2815
2816         acfg->cfgs [index] = cfg;
2817
2818         g_hash_table_insert (acfg->method_to_cfg, cfg->method, cfg);
2819
2820         acfg->stats.ccount++;
2821 }
2822
2823 static void
2824 load_profile_files (MonoAotCompile *acfg)
2825 {
2826         FILE *infile;
2827         char *tmp;
2828         int file_index, res, method_index, i;
2829         char ver [256];
2830         guint32 token;
2831
2832         file_index = 0;
2833         while (TRUE) {
2834                 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);
2835
2836                 if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
2837                         break;
2838
2839                 infile = fopen (tmp, "r");
2840                 g_assert (infile);
2841
2842                 printf ("Using profile data file '%s'\n", tmp);
2843
2844                 file_index ++;
2845
2846                 res = fscanf (infile, "%32s\n", ver);
2847                 if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
2848                         printf ("Profile file has wrong version or invalid.\n");
2849                         fclose (infile);
2850                         continue;
2851                 }
2852
2853                 while (TRUE) {
2854                         res = fscanf (infile, "%d\n", &token);
2855                         if (res < 1)
2856                                 break;
2857
2858                         method_index = mono_metadata_token_index (token) - 1;
2859
2860                         if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
2861                                 acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
2862                 }
2863                 fclose (infile);
2864         }
2865
2866         /* Add missing methods */
2867         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
2868                 if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (i)))
2869                         acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (i));
2870         }               
2871 }
2872
2873 /**
2874  * alloc_got_slots:
2875  *
2876  *  Collect all patches which have shared GOT entries and alloc entries for them. The
2877  * rest will get entries allocated during emit_code ().
2878  */
2879 static void
2880 alloc_got_slots (MonoAotCompile *acfg)
2881 {
2882         int i;
2883         GList *l;
2884         MonoJumpInfo *ji;
2885
2886         /* Slot 0 is reserved for the address of the current assembly */
2887         ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
2888         ji->type = MONO_PATCH_INFO_IMAGE;
2889         ji->data.image = acfg->image;
2890
2891         get_shared_got_offset (acfg, ji);
2892
2893         for (l = acfg->method_order; l != NULL; l = l->next) {
2894                 i = GPOINTER_TO_UINT (l->data);
2895
2896                 if (acfg->cfgs [i]) {
2897                         MonoCompile *cfg = acfg->cfgs [i];
2898
2899                         for (ji = cfg->patch_info; ji; ji = ji->next) {
2900                                 switch (ji->type) {
2901                                 case MONO_PATCH_INFO_VTABLE:
2902                                 case MONO_PATCH_INFO_CLASS:
2903                                 case MONO_PATCH_INFO_IID:
2904                                 case MONO_PATCH_INFO_ADJUSTED_IID:
2905                                 case MONO_PATCH_INFO_FIELD:
2906                                 case MONO_PATCH_INFO_SFLDA:
2907                                 case MONO_PATCH_INFO_DECLSEC:
2908                                 case MONO_PATCH_INFO_LDTOKEN:
2909                                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
2910                                 case MONO_PATCH_INFO_RVA:
2911                                         get_shared_got_offset (acfg, ji);
2912                                         break;
2913                                 default:
2914                                         break;
2915                                 }
2916                         }
2917                 }
2918         }
2919 }
2920
2921 static void
2922 emit_code (MonoAotCompile *acfg)
2923 {
2924         int i;
2925         char *symbol;
2926         GList *l;
2927
2928         symbol = g_strdup_printf ("methods");
2929         emit_section_change (acfg, ".text", 0);
2930         emit_global (acfg, symbol, TRUE);
2931         emit_alignment (acfg, 8);
2932         emit_label (acfg, symbol);
2933
2934         for (l = acfg->method_order; l != NULL; l = l->next) {
2935                 i = GPOINTER_TO_UINT (l->data);
2936
2937                 if (acfg->cfgs [i])
2938                         emit_method_code (acfg, acfg->cfgs [i]);
2939         }
2940
2941         symbol = g_strdup_printf ("methods_end");
2942         emit_section_change (acfg, ".text", 0);
2943         emit_global (acfg, symbol, FALSE);
2944         emit_alignment (acfg, 8);
2945         emit_label (acfg, symbol);
2946
2947         symbol = g_strdup_printf ("method_offsets");
2948         emit_section_change (acfg, ".text", 1);
2949         emit_global (acfg, symbol, FALSE);
2950         emit_alignment (acfg, 8);
2951         emit_label (acfg, symbol);
2952
2953         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
2954                 if (acfg->cfgs [i]) {
2955                         symbol = g_strdup_printf (".Lm_%x", i + 1);
2956                         emit_symbol_diff (acfg, symbol, "methods", 0);
2957                 } else {
2958                         emit_int32 (acfg, 0xffffffff);
2959                 }
2960         }
2961         emit_line (acfg);
2962 }
2963
2964 static void
2965 emit_info (MonoAotCompile *acfg)
2966 {
2967         int i;
2968         char *symbol;
2969         GList *l;
2970
2971         /* Emit method info */
2972         symbol = g_strdup_printf ("method_info");
2973         emit_section_change (acfg, ".text", 1);
2974         emit_global (acfg, symbol, FALSE);
2975         emit_alignment (acfg, 8);
2976         emit_label (acfg, symbol);
2977
2978         /* To reduce size of generated assembly code */
2979         symbol = g_strdup_printf ("mi");
2980         emit_label (acfg, symbol);
2981
2982         for (l = acfg->method_order; l != NULL; l = l->next) {
2983                 i = GPOINTER_TO_UINT (l->data);
2984
2985                 if (acfg->cfgs [i])
2986                         emit_method_info (acfg, acfg->cfgs [i]);
2987         }
2988
2989         symbol = g_strdup_printf ("method_info_offsets");
2990         emit_section_change (acfg, ".text", 1);
2991         emit_global (acfg, symbol, FALSE);
2992         emit_alignment (acfg, 8);
2993         emit_label (acfg, symbol);
2994
2995         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
2996                 if (acfg->cfgs [i]) {
2997                         symbol = g_strdup_printf (".Lm_%x_p", i + 1);
2998                         emit_symbol_diff (acfg, symbol, "mi", 0);
2999                 } else {
3000                         emit_int32 (acfg, 0);
3001                 }
3002         }
3003         emit_line (acfg);
3004 }
3005
3006 static void
3007 emit_method_order (MonoAotCompile *acfg)
3008 {
3009         int i, index, len;
3010         char *symbol;
3011         GList *l;
3012
3013         symbol = g_strdup_printf ("method_order");
3014         emit_section_change (acfg, ".text", 1);
3015         emit_global (acfg, symbol, FALSE);
3016         emit_alignment (acfg, 8);
3017         emit_label (acfg, symbol);
3018
3019         /* First emit an index table */
3020         index = 0;
3021         len = 0;
3022         for (l = acfg->method_order; l != NULL; l = l->next) {
3023                 i = GPOINTER_TO_UINT (l->data);
3024
3025                 if (acfg->cfgs [i]) {
3026                         if ((index % 1024) == 0) {
3027                                 emit_int32 (acfg, i);
3028                         }
3029
3030                         index ++;
3031                 }
3032
3033                 len ++;
3034         }
3035         emit_int32 (acfg, 0xffffff);
3036
3037         /* Then emit the whole method order */
3038         for (l = acfg->method_order; l != NULL; l = l->next) {
3039                 i = GPOINTER_TO_UINT (l->data);
3040
3041                 if (acfg->cfgs [i]) {
3042                         emit_int32 (acfg, i);
3043                 }
3044         }       
3045         emit_line (acfg);
3046
3047         symbol = g_strdup_printf ("method_order_end");
3048         emit_section_change (acfg, ".text", 1);
3049         emit_global (acfg, symbol, FALSE);
3050         emit_label (acfg, symbol);
3051 }
3052
3053 static void
3054 emit_exception_info (MonoAotCompile *acfg)
3055 {
3056         int i;
3057         char *symbol;
3058
3059         symbol = g_strdup_printf ("ex_info");
3060         emit_section_change (acfg, ".text", 1);
3061         emit_global (acfg, symbol, FALSE);
3062         emit_alignment (acfg, 8);
3063         emit_label (acfg, symbol);
3064
3065         /* To reduce size of generate assembly */
3066         symbol = g_strdup_printf ("ex");
3067         emit_label (acfg, symbol);
3068
3069         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
3070                 if (acfg->cfgs [i])
3071                         emit_exception_debug_info (acfg, acfg->cfgs [i]);
3072         }
3073
3074         symbol = g_strdup_printf ("ex_info_offsets");
3075         emit_section_change (acfg, ".text", 1);
3076         emit_global (acfg, symbol, FALSE);
3077         emit_alignment (acfg, 8);
3078         emit_label (acfg, symbol);
3079
3080         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
3081                 if (acfg->cfgs [i]) {
3082                         symbol = g_strdup_printf (".Le_%x_p", i + 1);
3083                         emit_symbol_diff (acfg, symbol, "ex", 0);
3084                 } else {
3085                         emit_int32 (acfg, 0);
3086                 }
3087         }
3088         emit_line (acfg);
3089 }
3090
3091 static void
3092 emit_class_info (MonoAotCompile *acfg)
3093 {
3094         int i;
3095         char *symbol;
3096
3097         symbol = g_strdup_printf ("class_info");
3098         emit_section_change (acfg, ".text", 1);
3099         emit_global (acfg, symbol, FALSE);
3100         emit_alignment (acfg, 8);
3101         emit_label (acfg, symbol);
3102
3103         for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
3104                 emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
3105
3106         symbol = g_strdup_printf ("class_info_offsets");
3107         emit_section_change (acfg, ".text", 1);
3108         emit_global (acfg, symbol, FALSE);
3109         emit_alignment (acfg, 8);
3110         emit_label (acfg, symbol);
3111
3112         for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
3113                 symbol = g_strdup_printf (".LK_I_%x", i);
3114                 emit_symbol_diff (acfg, symbol, "class_info", 0);
3115         }
3116         emit_line (acfg);
3117 }
3118
3119 typedef struct ClassNameTableEntry {
3120         guint32 token, index;
3121         struct ClassNameTableEntry *next;
3122 } ClassNameTableEntry;
3123
3124 static void
3125 emit_class_name_table (MonoAotCompile *acfg)
3126 {
3127         int i, table_size;
3128         guint32 token, hash;
3129         MonoClass *klass;
3130         GPtrArray *table;
3131         char *full_name;
3132         char *symbol;
3133         ClassNameTableEntry *entry, *new_entry;
3134
3135         /*
3136          * Construct a chained hash table for mapping class names to typedef tokens.
3137          */
3138         table_size = g_spaced_primes_closest ((int)(acfg->image->tables [MONO_TABLE_TYPEDEF].rows * 1.5));
3139         table = g_ptr_array_sized_new (table_size);
3140         for (i = 0; i < table_size; ++i)
3141                 g_ptr_array_add (table, NULL);
3142         for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
3143                 token = MONO_TOKEN_TYPE_DEF | (i + 1);
3144                 klass = mono_class_get (acfg->image, token);
3145                 full_name = mono_type_get_full_name (klass);
3146                 hash = g_str_hash (full_name) % table_size;
3147
3148                 //printf ("A: '%s' %d %d\n", full_name, g_str_hash (full_name), hash);
3149
3150                 /* FIXME: Allocate from the mempool */
3151                 new_entry = g_new0 (ClassNameTableEntry, 1);
3152                 new_entry->token = token;
3153
3154                 entry = g_ptr_array_index (table, hash);
3155                 if (entry == NULL) {
3156                         new_entry->index = hash;
3157                         g_ptr_array_index (table, hash) = new_entry;
3158                 } else {
3159                         while (entry->next)
3160                                 entry = entry->next;
3161                         
3162                         entry->next = new_entry;
3163                         new_entry->index = table->len;
3164                         g_ptr_array_add (table, new_entry);
3165                 }
3166         }
3167
3168         /* Emit the table */
3169         symbol = g_strdup_printf ("class_name_table");
3170         emit_section_change (acfg, ".text", 0);
3171         emit_global (acfg, symbol, FALSE);
3172         emit_alignment (acfg, 8);
3173         emit_label (acfg, symbol);
3174
3175         /* FIXME: Optimize memory usage */
3176         g_assert (table_size < 65000);
3177         emit_int16 (acfg, table_size);
3178         g_assert (table->len < 65000);
3179         for (i = 0; i < table->len; ++i) {
3180                 ClassNameTableEntry *entry = g_ptr_array_index (table, i);
3181
3182                 if (entry == NULL) {
3183                         emit_int16 (acfg, 0);
3184                         emit_int16 (acfg, 0);
3185                 } else {
3186                         emit_int16 (acfg, mono_metadata_token_index (entry->token));
3187                         if (entry->next)
3188                                 emit_int16 (acfg, entry->next->index);
3189                         else
3190                                 emit_int16 (acfg, 0);
3191                 }
3192         }
3193 }
3194
3195 static void
3196 emit_image_table (MonoAotCompile *acfg)
3197 {
3198         int i;
3199         char *symbol;
3200
3201         /*
3202          * The image table is small but referenced in a lot of places.
3203          * So we emit it at once, and reference its elements by an index.
3204          */
3205
3206         symbol = g_strdup_printf ("mono_image_table");
3207         emit_section_change (acfg, ".text", 1);
3208         emit_global (acfg, symbol, FALSE);
3209         emit_alignment (acfg, 8);
3210         emit_label (acfg, symbol);
3211         emit_int32 (acfg, acfg->image_table->len);
3212         for (i = 0; i < acfg->image_table->len; i++) {
3213                 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
3214                 MonoAssemblyName *aname = &image->assembly->aname;
3215
3216                 /* FIXME: Support multi-module assemblies */
3217                 g_assert (image->assembly->image == image);
3218
3219                 emit_string (acfg, image->assembly_name);
3220                 emit_string (acfg, image->guid);
3221                 emit_string (acfg, aname->culture ? aname->culture : "");
3222                 emit_string (acfg, (const char*)aname->public_key_token);
3223
3224                 emit_alignment (acfg, 8);
3225                 emit_int32 (acfg, aname->flags);
3226                 emit_int32 (acfg, aname->major);
3227                 emit_int32 (acfg, aname->minor);
3228                 emit_int32 (acfg, aname->build);
3229                 emit_int32 (acfg, aname->revision);
3230         }
3231 }
3232
3233 static void
3234 emit_got_info (MonoAotCompile *acfg)
3235 {
3236         char *symbol;
3237         int i, buf_size;
3238         guint8 *p, *buf;
3239         guint32 *got_info_offsets;
3240
3241         /**
3242          * FIXME: 
3243          * - optimize offsets table.
3244          * - reduce number of exported symbols.
3245          * - emit info for a klass only once.
3246          * - determine when a method uses a GOT slot which is guaranteed to be already 
3247          *   initialized.
3248          * - clean up and document the code.
3249          * - use String.Empty in class libs.
3250          */
3251
3252         /* Encode info required to decode shared GOT entries */
3253         buf_size = acfg->shared_patches->len * 64;
3254         p = buf = mono_mempool_alloc (acfg->mempool, buf_size);
3255         got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->shared_patches->len * sizeof (guint32));
3256         for (i = 0; i < acfg->shared_patches->len; ++i) {
3257                 MonoJumpInfo *ji = g_ptr_array_index (acfg->shared_patches, i);
3258
3259                 /* No need to encode the patch type */
3260                 got_info_offsets [i] = p - buf;
3261                 encode_patch (acfg, ji, p, &p, FALSE);
3262         }
3263
3264         g_assert (p - buf <= buf_size);
3265
3266         acfg->stats.got_info_size = p - buf;
3267
3268         /* Emit got_info table */
3269         symbol = g_strdup_printf ("got_info");
3270         emit_section_change (acfg, ".text", 1);
3271         emit_global (acfg, symbol, FALSE);
3272         emit_alignment (acfg, 8);
3273         emit_label (acfg, symbol);
3274
3275         emit_bytes (acfg, buf, p - buf);
3276
3277         /* Emit got_info_offsets table */
3278         symbol = g_strdup_printf ("got_info_offsets");
3279         emit_section_change (acfg, ".text", 1);
3280         emit_global (acfg, symbol, FALSE);
3281         emit_alignment (acfg, 8);
3282         emit_label (acfg, symbol);
3283
3284         for (i = 0; i < acfg->shared_patches->len; ++i)
3285                 emit_int32 (acfg, got_info_offsets [i]);
3286
3287         acfg->stats.got_info_offsets_size = acfg->shared_patches->len * 4;
3288 }
3289
3290 static void
3291 emit_got (MonoAotCompile *acfg)
3292 {
3293         char *symbol;
3294
3295         /* Don't make GOT global so accesses to it don't need relocations */
3296         symbol = g_strdup_printf ("got");
3297         emit_section_change (acfg, ".bss", 1);
3298         emit_alignment (acfg, 8);
3299         emit_label (acfg, symbol);
3300         if (acfg->got_offset > 0)
3301                 emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
3302
3303         symbol = g_strdup_printf ("got_addr");
3304         emit_section_change (acfg, ".data", 1);
3305         emit_global (acfg, symbol, FALSE);
3306         emit_alignment (acfg, 8);
3307         emit_label (acfg, symbol);
3308         emit_pointer (acfg, "got");
3309
3310         symbol = g_strdup_printf ("got_size");
3311         emit_section_change (acfg, ".data", 1);
3312         emit_global (acfg, symbol, FALSE);
3313         emit_alignment (acfg, 8);
3314         emit_label (acfg, symbol);
3315         emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
3316 }
3317
3318 static void
3319 emit_globals (MonoAotCompile *acfg)
3320 {
3321         char *opts_str;
3322
3323         emit_string_symbol (acfg, "mono_assembly_guid" , acfg->image->guid);
3324
3325         emit_string_symbol (acfg, "mono_aot_version", MONO_AOT_FILE_VERSION);
3326
3327         opts_str = g_strdup_printf ("%d", acfg->opts);
3328         emit_string_symbol (acfg, "mono_aot_opt_flags", opts_str);
3329         g_free (opts_str);
3330 }
3331
3332 int
3333 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
3334 {
3335         MonoImage *image = ass->image;
3336         char *symbol;
3337         int i;
3338         MonoAotCompile *acfg;
3339         MonoCompile **cfgs;
3340
3341         printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
3342
3343         acfg = g_new0 (MonoAotCompile, 1);
3344         acfg->plt_offset_to_patch = g_hash_table_new (NULL, NULL);
3345         acfg->patch_to_plt_offset = g_hash_table_new (NULL, NULL);
3346         acfg->patch_to_shared_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
3347         acfg->shared_patches = g_ptr_array_new ();
3348         acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
3349         acfg->token_info_hash = g_hash_table_new (NULL, NULL);
3350         acfg->image_hash = g_hash_table_new (NULL, NULL);
3351         acfg->image_table = g_ptr_array_new ();
3352         acfg->image = image;
3353         acfg->opts = opts;
3354         acfg->mempool = mono_mempool_new ();
3355
3356         mono_aot_parse_options (aot_options, &acfg->aot_opts);
3357
3358         load_profile_files (acfg);
3359
3360 #if 0
3361         if (mono_defaults.generic_nullable_class) {
3362                 /* 
3363                  * FIXME: Its hard to skip generic methods or methods which use generics.
3364                  */
3365                 printf ("Error: Can't AOT Net 2.0 assemblies.\n");
3366                 return 1;
3367         }
3368 #endif
3369
3370         emit_start (acfg);
3371
3372         cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
3373         acfg->cfgs = cfgs;
3374         acfg->nmethods = image->tables [MONO_TABLE_METHOD].rows;
3375         acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
3376         acfg->has_got_slots = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows + 32);
3377
3378         /* PLT offset 0 is reserved for the PLT trampoline */
3379         acfg->plt_offset = 1;
3380
3381         /* Compile methods */
3382         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i)
3383                 compile_method (acfg, i);
3384
3385         alloc_got_slots (acfg);
3386
3387         emit_code (acfg);
3388
3389         emit_info (acfg);
3390
3391         emit_method_order (acfg);
3392
3393         emit_class_name_table (acfg);
3394
3395         emit_got_info (acfg);
3396
3397         emit_exception_info (acfg);
3398
3399         emit_class_info (acfg);
3400
3401         emit_plt (acfg);
3402
3403         emit_image_table (acfg);
3404
3405         emit_got (acfg);
3406
3407         emit_globals (acfg);
3408
3409         symbol = g_strdup_printf ("mem_end");
3410         emit_section_change (acfg, ".text", 1);
3411         emit_global (acfg, symbol, FALSE);
3412         emit_alignment (acfg, 8);
3413         emit_label (acfg, symbol);
3414
3415         printf ("Code: %d Info: %d Ex Info: %d Class Info: %d PLT: %d GOT Info: %d GOT Info Offsets: %d GOT: %d\n", acfg->stats.code_size, acfg->stats.info_size, acfg->stats.ex_info_size, acfg->stats.class_info_size, acfg->plt_offset, acfg->stats.got_info_size, acfg->stats.got_info_offsets_size, (int)(acfg->got_offset * sizeof (gpointer)));
3416
3417         emit_writeout (acfg);
3418
3419         printf ("Compiled %d out of %d methods (%d%%)\n", acfg->stats.ccount, acfg->stats.mcount, acfg->stats.mcount ? (acfg->stats.ccount * 100) / acfg->stats.mcount : 100);
3420         printf ("%d methods are generic (%d%%)\n", acfg->stats.genericcount, acfg->stats.mcount ? (acfg->stats.genericcount * 100) / acfg->stats.mcount : 100);
3421         printf ("%d methods contain absolute addresses (%d%%)\n", acfg->stats.abscount, acfg->stats.mcount ? (acfg->stats.abscount * 100) / acfg->stats.mcount : 100);
3422         printf ("%d methods contain wrapper references (%d%%)\n", acfg->stats.wrappercount, acfg->stats.mcount ? (acfg->stats.wrappercount * 100) / acfg->stats.mcount : 100);
3423         printf ("%d methods contain lmf pointers (%d%%)\n", acfg->stats.lmfcount, acfg->stats.mcount ? (acfg->stats.lmfcount * 100) / acfg->stats.mcount : 100);
3424         printf ("%d methods have other problems (%d%%)\n", acfg->stats.ocount, acfg->stats.mcount ? (acfg->stats.ocount * 100) / acfg->stats.mcount : 100);
3425         printf ("Methods without GOT slots: %d (%d%%)\n", acfg->stats.methods_without_got_slots, acfg->stats.mcount ? (acfg->stats.methods_without_got_slots * 100) / acfg->stats.mcount : 100);
3426         printf ("Direct calls: %d (%d%%)\n", acfg->stats.direct_calls, acfg->stats.all_calls ? (acfg->stats.direct_calls * 100) / acfg->stats.all_calls : 100);
3427
3428         printf ("GOT slot distribution:\n");
3429         for (i = 0; i < MONO_PATCH_INFO_NONE; ++i)
3430                 if (acfg->stats.got_slot_types [i])
3431                         printf ("\t%s: %d\n", get_patch_name (i), acfg->stats.got_slot_types [i]);
3432
3433         return 0;
3434 }
3435
3436 #else
3437
3438 /* AOT disabled */
3439
3440 int
3441 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
3442 {
3443         return 0;
3444 }
3445
3446 #endif