2009-05-23 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / image-writer.c
1 /*
2  * image-writer.c: Creation of object files or assembly files using the same interface.
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Zoltan Varga (vargaz@gmail.com)
7  *   Paolo Molaro (lupus@ximian.com)
8  *
9  * (C) 2002 Ximian, Inc.
10  */
11
12 #include "config.h"
13 #include <sys/types.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 #ifdef HAVE_STDINT_H
18 #include <stdint.h>
19 #endif
20 #include <fcntl.h>
21 #include <ctype.h>
22 #include <string.h>
23 #ifndef PLATFORM_WIN32
24 #include <sys/time.h>
25 #else
26 #include <winsock2.h>
27 #include <windows.h>
28 #endif
29
30 #include <errno.h>
31 #include <sys/stat.h>
32 #include <limits.h>    /* for PAGESIZE */
33 #ifndef PAGESIZE
34 #define PAGESIZE 4096
35 #endif
36
37 #include "image-writer.h"
38
39 #ifndef PLATFORM_WIN32
40 #include <mono/utils/freebsd-elf32.h>
41 #include <mono/utils/freebsd-elf64.h>
42 #endif
43
44 #include "mini.h"
45
46 #define TV_DECLARE(name) gint64 name
47 #define TV_GETTIME(tv) tv = mono_100ns_ticks ()
48 #define TV_ELAPSED(start,end) (((end) - (start)) / 10)
49
50 /* 
51  * The used assembler dialect
52  * TARGET_ASM_APPLE == apple assembler on OSX
53  * TARGET_ASM_GAS == GNU assembler
54  */
55 #ifndef TARGET_ASM
56 #ifdef __MACH__
57 #define TARGET_ASM APPLE
58 #else
59 #define TARGET_ASM GAS
60 #endif
61 #endif
62
63 #if TARGET_ASM == APPLE
64 #define TARGET_ASM_APPLE
65 #elif TARGET_ASM == GAS
66 #define TARGET_ASM_GAS
67 #endif
68
69 /*
70  * Defines for the directives used by different assemblers
71  */
72 #if defined(__ppc__) || defined(__powerpc__) || defined(__MACH__)
73 #define AS_STRING_DIRECTIVE ".asciz"
74 #else
75 #define AS_STRING_DIRECTIVE ".string"
76 #endif
77
78 #define AS_INT32_DIRECTIVE ".long"
79 #define AS_INT64_DIRECTIVE ".quad"
80
81 #if defined(TARGET_ASM_APPLE)
82 #define AS_INT16_DIRECTIVE ".short"
83 #elif defined(TARGET_ASM_GAS)
84 #define AS_INT16_DIRECTIVE ".hword"
85 #else
86 #define AS_INT16_DIRECTIVE ".word"
87 #endif
88
89 #if defined(TARGET_ASM_APPLE)
90 #define AS_SKIP_DIRECTIVE ".space"
91 #else
92 #define AS_SKIP_DIRECTIVE ".skip"
93 #endif
94
95
96 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
97 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
98 #define ROUND_DOWN(VALUE,SIZE)  ((VALUE) & ~((SIZE) - 1))
99
100 #if defined(TARGET_AMD64) && !defined(PLATFORM_WIN32)
101 #define USE_ELF_WRITER 1
102 #define USE_ELF_RELA 1
103 #endif
104
105 #if defined(TARGET_X86) && !defined(PLATFORM_WIN32)
106 #define USE_ELF_WRITER 1
107 #endif
108
109 #if defined(TARGET_ARM) && !defined(__MACH__)
110 #define USE_ELF_WRITER 1
111 #endif
112
113 #if defined(__mips__)
114 #define USE_ELF_WRITER 1
115 #endif
116
117 #if defined(USE_ELF_WRITER)
118 #define USE_BIN_WRITER 1
119 #endif
120
121 #ifdef USE_BIN_WRITER
122
123 typedef struct _BinSymbol BinSymbol;
124 typedef struct _BinReloc BinReloc;
125 typedef struct _BinSection BinSection;
126
127 #endif
128
129 /* emit mode */
130 enum {
131         EMIT_NONE,
132         EMIT_BYTE,
133         EMIT_WORD,
134         EMIT_LONG
135 };
136
137 struct _MonoImageWriter {
138         MonoMemPool *mempool;
139         char *outfile;
140         gboolean use_bin_writer;
141         const char *current_section;
142         int current_subsection;
143         const char *section_stack [16];
144         int subsection_stack [16];
145         int stack_pos;
146         FILE *fp;
147         /* Bin writer */
148 #ifdef USE_BIN_WRITER
149         BinSymbol *symbols;
150         BinSection *sections;
151         BinSection *cur_section;
152         BinReloc *relocations;
153         GHashTable *labels;
154         int num_relocs;
155 #endif
156         /* Asm writer */
157         char *tmpfname;
158         int mode; /* emit mode */
159         int col_count; /* bytes emitted per .byte line */
160 };
161
162 static G_GNUC_UNUSED int
163 ilog2(register int value)
164 {
165         int count = -1;
166         while (value & ~0xf) count += 4, value >>= 4;
167         while (value) count++, value >>= 1;
168         return count;
169 }
170
171 #ifdef USE_BIN_WRITER
172
173 typedef struct _BinLabel BinLabel;
174 struct _BinLabel {
175         char *name;
176         BinSection *section;
177         int offset;
178 };
179
180 struct _BinReloc {
181         BinReloc *next;
182         char *val1;
183         char *val2;
184         BinSection *val2_section;
185         int val2_offset;
186         int offset;
187         BinSection *section;
188         int section_offset;
189         int reloc_type;
190 };
191
192 struct _BinSymbol {
193         BinSymbol *next;
194         char *name;
195         BinSection *section;
196         int offset;
197         gboolean is_function;
198         gboolean is_global;
199         char *end_label;
200 };
201
202 struct _BinSection {
203         BinSection *next;
204         BinSection *parent;
205         char *name;
206         int subsection;
207         guint8 *data;
208         int data_len;
209         int cur_offset;
210         int file_offset;
211         int virt_offset;
212         int shidx;
213 };
214
215 static void
216 bin_writer_emit_start (MonoImageWriter *acfg)
217 {
218         acfg->labels = g_hash_table_new (g_str_hash, g_str_equal);
219 }
220
221 static void
222 bin_writer_emit_section_change (MonoImageWriter *acfg, const char *section_name, int subsection_index)
223 {
224         BinSection *section;
225
226         if (acfg->cur_section && acfg->cur_section->subsection == subsection_index
227                         && strcmp (acfg->cur_section->name, section_name) == 0)
228                 return;
229         for (section = acfg->sections; section; section = section->next) {
230                 if (section->subsection == subsection_index && strcmp (section->name, section_name) == 0) {
231                         acfg->cur_section = section;
232                         return;
233                 }
234         }
235         if (!section) {
236                 section = g_new0 (BinSection, 1);
237                 section->name = g_strdup (section_name);
238                 section->subsection = subsection_index;
239                 section->next = acfg->sections;
240                 acfg->sections = section;
241                 acfg->cur_section = section;
242         }
243 }
244
245 static void
246 bin_writer_emit_symbol_inner (MonoImageWriter *acfg, const char *name, const char *end_label, gboolean is_global, gboolean func)
247 {
248         BinSymbol *symbol = g_new0 (BinSymbol, 1);
249         symbol->name = g_strdup (name);
250         if (end_label)
251                 symbol->end_label = g_strdup (end_label);
252         symbol->is_function = func;
253         symbol->is_global = is_global;
254         symbol->section = acfg->cur_section;
255         /* FIXME: we align after this call... */
256         symbol->offset = symbol->section->cur_offset;
257         symbol->next = acfg->symbols;
258         acfg->symbols = symbol;
259 }
260
261 static void
262 bin_writer_emit_global (MonoImageWriter *acfg, const char *name, gboolean func)
263 {
264         bin_writer_emit_symbol_inner (acfg, name, NULL, TRUE, func);
265 }
266
267 static void
268 bin_writer_emit_local_symbol (MonoImageWriter *acfg, const char *name, const char *end_label, gboolean func)
269 {
270         bin_writer_emit_symbol_inner (acfg, name, end_label, FALSE, func);
271 }
272
273 static void
274 bin_writer_emit_label (MonoImageWriter *acfg, const char *name)
275 {
276         BinLabel *label = g_new0 (BinLabel, 1);
277         label->name = g_strdup (name);
278         label->section = acfg->cur_section;
279         label->offset = acfg->cur_section->cur_offset;
280         g_hash_table_insert (acfg->labels, label->name, label);
281 }
282
283 static void
284 bin_writer_emit_ensure_buffer (BinSection *section, int size)
285 {
286         int new_offset = section->cur_offset + size;
287         if (new_offset >= section->data_len) {
288                 int new_size = section->data_len? section->data_len * 2: 256;
289                 guint8 *data;
290                 while (new_size <= new_offset)
291                         new_size *= 2;
292                 data = g_malloc0 (new_size);
293                 memcpy (data, section->data, section->data_len);
294                 g_free (section->data);
295                 section->data = data;
296                 section->data_len = new_size;
297         }
298 }
299
300 static void
301 bin_writer_emit_bytes (MonoImageWriter *acfg, const guint8* buf, int size)
302 {
303         bin_writer_emit_ensure_buffer (acfg->cur_section, size);
304         memcpy (acfg->cur_section->data + acfg->cur_section->cur_offset, buf, size);
305         acfg->cur_section->cur_offset += size;
306 }
307
308 static void
309 bin_writer_emit_string (MonoImageWriter *acfg, const char *value)
310 {
311         int size = strlen (value) + 1;
312         bin_writer_emit_bytes (acfg, (const guint8*)value, size);
313 }
314
315 static void
316 bin_writer_emit_line (MonoImageWriter *acfg)
317 {
318         /* Nothing to do in binary writer */
319 }
320
321 static void 
322 bin_writer_emit_alignment (MonoImageWriter *acfg, int size)
323 {
324         int offset = acfg->cur_section->cur_offset;
325         int add;
326         offset += (size - 1);
327         offset &= ~(size - 1);
328         add = offset - acfg->cur_section->cur_offset;
329         if (add) {
330                 bin_writer_emit_ensure_buffer (acfg->cur_section, add);
331                 acfg->cur_section->cur_offset += add;
332         }
333 }
334
335 static void
336 bin_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target)
337 {
338         BinReloc *reloc;
339
340         if (!target)
341                 // FIXME:
342                 g_assert_not_reached ();
343         reloc = g_new0 (BinReloc, 1);
344         reloc->val1 = g_strdup (target);
345         reloc->section = acfg->cur_section;
346         reloc->section_offset = acfg->cur_section->cur_offset;
347         reloc->next = acfg->relocations;
348         acfg->relocations = reloc;
349         if (strcmp (reloc->section->name, ".data") == 0) {
350                 acfg->num_relocs++;
351                 //g_print ("reloc: %s at %d\n", target, acfg->cur_section->cur_offset);
352         }
353         acfg->cur_section->cur_offset += sizeof (gpointer);
354 }
355
356 static void
357 bin_writer_emit_pointer (MonoImageWriter *acfg, const char *target)
358 {
359         bin_writer_emit_alignment (acfg, sizeof (gpointer));
360         bin_writer_emit_pointer_unaligned (acfg, target);
361 }
362
363 static void
364 bin_writer_emit_int16 (MonoImageWriter *acfg, int value)
365 {
366         guint8 *data;
367         bin_writer_emit_ensure_buffer (acfg->cur_section, 2);
368         data = acfg->cur_section->data + acfg->cur_section->cur_offset;
369         acfg->cur_section->cur_offset += 2;
370         /* FIXME: little endian */
371         data [0] = value;
372         data [1] = value >> 8;
373 }
374
375 static void
376 bin_writer_emit_int32 (MonoImageWriter *acfg, int value)
377 {
378         guint8 *data;
379         bin_writer_emit_ensure_buffer (acfg->cur_section, 4);
380         data = acfg->cur_section->data + acfg->cur_section->cur_offset;
381         acfg->cur_section->cur_offset += 4;
382         /* FIXME: little endian */
383         data [0] = value;
384         data [1] = value >> 8;
385         data [2] = value >> 16;
386         data [3] = value >> 24;
387 }
388
389 static BinReloc*
390 create_reloc (MonoImageWriter *acfg, const char *end, const char* start, int offset)
391 {
392         BinReloc *reloc;
393         reloc = mono_mempool_alloc0 (acfg->mempool, sizeof (BinReloc));
394         reloc->val1 = mono_mempool_strdup (acfg->mempool, end);
395         if (strcmp (start, ".") == 0) {
396                 reloc->val2_section = acfg->cur_section;
397                 reloc->val2_offset = acfg->cur_section->cur_offset;
398         } else {
399                 reloc->val2 = mono_mempool_strdup (acfg->mempool, start);
400         }
401         reloc->offset = offset;
402         reloc->section = acfg->cur_section;
403         reloc->section_offset = acfg->cur_section->cur_offset;
404         reloc->next = acfg->relocations;
405         acfg->relocations = reloc;
406         return reloc;
407 }
408
409 static void
410 bin_writer_emit_symbol_diff (MonoImageWriter *acfg, const char *end, const char* start, int offset)
411 {
412         create_reloc (acfg, end, start, offset);
413         acfg->cur_section->cur_offset += 4;
414         /*if (strcmp (reloc->section->name, ".data") == 0) {
415                 acfg->num_relocs++;
416                 g_print ("reloc: %s - %s + %d at %d\n", end, start, offset, acfg->cur_section->cur_offset - 4);
417         }*/
418 }
419
420 /* 
421  * Emit a relocation entry of type RELOC_TYPE against symbol SYMBOL at the current PC.
422  * Do not advance PC.
423  */
424 static G_GNUC_UNUSED void
425 bin_writer_emit_reloc (MonoImageWriter *acfg, int reloc_type, const char *symbol, int addend)
426 {
427         BinReloc *reloc = create_reloc (acfg, symbol, ".", addend);
428         reloc->reloc_type = reloc_type;
429 }
430
431 static void
432 bin_writer_emit_zero_bytes (MonoImageWriter *acfg, int num)
433 {
434         bin_writer_emit_ensure_buffer (acfg->cur_section, num);
435         acfg->cur_section->cur_offset += num;
436 }
437
438 #ifdef USE_ELF_WRITER
439
440 enum {
441         SECT_NULL,
442         SECT_HASH,
443         SECT_DYNSYM,
444         SECT_DYNSTR,
445         SECT_REL_DYN,
446         SECT_RELA_DYN,
447         SECT_TEXT,
448         SECT_DYNAMIC,
449         SECT_GOT_PLT,
450         SECT_DATA,
451         SECT_BSS,
452         SECT_DEBUG_FRAME,
453         SECT_DEBUG_INFO,
454         SECT_DEBUG_ABBREV,
455         SECT_DEBUG_LINE,
456         SECT_DEBUG_LOC,
457         SECT_SHSTRTAB,
458         SECT_SYMTAB,
459         SECT_STRTAB,
460         SECT_NUM
461 };
462
463 #if SIZEOF_VOID_P == 4
464
465 typedef Elf32_Ehdr ElfHeader;
466 typedef Elf32_Shdr ElfSectHeader;
467 typedef Elf32_Phdr ElfProgHeader;
468 typedef Elf32_Sym ElfSymbol;
469 typedef Elf32_Rel ElfReloc;
470 typedef Elf32_Rela ElfRelocA;
471 typedef Elf32_Dyn ElfDynamic;
472
473 #else
474
475 typedef Elf64_Ehdr ElfHeader;
476 typedef Elf64_Shdr ElfSectHeader;
477 typedef Elf64_Phdr ElfProgHeader;
478 typedef Elf64_Sym ElfSymbol;
479 typedef Elf64_Rel ElfReloc;
480 typedef Elf64_Rela ElfRelocA;
481 typedef Elf64_Dyn ElfDynamic;
482
483 #endif
484
485 typedef struct {
486         const char *name;
487         int type;
488         int esize;
489         int flags;
490         int align;
491 } SectInfo;
492
493 static SectInfo section_info [] = {
494         {"", 0, 0, 0, 0},
495         {".hash", SHT_HASH, 4, 2, SIZEOF_VOID_P},
496         {".dynsym", SHT_DYNSYM, sizeof (ElfSymbol), 2, SIZEOF_VOID_P},
497         {".dynstr", SHT_STRTAB, 0, 2, 1},
498         {".rel.dyn", SHT_REL, sizeof (ElfReloc), 2, SIZEOF_VOID_P},
499         {".rela.dyn", SHT_RELA, sizeof (ElfRelocA), 2, SIZEOF_VOID_P},
500         {".text", SHT_PROGBITS, 0, 6, 4096},
501         {".dynamic", SHT_DYNAMIC, sizeof (ElfDynamic), 3, SIZEOF_VOID_P},
502         {".got.plt", SHT_PROGBITS, SIZEOF_VOID_P, 3, SIZEOF_VOID_P},
503         {".data", SHT_PROGBITS, 0, 3, 8},
504         {".bss", SHT_NOBITS, 0, 3, 8},
505         {".debug_frame", SHT_PROGBITS, 0, 0, 8},
506         {".debug_info", SHT_PROGBITS, 0, 0, 1},
507         {".debug_abbrev", SHT_PROGBITS, 0, 0, 1},
508         {".debug_line", SHT_PROGBITS, 0, 0, 1},
509         {".debug_loc", SHT_PROGBITS, 0, 0, 1},
510         {".shstrtab", SHT_STRTAB, 0, 0, 1},
511         {".symtab", SHT_SYMTAB, sizeof (ElfSymbol), 0, SIZEOF_VOID_P},
512         {".strtab", SHT_STRTAB, 0, 0, 1}
513 };
514
515 typedef struct {
516         GString *data;
517         GHashTable *hash;
518 } ElfStrTable;
519
520 static int
521 str_table_add (ElfStrTable *table, const char* value)
522 {
523         int idx;
524         if (!table->data) {
525                 table->data = g_string_new_len ("", 1);
526                 table->hash = g_hash_table_new (g_str_hash, g_str_equal);
527         }
528         idx = GPOINTER_TO_UINT (g_hash_table_lookup (table->hash, value));
529         if (idx)
530                 return idx;
531         idx = table->data->len;
532         g_string_append (table->data, value);
533         g_string_append_c (table->data, 0);
534         g_hash_table_insert (table->hash, (void*)value, GUINT_TO_POINTER (idx));
535         return idx;
536 }
537
538 static void
539 append_subsection (MonoImageWriter *acfg, ElfSectHeader *sheaders, BinSection *sect, BinSection *add)
540 {
541         int offset = sect->cur_offset;
542         /*offset += (sheaders [sect->shidx].sh_addralign - 1);
543         offset &= ~(sheaders [sect->shidx].sh_addralign - 1);*/
544         offset += (8 - 1);
545         offset &= ~(8 - 1);
546         bin_writer_emit_ensure_buffer (sect, offset);
547         //g_print ("section %s aligned to %d from %d\n", sect->name, offset, sect->cur_offset);
548         sect->cur_offset = offset;
549
550         bin_writer_emit_ensure_buffer (sect, add->cur_offset);
551         memcpy (sect->data + sect->cur_offset, add->data, add->cur_offset);
552         add->parent = sect;
553         sect->cur_offset += add->cur_offset;
554         add->cur_offset = offset; /* it becomes the offset in the parent section */
555         //g_print ("subsection %d of %s added at offset %d (align: %d)\n", add->subsection, sect->name, add->cur_offset, (int)sheaders [sect->shidx].sh_addralign);
556         add->data = NULL;
557         add->data_len = 0;
558 }
559
560 /* merge the subsections */
561 static int
562 collect_sections (MonoImageWriter *acfg, ElfSectHeader *sheaders, BinSection **out, int num)
563 {
564         int i, j, maxs, num_sections;
565         BinSection *sect;
566
567         num_sections = 0;
568         maxs = 0;
569         for (sect = acfg->sections; sect; sect = sect->next) {
570                 if (sect->subsection == 0) {
571                         out [num_sections++] = sect;
572                         g_assert (num_sections < num);
573                 }
574                 maxs = MAX (maxs, sect->subsection);
575         }
576         for (i = 0; i < num_sections; i++) {
577                 for (j = 1; j <= maxs; ++j) {
578                         for (sect = acfg->sections; sect; sect = sect->next) {
579                                 if (sect->subsection == j && strcmp (out [i]->name, sect->name) == 0) {
580                                         append_subsection (acfg, sheaders, out [i], sect);
581                                 }
582                         }
583                 }
584         }
585         return num_sections;
586 }
587
588 static unsigned long
589 elf_hash (const unsigned char *name)
590 {
591         unsigned long h = 0, g;
592         while (*name) {
593                 h = (h << 4) + *name++;
594                 if ((g = h & 0xf0000000))
595                         h ^= g >> 24;
596                 h &= ~g;
597         }
598         return h;
599 }
600
601 #define NUM_BUCKETS 17
602
603 static int*
604 build_hash (MonoImageWriter *acfg, int num_sections, ElfStrTable *dynstr)
605 {
606         int *data;
607         int num_symbols = 1 + num_sections + 3;
608         BinSymbol *symbol;
609
610         for (symbol = acfg->symbols; symbol; symbol = symbol->next) {
611                 if (!symbol->is_global)
612                         continue;
613                 num_symbols++;
614                 str_table_add (dynstr, symbol->name);
615                 /*g_print ("adding sym: %s\n", symbol->name);*/
616         }
617         str_table_add (dynstr, "__bss_start");
618         str_table_add (dynstr, "_edata");
619         str_table_add (dynstr, "_end");
620
621         data = g_new0 (int, num_symbols + 2 + NUM_BUCKETS);
622         data [0] = NUM_BUCKETS;
623         data [1] = num_symbols;
624
625         return data;
626 }
627
628 static gsize
629 get_label_addr (MonoImageWriter *acfg, const char *name)
630 {
631         int offset;
632         BinLabel *lab;
633         BinSection *section;
634         gsize value;
635
636         lab = g_hash_table_lookup (acfg->labels, name);
637         if (!lab)
638                 g_error ("Undefined label: '%s'.\n", name);
639         section = lab->section;
640         offset = lab->offset;
641         if (section->parent) {
642                 value = section->parent->virt_offset + section->cur_offset + offset;
643         } else {
644                 value = section->virt_offset + offset;
645         }
646         return value;
647 }
648
649 static ElfSymbol*
650 collect_syms (MonoImageWriter *acfg, int *hash, ElfStrTable *strtab, ElfSectHeader *sheaders, int *num_syms)
651 {
652         ElfSymbol *symbols;
653         BinSymbol *symbol;
654         BinSection *section;
655         int i;
656         int *bucket;
657         int *chain;
658         unsigned long hashc;
659
660         if (hash)
661                 symbols = g_new0 (ElfSymbol, hash [1]);
662         else {
663                 i = 0;
664                 for (symbol = acfg->symbols; symbol; symbol = symbol->next)
665                         i ++;
666                 
667                 symbols = g_new0 (ElfSymbol, i + SECT_NUM + 10); /* FIXME */
668         }
669
670         /* the first symbol is undef, all zeroes */
671         i = 1;
672         if (sheaders) {
673                 int j;
674                 for (j = 1; j < SECT_NUM; ++j) {
675                         symbols [i].st_info = ELF32_ST_INFO (STB_LOCAL, STT_SECTION);
676                         symbols [i].st_shndx = j;
677                         symbols [i].st_value = sheaders [j].sh_addr;
678                         ++i;
679                 }
680         } else {
681                 for (section = acfg->sections; section; section = section->next) {
682                         if (section->parent)
683                                 continue;
684                         symbols [i].st_info = ELF32_ST_INFO (STB_LOCAL, STT_SECTION);
685                         if (strcmp (section->name, ".text") == 0) {
686                                 symbols [i].st_shndx = SECT_TEXT;
687                                 section->shidx = SECT_TEXT;
688                                 section->file_offset = 4096;
689                                 symbols [i].st_value = section->virt_offset;
690                         } else if (strcmp (section->name, ".data") == 0) {
691                                 symbols [i].st_shndx = SECT_DATA;
692                                 section->shidx = SECT_DATA;
693                                 section->file_offset = 4096 + 28; /* FIXME */
694                                 symbols [i].st_value = section->virt_offset;
695                         } else if (strcmp (section->name, ".bss") == 0) {
696                                 symbols [i].st_shndx = SECT_BSS;
697                                 section->shidx = SECT_BSS;
698                                 section->file_offset = 4096 + 28 + 8; /* FIXME */
699                                 symbols [i].st_value = section->virt_offset;
700                         }
701                         ++i;
702                 }
703         }
704         for (symbol = acfg->symbols; symbol; symbol = symbol->next) {
705                 int offset;
706                 BinLabel *lab;
707                 if (!symbol->is_global && hash)
708                         continue;
709                 symbols [i].st_info = ELF32_ST_INFO (symbol->is_global ? STB_GLOBAL : STB_LOCAL, symbol->is_function? STT_FUNC : STT_OBJECT);
710                 symbols [i].st_name = str_table_add (strtab, symbol->name);
711                 /*g_print ("sym name %s tabled to %d\n", symbol->name, symbols [i].st_name);*/
712                 section = symbol->section;
713                 symbols [i].st_shndx = section->parent? section->parent->shidx: section->shidx;
714                 lab = g_hash_table_lookup (acfg->labels, symbol->name);
715                 offset = lab->offset;
716                 if (section->parent) {
717                         symbols [i].st_value = section->parent->virt_offset + section->cur_offset + offset;
718                 } else {
719                         symbols [i].st_value = section->virt_offset + offset;
720                 }
721
722                 if (symbol->end_label) {
723                         BinLabel *elab = g_hash_table_lookup (acfg->labels, symbol->end_label);
724                         g_assert (elab);
725                         symbols [i].st_size = elab->offset - lab->offset;
726                 }
727                 ++i;
728         }
729         /* add special symbols */
730         symbols [i].st_name = str_table_add (strtab, "__bss_start");
731         symbols [i].st_shndx = 0xfff1;
732         symbols [i].st_info = ELF32_ST_INFO (STB_GLOBAL, 0);
733         ++i;
734         symbols [i].st_name = str_table_add (strtab, "_edata");
735         symbols [i].st_shndx = 0xfff1;
736         symbols [i].st_info = ELF32_ST_INFO (STB_GLOBAL, 0);
737         ++i;
738         symbols [i].st_name = str_table_add (strtab, "_end");
739         symbols [i].st_shndx = 0xfff1;
740         symbols [i].st_info = ELF32_ST_INFO (STB_GLOBAL, 0);
741         ++i;
742
743         if (num_syms)
744                 *num_syms = i;
745
746         /* add to hash table */
747         if (hash) {
748                 bucket = hash + 2;
749                 chain = hash + 2 + hash [0];
750                 for (i = 0; i < hash [1]; ++i) {
751                         int slot;
752                         /*g_print ("checking %d '%s' (sym %d)\n", symbols [i].st_name, strtab->data->str + symbols [i].st_name, i);*/
753                         if (!symbols [i].st_name)
754                                 continue;
755                         hashc = elf_hash ((guint8*)strtab->data->str + symbols [i].st_name);
756                         slot = hashc % hash [0];
757                         /*g_print ("hashing '%s' at slot %d (sym %d)\n", strtab->data->str + symbols [i].st_name, slot, i);*/
758                         if (bucket [slot]) {
759                                 chain [i] = bucket [slot];
760                                 bucket [slot] = i;
761                         } else {
762                                 bucket [slot] = i;
763                         }
764                 }
765         }
766         return symbols;
767 }
768
769 static void
770 reloc_symbols (MonoImageWriter *acfg, ElfSymbol *symbols, ElfSectHeader *sheaders, ElfStrTable *strtab, gboolean dynamic)
771 {
772         BinSection *section;
773         BinSymbol *symbol;
774         int i;
775
776         i = 1;
777         if (dynamic) {
778                 for (section = acfg->sections; section; section = section->next) {
779                         if (section->parent)
780                                 continue;
781                         symbols [i].st_value = sheaders [section->shidx].sh_addr;
782                         ++i;
783                 }
784         } else {
785                 for (i = 1; i < SECT_NUM; ++i) {
786                         symbols [i].st_value = sheaders [i].sh_addr;
787                 }
788         }
789         for (symbol = acfg->symbols; symbol; symbol = symbol->next) {
790                 int offset;
791                 BinLabel *lab;
792                 if (dynamic && !symbol->is_global)
793                         continue;
794                 section = symbol->section;
795                 lab = g_hash_table_lookup (acfg->labels, symbol->name);
796                 offset = lab->offset;
797                 if (section->parent) {
798                         symbols [i].st_value = sheaders [section->parent->shidx].sh_addr + section->cur_offset + offset;
799                 } else {
800                         symbols [i].st_value = sheaders [section->shidx].sh_addr + offset;
801                 }
802                 ++i;
803         }
804         /* __bss_start */
805         symbols [i].st_value = sheaders [SECT_BSS].sh_addr;
806         ++i;
807         /* _edata */
808         symbols [i].st_value = sheaders [SECT_DATA].sh_addr + sheaders [SECT_DATA].sh_size;
809         ++i;
810         /* _end */
811         symbols [i].st_value = sheaders [SECT_BSS].sh_addr + sheaders [SECT_BSS].sh_size;
812         ++i;
813 }
814
815 static void
816 resolve_reloc (MonoImageWriter *acfg, BinReloc *reloc, guint8 **out_data, gsize *out_vaddr, gsize *out_start_val, gsize *out_end_val)
817 {
818         guint8 *data;
819         gssize end_val, start_val;
820         gsize vaddr;
821
822         end_val = get_label_addr (acfg, reloc->val1);
823         if (reloc->val2) {
824                 start_val = get_label_addr (acfg, reloc->val2);
825         } else if (reloc->val2_section) {
826                 start_val = reloc->val2_offset;
827                 if (reloc->val2_section->parent)
828                         start_val += reloc->val2_section->parent->virt_offset + reloc->val2_section->cur_offset;
829                 else
830                         start_val += reloc->val2_section->virt_offset;
831         } else {
832                 start_val = 0;
833         }
834         end_val = end_val - start_val + reloc->offset;
835         if (reloc->section->parent) {
836                 data = reloc->section->parent->data;
837                 data += reloc->section->cur_offset;
838                 data += reloc->section_offset;
839                 vaddr = reloc->section->parent->virt_offset;
840                 vaddr += reloc->section->cur_offset;
841                 vaddr += reloc->section_offset;
842         } else {
843                 data = reloc->section->data;
844                 data += reloc->section_offset;
845                 vaddr = reloc->section->virt_offset;
846                 vaddr += reloc->section_offset;
847         }
848
849         *out_start_val = start_val;
850         *out_end_val = end_val;
851         *out_data = data;
852         *out_vaddr = vaddr;
853 }
854
855 #ifdef USE_ELF_RELA
856
857 static ElfRelocA*
858 resolve_relocations (MonoImageWriter *acfg)
859 {
860         BinReloc *reloc;
861         guint8 *data;
862         gsize end_val, start_val;
863         ElfRelocA *rr;
864         int i;
865         gsize vaddr;
866
867         rr = g_new0 (ElfRelocA, acfg->num_relocs);
868         i = 0;
869
870         for (reloc = acfg->relocations; reloc; reloc = reloc->next) {
871                 resolve_reloc (acfg, reloc, &data, &vaddr, &start_val, &end_val);
872                 /* FIXME: little endian */
873                 data [0] = end_val;
874                 data [1] = end_val >> 8;
875                 data [2] = end_val >> 16;
876                 data [3] = end_val >> 24;
877                 // FIXME:
878                 if (start_val == 0 && reloc->val1 [0] != '.') {
879                         rr [i].r_offset = vaddr;
880                         rr [i].r_info = R_X86_64_RELATIVE;
881                         rr [i].r_addend = end_val;
882                         ++i;
883                         g_assert (i <= acfg->num_relocs);
884                 }
885         }
886         return rr;
887 }
888
889 #else /* USE_ELF_RELA */
890
891 static void
892 do_reloc (MonoImageWriter *acfg, BinReloc *reloc, guint8 *data, gssize addr)
893 {
894 #ifdef TARGET_ARM
895         /*
896          * We use the official ARM relocation types, but implement only the stuff actually
897          * needed by the code we generate.
898          */
899         switch (reloc->reloc_type) {
900         case R_ARM_CALL:
901         case R_ARM_JUMP24: {
902                 guint32 *code = (guint32*)(gpointer)data;
903                 guint32 ins = *code;
904                 int diff = addr;
905
906                 if (reloc->reloc_type == R_ARM_CALL)
907                         /* bl */
908                         g_assert (data [3] == 0xeb);
909                 else
910                         /* b */
911                         g_assert (data [3] == 0xea);
912                 if (diff >= 0 && diff <= 33554431) {
913                         diff >>= 2;
914                         ins = (ins & 0xff000000) | diff;
915                         *code = ins;
916                 } else if (diff <= 0 && diff >= -33554432) {
917                         diff >>= 2;
918                         ins = (ins & 0xff000000) | (diff & ~0xff000000);
919                         *code = ins;
920                 } else {
921                         g_assert_not_reached ();
922                 }
923                 break;
924         }
925         case R_ARM_ALU_PC_G0_NC: {
926                 /* Generated by emit_plt () */
927                 guint8 *code = data;
928                 guint32 val = addr;
929
930                 g_assert (val <= 0xffffff);
931                 if (val & 0xff0000)
932                         ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_PC, (val & 0xFF0000) >> 16, 16);
933                 else
934                         ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_PC, 0, 0);
935                 ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_IP, (val & 0xFF00) >> 8, 24);
936                 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, val & 0xFF);
937                 break;
938         }               
939         default:
940                 g_assert_not_reached ();
941         }
942 #else
943         g_assert_not_reached ();
944 #endif
945 }
946
947 static ElfReloc*
948 resolve_relocations (MonoImageWriter *acfg)
949 {
950         BinReloc *reloc;
951         guint8 *data;
952         gsize end_val, start_val;
953         ElfReloc *rr;
954         int i;
955         gsize vaddr;
956
957         rr = g_new0 (ElfReloc, acfg->num_relocs);
958         i = 0;
959
960         for (reloc = acfg->relocations; reloc; reloc = reloc->next) {
961                 resolve_reloc (acfg, reloc, &data, &vaddr, &start_val, &end_val);
962                 /* FIXME: little endian */
963                 if (reloc->reloc_type) {
964                         /* Must be static */
965                         g_assert (start_val > 0);
966                         do_reloc (acfg, reloc, data, end_val);
967                 } else {
968                         data [0] = end_val;
969                         data [1] = end_val >> 8;
970                         data [2] = end_val >> 16;
971                         data [3] = end_val >> 24;
972                 }
973                 // FIXME:
974                 if (start_val == 0 && reloc->val1 [0] != '.') {
975                         rr [i].r_offset = vaddr;
976                         rr [i].r_info = R_386_RELATIVE;
977                         ++i;
978                         g_assert (i <= acfg->num_relocs);
979                 }
980         }
981         return rr;
982 }
983
984 #endif /* USE_ELF_RELA */
985
986 static int
987 bin_writer_emit_writeout (MonoImageWriter *acfg)
988 {
989         FILE *file;
990         ElfHeader header;
991         ElfProgHeader progh [3];
992         ElfSectHeader secth [SECT_NUM];
993 #ifdef USE_ELF_RELA
994         ElfRelocA *relocs;
995 #else
996         ElfReloc *relocs;
997 #endif
998         ElfStrTable str_table = {NULL, NULL};
999         ElfStrTable sh_str_table = {NULL, NULL};
1000         ElfStrTable dyn_str_table = {NULL, NULL};
1001         BinSection* all_sections [32];
1002         BinSection* sections [SECT_NUM];
1003         ElfSymbol *dynsym;
1004         ElfSymbol *symtab;
1005         ElfDynamic dynamic [14];
1006         int *hash;
1007         int i, num_sections, file_offset, virt_offset, size, num_symtab;
1008         int num_local_syms;
1009
1010         file = acfg->fp;
1011
1012         /* Section headers */
1013         memset (&secth, 0, sizeof (secth));
1014         memset (&dynamic, 0, sizeof (dynamic));
1015         memset (&header, 0, sizeof (header));
1016
1017         for (i = 1; i < SECT_NUM; ++i) {
1018                 secth [i].sh_name = str_table_add (&sh_str_table, section_info [i].name);
1019                 secth [i].sh_type = section_info [i].type;
1020                 secth [i].sh_addralign = section_info [i].align;
1021                 secth [i].sh_flags = section_info [i].flags;
1022                 secth [i].sh_entsize = section_info [i].esize;
1023         }
1024         secth [SECT_DYNSYM].sh_info = SIZEOF_VOID_P == 4 ? 4 : 2;
1025         secth [SECT_SYMTAB].sh_info = SIZEOF_VOID_P == 4 ? 20 : 17;
1026         secth [SECT_HASH].sh_link = SECT_DYNSYM;
1027         secth [SECT_DYNSYM].sh_link = SECT_DYNSTR;
1028         secth [SECT_REL_DYN].sh_link = SECT_DYNSYM;
1029         secth [SECT_RELA_DYN].sh_link = SECT_DYNSYM;
1030         secth [SECT_DYNAMIC].sh_link = SECT_DYNSTR;
1031         secth [SECT_SYMTAB].sh_link = SECT_STRTAB;
1032
1033         num_sections = collect_sections (acfg, secth, all_sections, 16);
1034         hash = build_hash (acfg, num_sections, &dyn_str_table);
1035         num_symtab = hash [1]; /* FIXME */
1036 #if 0
1037         g_print ("num_sections: %d\n", num_sections);
1038         g_print ("dynsym: %d, dynstr size: %d\n", hash [1], (int)dyn_str_table.data->len);
1039         for (i = 0; i < num_sections; ++i) {
1040                 g_print ("section %s, size: %d, %x\n", all_sections [i]->name, all_sections [i]->cur_offset, all_sections [i]->cur_offset);
1041         }
1042 #endif
1043         /* Associate the bin sections with the ELF sections */
1044         memset (sections, 0, sizeof (sections));
1045         for (i = 0; i < num_sections; ++i) {
1046                 BinSection *sect = all_sections [i];
1047                 int j;
1048
1049                 for (j = 0; j < SECT_NUM; ++j) {
1050                         if (strcmp (sect->name, section_info [j].name) == 0) {
1051                                 sect->shidx = j;
1052                                 break;
1053                         }
1054                 }
1055
1056                 sections [all_sections [i]->shidx] = sect;
1057         }
1058
1059         /* at this point we know where in the file the first segment sections go */
1060         dynsym = collect_syms (acfg, hash, &dyn_str_table, NULL, NULL);
1061         num_local_syms = hash [1];
1062         symtab = collect_syms (acfg, NULL, &str_table, secth, &num_local_syms);
1063
1064         file_offset = virt_offset = sizeof (header) + sizeof (progh);
1065         secth [SECT_HASH].sh_addr = secth [SECT_HASH].sh_offset = file_offset;
1066         size = sizeof (int) * (2 + hash [0] + hash [1]);
1067         virt_offset = (file_offset += size);
1068         secth [SECT_HASH].sh_size = size;
1069         secth [SECT_DYNSYM].sh_addr = secth [SECT_DYNSYM].sh_offset = file_offset;
1070         size = sizeof (ElfSymbol) * hash [1];
1071         virt_offset = (file_offset += size);
1072         secth [SECT_DYNSYM].sh_size = size;
1073         secth [SECT_DYNSTR].sh_addr = secth [SECT_DYNSTR].sh_offset = file_offset;
1074         size = dyn_str_table.data->len;
1075         virt_offset = (file_offset += size);
1076         secth [SECT_DYNSTR].sh_size = size;
1077         file_offset += 4-1;
1078         file_offset &= ~(4-1);
1079         secth [SECT_REL_DYN].sh_addr = secth [SECT_REL_DYN].sh_offset = file_offset;
1080 #ifndef USE_ELF_RELA
1081         size = sizeof (ElfReloc) * acfg->num_relocs;
1082 #else
1083         size = 0;
1084 #endif
1085         virt_offset = (file_offset += size);
1086         secth [SECT_REL_DYN].sh_size = size;
1087         secth [SECT_RELA_DYN].sh_addr = secth [SECT_RELA_DYN].sh_offset = file_offset;
1088 #ifdef USE_ELF_RELA
1089         size = sizeof (ElfRelocA) * acfg->num_relocs;
1090 #else
1091         size = 0;
1092 #endif
1093         virt_offset = (file_offset += size);
1094         secth [SECT_RELA_DYN].sh_size = size;
1095
1096         file_offset = ALIGN_TO (file_offset, secth [SECT_TEXT].sh_addralign);
1097         virt_offset = file_offset;
1098         secth [SECT_TEXT].sh_addr = secth [SECT_TEXT].sh_offset = file_offset;
1099         if (sections [SECT_TEXT]) {
1100                 size = sections [SECT_TEXT]->cur_offset;
1101                 secth [SECT_TEXT].sh_size = size;
1102                 file_offset += size;
1103         }
1104
1105         file_offset = ALIGN_TO (file_offset, secth [SECT_DYNAMIC].sh_addralign);
1106         virt_offset = file_offset;
1107
1108         /* .dynamic, .got.plt, .data, .bss here */
1109         /* Have to increase the virt offset since these go to a separate segment */
1110         virt_offset += PAGESIZE;
1111         secth [SECT_DYNAMIC].sh_addr = virt_offset;
1112         secth [SECT_DYNAMIC].sh_offset = file_offset;
1113         size = sizeof (dynamic);
1114         secth [SECT_DYNAMIC].sh_size = size;
1115         file_offset += size;
1116         virt_offset += size;
1117
1118         file_offset = ALIGN_TO (file_offset, secth [SECT_GOT_PLT].sh_addralign);
1119         virt_offset = ALIGN_TO (virt_offset, secth [SECT_GOT_PLT].sh_addralign);
1120         secth [SECT_GOT_PLT].sh_addr = virt_offset;
1121         secth [SECT_GOT_PLT].sh_offset = file_offset;
1122         size = 12;
1123         secth [SECT_GOT_PLT].sh_size = size;
1124         file_offset += size;
1125         virt_offset += size;
1126
1127         file_offset = ALIGN_TO (file_offset, secth [SECT_DATA].sh_addralign);
1128         virt_offset = ALIGN_TO (virt_offset, secth [SECT_DATA].sh_addralign);
1129         secth [SECT_DATA].sh_addr = virt_offset;
1130         secth [SECT_DATA].sh_offset = file_offset;
1131         if (sections [SECT_DATA]) {
1132                 size = sections [SECT_DATA]->cur_offset;
1133                 secth [SECT_DATA].sh_size = size;
1134                 file_offset += size;
1135                 virt_offset += size;
1136         }
1137
1138         file_offset = ALIGN_TO (file_offset, secth [SECT_BSS].sh_addralign);
1139         virt_offset = ALIGN_TO (virt_offset, secth [SECT_BSS].sh_addralign);
1140         secth [SECT_BSS].sh_addr = virt_offset;
1141         secth [SECT_BSS].sh_offset = file_offset;
1142         if (sections [SECT_BSS]) {
1143                 size = sections [SECT_BSS]->cur_offset;
1144                 secth [SECT_BSS].sh_size = size;
1145         }
1146
1147         /* virtual doesn't matter anymore */
1148         file_offset = ALIGN_TO (file_offset, secth [SECT_DEBUG_FRAME].sh_addralign);
1149         secth [SECT_DEBUG_FRAME].sh_offset = file_offset;
1150         if (sections [SECT_DEBUG_FRAME])
1151                 size = sections [SECT_DEBUG_FRAME]->cur_offset;
1152         else
1153                 size = 0;
1154         secth [SECT_DEBUG_FRAME].sh_size = size;
1155         file_offset += size;
1156
1157         secth [SECT_DEBUG_INFO].sh_offset = file_offset;
1158         if (sections [SECT_DEBUG_INFO])
1159                 size = sections [SECT_DEBUG_INFO]->cur_offset;
1160         else
1161                 size = 0;
1162         secth [SECT_DEBUG_INFO].sh_size = size;
1163         file_offset += size;
1164
1165         secth [SECT_DEBUG_ABBREV].sh_offset = file_offset;
1166         if (sections [SECT_DEBUG_ABBREV])
1167                 size = sections [SECT_DEBUG_ABBREV]->cur_offset;
1168         else
1169                 size = 0;
1170         secth [SECT_DEBUG_ABBREV].sh_size = size;
1171         file_offset += size;
1172
1173         secth [SECT_DEBUG_LINE].sh_offset = file_offset;
1174         if (sections [SECT_DEBUG_LINE])
1175                 size = sections [SECT_DEBUG_LINE]->cur_offset;
1176         else
1177                 size = 0;
1178         secth [SECT_DEBUG_LINE].sh_size = size;
1179         file_offset += size;
1180
1181         secth [SECT_DEBUG_LOC].sh_offset = file_offset;
1182         if (sections [SECT_DEBUG_LOC])
1183                 size = sections [SECT_DEBUG_LOC]->cur_offset;
1184         else
1185                 size = 0;
1186         secth [SECT_DEBUG_LOC].sh_size = size;
1187         file_offset += size;
1188
1189         file_offset = ALIGN_TO (file_offset, secth [SECT_SHSTRTAB].sh_addralign);
1190         secth [SECT_SHSTRTAB].sh_offset = file_offset;
1191         size = sh_str_table.data->len;
1192         secth [SECT_SHSTRTAB].sh_size = size;
1193         file_offset += size;
1194
1195         file_offset = ALIGN_TO (file_offset, secth [SECT_SYMTAB].sh_addralign);
1196         secth [SECT_SYMTAB].sh_offset = file_offset;
1197         size = sizeof (ElfSymbol) * num_local_syms;
1198         secth [SECT_SYMTAB].sh_size = size;
1199         file_offset += size;
1200
1201         file_offset = ALIGN_TO (file_offset, secth [SECT_STRTAB].sh_addralign);
1202         secth [SECT_STRTAB].sh_offset = file_offset;
1203         size = str_table.data->len;
1204         secth [SECT_STRTAB].sh_size = size;
1205         file_offset += size;
1206
1207         file_offset += 4-1;
1208         file_offset &= ~(4-1);
1209
1210         header.e_ident [EI_MAG0] = ELFMAG0;
1211         header.e_ident [EI_MAG1] = ELFMAG1;
1212         header.e_ident [EI_MAG2] = ELFMAG2;
1213         header.e_ident [EI_MAG3] = ELFMAG3;
1214         header.e_ident [EI_CLASS] = SIZEOF_VOID_P == 4 ? ELFCLASS32 : ELFCLASS64;
1215         header.e_ident [EI_DATA] = ELFDATA2LSB;
1216         header.e_ident [EI_VERSION] = EV_CURRENT;
1217         header.e_ident [EI_OSABI] = ELFOSABI_NONE;
1218         header.e_ident [EI_ABIVERSION] = 0;
1219         for (i = EI_PAD; i < EI_NIDENT; ++i)
1220                 header.e_ident [i] = 0;
1221
1222         header.e_type = ET_DYN;
1223 #if defined(TARGET_X86)
1224         header.e_machine = EM_386;
1225 #elif defined(TARGET_AMD64)
1226         header.e_machine = EM_X86_64;
1227 #elif defined(TARGET_ARM)
1228         header.e_machine = EM_ARM;
1229 #else
1230         g_assert_not_reached ();
1231 #endif
1232         header.e_version = 1;
1233
1234         header.e_phoff = sizeof (header);
1235         header.e_ehsize = sizeof (header);
1236         header.e_phentsize = sizeof (ElfProgHeader);
1237         header.e_phnum = 3;
1238         header.e_entry = secth [SECT_TEXT].sh_addr;
1239         header.e_shstrndx = SECT_SHSTRTAB;
1240         header.e_shentsize = sizeof (ElfSectHeader);
1241         header.e_shnum = SECT_NUM;
1242         header.e_shoff = file_offset;
1243
1244         /* dynamic data */
1245         i = 0;
1246         dynamic [i].d_tag = DT_HASH;
1247         dynamic [i].d_un.d_val = secth [SECT_HASH].sh_offset;
1248         ++i;
1249         dynamic [i].d_tag = DT_STRTAB;
1250         dynamic [i].d_un.d_val = secth [SECT_DYNSTR].sh_offset;
1251         ++i;
1252         dynamic [i].d_tag = DT_SYMTAB;
1253         dynamic [i].d_un.d_val = secth [SECT_DYNSYM].sh_offset;
1254         ++i;
1255         dynamic [i].d_tag = DT_STRSZ;
1256         dynamic [i].d_un.d_val = dyn_str_table.data->len;
1257         ++i;
1258         dynamic [i].d_tag = DT_SYMENT;
1259         dynamic [i].d_un.d_val = sizeof (ElfSymbol);
1260         ++i;
1261 #ifdef USE_ELF_RELA
1262         dynamic [i].d_tag = DT_RELA;
1263         dynamic [i].d_un.d_val = secth [SECT_RELA_DYN].sh_offset;
1264         ++i;
1265         dynamic [i].d_tag = DT_RELASZ;
1266         dynamic [i].d_un.d_val = secth [SECT_RELA_DYN].sh_size;
1267         ++i;
1268         dynamic [i].d_tag = DT_RELAENT;
1269         dynamic [i].d_un.d_val = sizeof (ElfRelocA);
1270         ++i;
1271 #else
1272         dynamic [i].d_tag = DT_REL;
1273         dynamic [i].d_un.d_val = secth [SECT_REL_DYN].sh_offset;
1274         ++i;
1275         dynamic [i].d_tag = DT_RELSZ;
1276         dynamic [i].d_un.d_val = secth [SECT_REL_DYN].sh_size;
1277         ++i;
1278         dynamic [i].d_tag = DT_RELENT;
1279         dynamic [i].d_un.d_val = sizeof (ElfReloc);
1280         ++i;
1281 #endif
1282         dynamic [i].d_tag = DT_RELCOUNT;
1283         dynamic [i].d_un.d_val = acfg->num_relocs;
1284         ++i;
1285
1286         /* Program header */
1287         memset (&progh, 0, sizeof (progh));
1288         progh [0].p_type = PT_LOAD;
1289         progh [0].p_filesz = progh [0].p_memsz = secth [SECT_DYNAMIC].sh_offset;
1290         progh [0].p_align = 4096;
1291         progh [0].p_flags = 5;
1292
1293         progh [1].p_type = PT_LOAD;
1294         progh [1].p_offset = secth [SECT_DYNAMIC].sh_offset;
1295         progh [1].p_vaddr = progh [1].p_paddr = secth [SECT_DYNAMIC].sh_addr;
1296         progh [1].p_filesz = secth [SECT_BSS].sh_offset  - secth [SECT_DYNAMIC].sh_offset;
1297         progh [1].p_memsz = secth [SECT_BSS].sh_addr + secth [SECT_BSS].sh_size - secth [SECT_DYNAMIC].sh_addr;
1298         progh [1].p_align = 4096;
1299         progh [1].p_flags = 6;
1300
1301         progh [2].p_type = PT_DYNAMIC;
1302         progh [2].p_offset = secth [SECT_DYNAMIC].sh_offset;
1303         progh [2].p_vaddr = progh [2].p_paddr = secth [SECT_DYNAMIC].sh_addr;
1304         progh [2].p_filesz = progh [2].p_memsz = secth [SECT_DYNAMIC].sh_size;
1305         progh [2].p_align = SIZEOF_VOID_P;
1306         progh [2].p_flags = 6;
1307
1308         /* Compute the addresses of the bin sections, so relocation can be done */
1309         for (i = 0; i < SECT_NUM; ++i) {
1310                 if (sections [i]) {
1311                         sections [i]->file_offset = secth [i].sh_offset;
1312                         sections [i]->virt_offset = secth [i].sh_addr;
1313                 }
1314         }
1315
1316         reloc_symbols (acfg, dynsym, secth, &dyn_str_table, TRUE);
1317         reloc_symbols (acfg, symtab, secth, &str_table, FALSE);
1318         relocs = resolve_relocations (acfg);
1319
1320         fwrite (&header, sizeof (header), 1, file);
1321         fwrite (&progh, sizeof (progh), 1, file);
1322         fwrite (hash, sizeof (int) * (hash [0] + hash [1] + 2), 1, file);
1323         fwrite (dynsym, sizeof (ElfSymbol) * hash [1], 1, file);
1324         fwrite (dyn_str_table.data->str, dyn_str_table.data->len, 1, file);
1325         /* .rel.dyn */
1326         fseek (file, secth [SECT_REL_DYN].sh_offset, SEEK_SET);
1327         fwrite (relocs, sizeof (ElfReloc), acfg->num_relocs, file);
1328
1329         /* .rela.dyn */
1330         fseek (file, secth [SECT_RELA_DYN].sh_offset, SEEK_SET);
1331         fwrite (relocs, secth [SECT_RELA_DYN].sh_size, 1, file);
1332
1333         /* .text */
1334         if (sections [SECT_TEXT]) {
1335                 fseek (file, secth [SECT_TEXT].sh_offset, SEEK_SET);
1336                 fwrite (sections [SECT_TEXT]->data, sections [SECT_TEXT]->cur_offset, 1, file);
1337         }
1338         /* .dynamic */
1339         fwrite (dynamic, sizeof (dynamic), 1, file);
1340
1341         /* .got.plt */
1342         size = secth [SECT_DYNAMIC].sh_addr;
1343         fwrite (&size, sizeof (size), 1, file);
1344
1345         /* .data */
1346         if (sections [SECT_DATA]) {
1347                 fseek (file, secth [SECT_DATA].sh_offset, SEEK_SET);
1348                 fwrite (sections [SECT_DATA]->data, sections [SECT_DATA]->cur_offset, 1, file);
1349         }
1350
1351         fseek (file, secth [SECT_DEBUG_FRAME].sh_offset, SEEK_SET);
1352         if (sections [SECT_DEBUG_FRAME])
1353                 fwrite (sections [SECT_DEBUG_FRAME]->data, sections [SECT_DEBUG_FRAME]->cur_offset, 1, file);
1354         fseek (file, secth [SECT_DEBUG_INFO].sh_offset, SEEK_SET);
1355         if (sections [SECT_DEBUG_INFO])
1356                 fwrite (sections [SECT_DEBUG_INFO]->data, sections [SECT_DEBUG_INFO]->cur_offset, 1, file);
1357         fseek (file, secth [SECT_DEBUG_ABBREV].sh_offset, SEEK_SET);
1358         if (sections [SECT_DEBUG_ABBREV])
1359                 fwrite (sections [SECT_DEBUG_ABBREV]->data, sections [SECT_DEBUG_ABBREV]->cur_offset, 1, file);
1360         fseek (file, secth [SECT_DEBUG_LINE].sh_offset, SEEK_SET);
1361         if (sections [SECT_DEBUG_LINE])
1362                 fwrite (sections [SECT_DEBUG_LINE]->data, sections [SECT_DEBUG_LINE]->cur_offset, 1, file);
1363         fseek (file, secth [SECT_DEBUG_LINE].sh_offset, SEEK_SET);
1364         if (sections [SECT_DEBUG_LOC])
1365                 fwrite (sections [SECT_DEBUG_LOC]->data, sections [SECT_DEBUG_LOC]->cur_offset, 1, file);
1366         fseek (file, secth [SECT_SHSTRTAB].sh_offset, SEEK_SET);
1367         fwrite (sh_str_table.data->str, sh_str_table.data->len, 1, file);
1368         fseek (file, secth [SECT_SYMTAB].sh_offset, SEEK_SET);
1369         fwrite (symtab, sizeof (ElfSymbol) * num_local_syms, 1, file);
1370         fseek (file, secth [SECT_STRTAB].sh_offset, SEEK_SET);
1371         fwrite (str_table.data->str, str_table.data->len, 1, file);
1372         /*g_print ("file_offset %d vs %d\n", file_offset, ftell (file));*/
1373         /*g_assert (file_offset >= ftell (file));*/
1374         fseek (file, file_offset, SEEK_SET);
1375         fwrite (&secth, sizeof (secth), 1, file);
1376         fclose (file);
1377
1378         return 0;
1379 }
1380
1381 #endif /* USE_ELF_WRITER */
1382
1383 #endif /* USE_BIN_WRITER */
1384
1385 /* ASM WRITER */
1386
1387 static void
1388 asm_writer_emit_start (MonoImageWriter *acfg)
1389 {
1390 }
1391
1392 static int
1393 asm_writer_emit_writeout (MonoImageWriter *acfg)
1394 {
1395         fclose (acfg->fp);
1396
1397         return 0;
1398 }
1399
1400 static void
1401 asm_writer_emit_unset_mode (MonoImageWriter *acfg)
1402 {
1403         if (acfg->mode == EMIT_NONE)
1404                 return;
1405         fprintf (acfg->fp, "\n");
1406         acfg->mode = EMIT_NONE;
1407 }
1408
1409 static void
1410 asm_writer_emit_section_change (MonoImageWriter *acfg, const char *section_name, int subsection_index)
1411 {
1412         asm_writer_emit_unset_mode (acfg);
1413 #if defined(PLATFORM_WIN32)
1414         fprintf (acfg->fp, ".section %s\n", section_name);
1415 #elif defined(TARGET_ASM_APPLE)
1416         if (strcmp(section_name, ".bss") == 0)
1417                 fprintf (acfg->fp, "%s\n", ".data");
1418         else
1419                 fprintf (acfg->fp, "%s\n", section_name);
1420 #elif defined(TARGET_ARM)
1421         /* ARM gas doesn't seem to like subsections of .bss */
1422         if (!strcmp (section_name, ".text") || !strcmp (section_name, ".data")) {
1423                 fprintf (acfg->fp, "%s %d\n", section_name, subsection_index);
1424         } else {
1425                 fprintf (acfg->fp, ".section \"%s\"\n", section_name);
1426                 fprintf (acfg->fp, ".subsection %d\n", subsection_index);
1427         }
1428 #else
1429         if (!strcmp (section_name, ".text") || !strcmp (section_name, ".data") || !strcmp (section_name, ".bss")) {
1430                 fprintf (acfg->fp, "%s %d\n", section_name, subsection_index);
1431         } else {
1432                 fprintf (acfg->fp, ".section \"%s\"\n", section_name);
1433                 fprintf (acfg->fp, ".subsection %d\n", subsection_index);
1434         }
1435 #endif
1436 }
1437
1438 static void
1439 asm_writer_emit_symbol_type (MonoImageWriter *acfg, const char *name, gboolean func)
1440 {
1441         const char *stype;
1442
1443         if (func)
1444                 stype = "function";
1445         else
1446                 stype = "object";
1447
1448         asm_writer_emit_unset_mode (acfg);
1449 #if defined(TARGET_ASM_APPLE)
1450
1451 #elif defined(TARGET_ARM)
1452         fprintf (acfg->fp, "\t.type %s,#%s\n", name, stype);
1453 #elif defined(PLATFORM_WIN32)
1454
1455 #else
1456         fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
1457 #endif
1458 }
1459
1460 static void
1461 asm_writer_emit_global (MonoImageWriter *acfg, const char *name, gboolean func)
1462 {
1463         asm_writer_emit_unset_mode (acfg);
1464 #if  (defined(__ppc__) && defined(TARGET_ASM_APPLE)) || defined(PLATFORM_WIN32)
1465     // mach-o always uses a '_' prefix.
1466         fprintf (acfg->fp, "\t.globl _%s\n", name);
1467 #else
1468         fprintf (acfg->fp, "\t.globl %s\n", name);
1469 #endif
1470
1471         asm_writer_emit_symbol_type (acfg, name, func);
1472 }
1473
1474 static void
1475 asm_writer_emit_local_symbol (MonoImageWriter *acfg, const char *name, const char *end_label, gboolean func)
1476 {
1477         asm_writer_emit_unset_mode (acfg);
1478
1479 #ifndef TARGET_ASM_APPLE
1480         fprintf (acfg->fp, "\t.local %s\n", name);
1481 #endif
1482
1483         asm_writer_emit_symbol_type (acfg, name, func);
1484 }
1485
1486 static void
1487 asm_writer_emit_label (MonoImageWriter *acfg, const char *name)
1488 {
1489         asm_writer_emit_unset_mode (acfg);
1490 #if (defined(__ppc__) && defined(TARGET_ASM_APPLE)) || defined(PLATFORM_WIN32)
1491     // mach-o always uses a '_' prefix.
1492         fprintf (acfg->fp, "_%s:\n", name);
1493 #else
1494         fprintf (acfg->fp, "%s:\n", name);
1495 #endif
1496
1497 #if defined(PLATFORM_WIN32)
1498         /* Emit a normal label too */
1499         fprintf (acfg->fp, "%s:\n", name);
1500 #endif
1501 }
1502
1503 static void
1504 asm_writer_emit_string (MonoImageWriter *acfg, const char *value)
1505 {
1506         asm_writer_emit_unset_mode (acfg);
1507         fprintf (acfg->fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1508 }
1509
1510 static void
1511 asm_writer_emit_line (MonoImageWriter *acfg)
1512 {
1513         asm_writer_emit_unset_mode (acfg);
1514         fprintf (acfg->fp, "\n");
1515 }
1516
1517 static void 
1518 asm_writer_emit_alignment (MonoImageWriter *acfg, int size)
1519 {
1520         asm_writer_emit_unset_mode (acfg);
1521 #if defined(TARGET_ARM)
1522         fprintf (acfg->fp, "\t.align %d\n", ilog2 (size));
1523 #elif defined(__ppc__) && defined(TARGET_ASM_APPLE)
1524         // the mach-o assembler specifies alignments as powers of 2.
1525         fprintf (acfg->fp, "\t.align %d\t; ilog2\n", ilog2(size));
1526 #elif defined(TARGET_ASM_GAS)
1527         fprintf (acfg->fp, "\t.balign %d\n", size);
1528 #else
1529         fprintf (acfg->fp, "\t.align %d\n", size);
1530 #endif
1531 }
1532
1533 static void
1534 asm_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target)
1535 {
1536         asm_writer_emit_unset_mode (acfg);
1537         fprintf (acfg->fp, "\t%s %s\n", AS_INT64_DIRECTIVE, target ? target : "0");
1538 }
1539
1540 static void
1541 asm_writer_emit_pointer (MonoImageWriter *acfg, const char *target)
1542 {
1543         asm_writer_emit_unset_mode (acfg);
1544         asm_writer_emit_alignment (acfg, sizeof (gpointer));
1545         asm_writer_emit_pointer_unaligned (acfg, target);
1546 }
1547
1548 static char *byte_to_str;
1549
1550 static void
1551 asm_writer_emit_bytes (MonoImageWriter *acfg, const guint8* buf, int size)
1552 {
1553         int i;
1554         if (acfg->mode != EMIT_BYTE) {
1555                 acfg->mode = EMIT_BYTE;
1556                 acfg->col_count = 0;
1557         }
1558
1559         if (byte_to_str == NULL) {
1560                 byte_to_str = g_new0 (char, 256 * 8);
1561                 for (i = 0; i < 256; ++i) {
1562                         sprintf (byte_to_str + (i * 8), ",%d", i);
1563                 }
1564         }
1565
1566         for (i = 0; i < size; ++i, ++acfg->col_count) {
1567                 if ((acfg->col_count % 32) == 0)
1568                         fprintf (acfg->fp, "\n\t.byte %d", buf [i]);
1569                 else
1570                         fputs (byte_to_str + (buf [i] * 8), acfg->fp);
1571         }
1572 }
1573
1574 static inline void
1575 asm_writer_emit_int16 (MonoImageWriter *acfg, int value)
1576 {
1577         if (acfg->mode != EMIT_WORD) {
1578                 acfg->mode = EMIT_WORD;
1579                 acfg->col_count = 0;
1580         }
1581         if ((acfg->col_count++ % 8) == 0)
1582                 fprintf (acfg->fp, "\n\t%s ", AS_INT16_DIRECTIVE);
1583         fprintf (acfg->fp, "%d", value);
1584 }
1585
1586 static inline void
1587 asm_writer_emit_int32 (MonoImageWriter *acfg, int value)
1588 {
1589         if (acfg->mode != EMIT_LONG) {
1590                 acfg->mode = EMIT_LONG;
1591                 acfg->col_count = 0;
1592         }
1593         if ((acfg->col_count++ % 8) == 0)
1594                 fprintf (acfg->fp, "\n\t%s ", AS_INT32_DIRECTIVE);
1595         else
1596                 fprintf (acfg->fp, ",");
1597         fprintf (acfg->fp, "%d", value);
1598 }
1599
1600 static void
1601 asm_writer_emit_symbol_diff (MonoImageWriter *acfg, const char *end, const char* start, int offset)
1602 {
1603         if (acfg->mode != EMIT_LONG) {
1604                 acfg->mode = EMIT_LONG;
1605                 acfg->col_count = 0;
1606         }
1607         if ((acfg->col_count++ % 8) == 0)
1608                 fprintf (acfg->fp, "\n\t%s ", AS_INT32_DIRECTIVE);
1609         else
1610                 fprintf (acfg->fp, ",");
1611         if (offset > 0)
1612                 fprintf (acfg->fp, "%s - %s + %d", end, start, offset);
1613         else if (offset < 0)
1614                 fprintf (acfg->fp, "%s - %s %d", end, start, offset);
1615         else
1616                 fprintf (acfg->fp, "%s - %s", end, start);
1617 }
1618
1619 static void
1620 asm_writer_emit_zero_bytes (MonoImageWriter *acfg, int num)
1621 {
1622         asm_writer_emit_unset_mode (acfg);
1623         fprintf (acfg->fp, "\t%s %d\n", AS_SKIP_DIRECTIVE, num);
1624 }
1625
1626 /* EMIT FUNCTIONS */
1627
1628 void
1629 img_writer_emit_start (MonoImageWriter *acfg)
1630 {
1631 #ifdef USE_BIN_WRITER
1632         if (acfg->use_bin_writer)
1633                 bin_writer_emit_start (acfg);
1634         else
1635                 asm_writer_emit_start (acfg);
1636 #else
1637         asm_writer_emit_start (acfg);
1638 #endif
1639 }
1640
1641 void
1642 img_writer_emit_section_change (MonoImageWriter *acfg, const char *section_name, int subsection_index)
1643 {
1644 #ifdef USE_BIN_WRITER
1645         if (acfg->use_bin_writer)
1646                 bin_writer_emit_section_change (acfg, section_name, subsection_index);
1647         else
1648                 asm_writer_emit_section_change (acfg, section_name, subsection_index);
1649 #else
1650         asm_writer_emit_section_change (acfg, section_name, subsection_index);
1651 #endif
1652
1653         acfg->current_section = section_name;
1654         acfg->current_subsection = subsection_index;
1655 }
1656
1657 void
1658 img_writer_emit_push_section (MonoImageWriter *acfg, const char *section_name, int subsection)
1659 {
1660         g_assert (acfg->stack_pos < 16 - 1);
1661         acfg->section_stack [acfg->stack_pos] = acfg->current_section;
1662         acfg->subsection_stack [acfg->stack_pos] = acfg->current_subsection;
1663         acfg->stack_pos ++;
1664
1665         img_writer_emit_section_change (acfg, section_name, subsection);
1666 }
1667
1668 void
1669 img_writer_emit_pop_section (MonoImageWriter *acfg)
1670 {
1671         g_assert (acfg->stack_pos > 0);
1672         acfg->stack_pos --;
1673         img_writer_emit_section_change (acfg, acfg->section_stack [acfg->stack_pos], acfg->subsection_stack [acfg->stack_pos]);
1674 }
1675
1676 void
1677 img_writer_emit_global (MonoImageWriter *acfg, const char *name, gboolean func)
1678 {
1679 #ifdef USE_BIN_WRITER
1680         if (acfg->use_bin_writer)
1681                 bin_writer_emit_global (acfg, name, func);
1682         else
1683                 asm_writer_emit_global (acfg, name, func);
1684 #else
1685         asm_writer_emit_global (acfg, name, func);
1686 #endif
1687 }
1688
1689 void
1690 img_writer_emit_local_symbol (MonoImageWriter *acfg, const char *name, const char *end_label, gboolean func)
1691 {
1692 #ifdef USE_BIN_WRITER
1693         if (acfg->use_bin_writer)
1694                 bin_writer_emit_local_symbol (acfg, name, end_label, func);
1695         else
1696                 asm_writer_emit_local_symbol (acfg, name, end_label, func);
1697 #else
1698         asm_writer_emit_local_symbol (acfg, name, end_label, func);
1699 #endif
1700 }
1701
1702 void
1703 img_writer_emit_label (MonoImageWriter *acfg, const char *name)
1704 {
1705 #ifdef USE_BIN_WRITER
1706         if (acfg->use_bin_writer)
1707                 bin_writer_emit_label (acfg, name);
1708         else
1709                 asm_writer_emit_label (acfg, name);
1710 #else
1711         asm_writer_emit_label (acfg, name);
1712 #endif
1713 }
1714
1715 void
1716 img_writer_emit_bytes (MonoImageWriter *acfg, const guint8* buf, int size)
1717 {
1718 #ifdef USE_BIN_WRITER
1719         if (acfg->use_bin_writer)
1720                 bin_writer_emit_bytes (acfg, buf, size);
1721         else
1722                 asm_writer_emit_bytes (acfg, buf, size);
1723 #else
1724         asm_writer_emit_bytes (acfg, buf, size);
1725 #endif
1726 }
1727
1728 void
1729 img_writer_emit_string (MonoImageWriter *acfg, const char *value)
1730 {
1731 #ifdef USE_BIN_WRITER
1732         if (acfg->use_bin_writer)
1733                 bin_writer_emit_string (acfg, value);
1734         else
1735                 asm_writer_emit_string (acfg, value);
1736 #else
1737         asm_writer_emit_string (acfg, value);
1738 #endif
1739 }
1740
1741 void
1742 img_writer_emit_line (MonoImageWriter *acfg)
1743 {
1744 #ifdef USE_BIN_WRITER
1745         if (acfg->use_bin_writer)
1746                 bin_writer_emit_line (acfg);
1747         else
1748                 asm_writer_emit_line (acfg);
1749 #else
1750                 asm_writer_emit_line (acfg);
1751 #endif
1752 }
1753
1754 void
1755 img_writer_emit_alignment (MonoImageWriter *acfg, int size)
1756 {
1757 #ifdef USE_BIN_WRITER
1758         if (acfg->use_bin_writer)
1759                 bin_writer_emit_alignment (acfg, size);
1760         else
1761                 asm_writer_emit_alignment (acfg, size);
1762 #else
1763         asm_writer_emit_alignment (acfg, size);
1764 #endif
1765 }
1766
1767 void
1768 img_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target)
1769 {
1770 #ifdef USE_BIN_WRITER
1771         if (acfg->use_bin_writer)
1772                 bin_writer_emit_pointer_unaligned (acfg, target);
1773         else
1774                 asm_writer_emit_pointer_unaligned (acfg, target);
1775 #else
1776         asm_writer_emit_pointer_unaligned (acfg, target);
1777 #endif
1778 }
1779
1780 void
1781 img_writer_emit_pointer (MonoImageWriter *acfg, const char *target)
1782 {
1783 #ifdef USE_BIN_WRITER
1784         if (acfg->use_bin_writer)
1785                 bin_writer_emit_pointer (acfg, target);
1786         else
1787                 asm_writer_emit_pointer (acfg, target);
1788 #else
1789         asm_writer_emit_pointer (acfg, target);
1790 #endif
1791 }
1792
1793 void
1794 img_writer_emit_int16 (MonoImageWriter *acfg, int value)
1795 {
1796 #ifdef USE_BIN_WRITER
1797         if (acfg->use_bin_writer)
1798                 bin_writer_emit_int16 (acfg, value);
1799         else
1800                 asm_writer_emit_int16 (acfg, value);
1801 #else
1802         asm_writer_emit_int16 (acfg, value);
1803 #endif
1804 }
1805
1806 void
1807 img_writer_emit_int32 (MonoImageWriter *acfg, int value)
1808 {
1809 #ifdef USE_BIN_WRITER
1810         if (acfg->use_bin_writer)
1811                 bin_writer_emit_int32 (acfg, value);
1812         else
1813                 asm_writer_emit_int32 (acfg, value);
1814 #else
1815         asm_writer_emit_int32 (acfg, value);
1816 #endif
1817 }
1818
1819 void
1820 img_writer_emit_symbol_diff (MonoImageWriter *acfg, const char *end, const char* start, int offset)
1821 {
1822 #ifdef USE_BIN_WRITER
1823         if (acfg->use_bin_writer)
1824                 bin_writer_emit_symbol_diff (acfg, end, start, offset);
1825         else
1826                 asm_writer_emit_symbol_diff (acfg, end, start, offset);
1827 #else
1828         asm_writer_emit_symbol_diff (acfg, end, start, offset);
1829 #endif
1830 }
1831
1832 void
1833 img_writer_emit_zero_bytes (MonoImageWriter *acfg, int num)
1834 {
1835 #ifdef USE_BIN_WRITER
1836         if (acfg->use_bin_writer)
1837                 bin_writer_emit_zero_bytes (acfg, num);
1838         else
1839                 asm_writer_emit_zero_bytes (acfg, num);
1840 #else
1841         asm_writer_emit_zero_bytes (acfg, num);
1842 #endif
1843 }
1844
1845 int
1846 img_writer_emit_writeout (MonoImageWriter *acfg)
1847 {
1848 #ifdef USE_BIN_WRITER
1849         if (acfg->use_bin_writer)
1850                 return bin_writer_emit_writeout (acfg);
1851         else
1852                 return asm_writer_emit_writeout (acfg);
1853 #else
1854                 return asm_writer_emit_writeout (acfg);
1855 #endif
1856 }
1857
1858 void
1859 img_writer_emit_byte (MonoImageWriter *acfg, guint8 val)
1860 {
1861         img_writer_emit_bytes (acfg, &val, 1);
1862 }
1863
1864 /* 
1865  * Emit a relocation entry of type RELOC_TYPE against symbol SYMBOL at the current PC.
1866  * Do not advance PC.
1867  */
1868 void
1869 img_writer_emit_reloc (MonoImageWriter *acfg, int reloc_type, const char *symbol, int addend)
1870 {
1871         /* This is only supported by the bin writer */
1872 #ifdef USE_BIN_WRITER
1873         if (acfg->use_bin_writer)
1874                 bin_writer_emit_reloc (acfg, reloc_type, symbol, addend);
1875         else
1876                 g_assert_not_reached ();
1877 #else
1878                 g_assert_not_reached ();
1879 #endif
1880 }
1881
1882 /*
1883  * img_writer_emit_unset_mode:
1884  *
1885  *   Flush buffered data so it is safe to write to the output file from outside this
1886  * module. This is a nop for the binary writer.
1887  */
1888 void
1889 img_writer_emit_unset_mode (MonoImageWriter *acfg)
1890 {
1891         if (!acfg->use_bin_writer)
1892                 asm_writer_emit_unset_mode (acfg);
1893 }
1894
1895 /*
1896  * Return whenever the binary writer is supported on this platform.
1897  */
1898 gboolean
1899 bin_writer_supported (void)
1900 {
1901 #ifdef USE_BIN_WRITER
1902         return TRUE;
1903 #else
1904         return FALSE;
1905 #endif
1906 }
1907
1908 MonoImageWriter*
1909 img_writer_create (FILE *fp, gboolean use_bin_writer)
1910 {
1911         MonoImageWriter *w = g_new0 (MonoImageWriter, 1);
1912         
1913 #ifndef USE_BIN_WRITER
1914         g_assert (!use_bin_writer);
1915 #endif
1916
1917         w->fp = fp;
1918         w->use_bin_writer = use_bin_writer;
1919         w->mempool = mono_mempool_new ();
1920
1921         return w;
1922 }
1923
1924 void
1925 img_writer_destroy (MonoImageWriter *w)
1926 {
1927         // FIXME: Free all the stuff
1928         mono_mempool_destroy (w->mempool);
1929         g_free (w);
1930 }