Mon Feb 1 14:29:43 CET 2010 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / image-writer.c
index 383fe33355fa245a21b7a448d0ca44c5c0b1815a..eb537d4ade7582e063fdc5fa83ec8b2e81053c7f 100644 (file)
@@ -20,7 +20,7 @@
 #include <fcntl.h>
 #include <ctype.h>
 #include <string.h>
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
 #include <sys/time.h>
 #else
 #include <winsock2.h>
@@ -36,7 +36,7 @@
 
 #include "image-writer.h"
 
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
 #include <mono/utils/freebsd-elf32.h>
 #include <mono/utils/freebsd-elf64.h>
 #endif
 #define TV_GETTIME(tv) tv = mono_100ns_ticks ()
 #define TV_ELAPSED(start,end) (((end) - (start)) / 10)
 
-#ifdef PLATFORM_WIN32
-#define SHARED_EXT ".dll"
-#elif defined(__ppc__) && defined(__MACH__)
-#define SHARED_EXT ".dylib"
+/* 
+ * The used assembler dialect
+ * TARGET_ASM_APPLE == apple assembler on OSX
+ * TARGET_ASM_GAS == GNU assembler
+ */
+#if !defined(TARGET_ASM_APPLE) && !defined(TARGET_ASM_GAS)
+#ifdef __MACH__
+#define TARGET_ASM_APPLE
 #else
-#define SHARED_EXT ".so"
+#define TARGET_ASM_GAS
+#endif
 #endif
 
-#if defined(sparc) || defined(__ppc__) || defined(__powerpc__) || defined(__MACH__)
+/*
+ * Defines for the directives used by different assemblers
+ */
+#if defined(TARGET_POWERPC) || defined(__MACH__)
 #define AS_STRING_DIRECTIVE ".asciz"
 #else
-/* GNU as */
 #define AS_STRING_DIRECTIVE ".string"
 #endif
 
+#define AS_INT32_DIRECTIVE ".long"
+#define AS_INT64_DIRECTIVE ".quad"
+
+#if (defined(TARGET_AMD64) || defined(TARGET_POWERPC64)) && !defined(__mono_ilp32__)
+#define AS_POINTER_DIRECTIVE ".quad"
+#else
+#define AS_POINTER_DIRECTIVE ".long"
+#endif
+
+#if defined(TARGET_ASM_APPLE)
+#define AS_INT16_DIRECTIVE ".short"
+#elif defined(TARGET_ASM_GAS)
+#define AS_INT16_DIRECTIVE ".hword"
+#else
+#define AS_INT16_DIRECTIVE ".word"
+#endif
+
+#if defined(TARGET_ASM_APPLE)
+#define AS_SKIP_DIRECTIVE ".space"
+#else
+#define AS_SKIP_DIRECTIVE ".skip"
+#endif
 
-// __MACH__
-// .byte generates 1 byte per expression.
-// .short generates 2 bytes per expression.
-// .long generates 4 bytes per expression.
-// .quad generates 8 bytes per expression.
 
 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
 
-#if defined(__x86_64__) && !defined(PLATFORM_WIN32)
+#if defined(TARGET_AMD64) && !defined(HOST_WIN32)
 #define USE_ELF_WRITER 1
 #define USE_ELF_RELA 1
 #endif
 
-#if defined(__i386__) && !defined(PLATFORM_WIN32)
+#if defined(TARGET_X86) && !defined(TARGET_WIN32)
 #define USE_ELF_WRITER 1
 #endif
 
-#if defined(__arm__) && !defined(__MACH__)
+#if defined(TARGET_ARM) && !defined(__MACH__)
 #define USE_ELF_WRITER 1
 #endif
 
@@ -128,11 +152,14 @@ struct _MonoImageWriter {
        BinReloc *relocations;
        GHashTable *labels;
        int num_relocs;
+       guint8 *out_buf;
+       int out_buf_size, out_buf_pos;
 #endif
        /* Asm writer */
        char *tmpfname;
        int mode; /* emit mode */
        int col_count; /* bytes emitted per .byte line */
+       int label_gen;
 };
 
 static G_GNUC_UNUSED int
@@ -186,6 +213,8 @@ struct _BinSection {
        int file_offset;
        int virt_offset;
        int shidx;
+       guint64 addr;
+       gboolean has_addr;
 };
 
 static void
@@ -218,6 +247,13 @@ bin_writer_emit_section_change (MonoImageWriter *acfg, const char *section_name,
        }
 }
 
+static void
+bin_writer_set_section_addr (MonoImageWriter *acfg, guint64 addr)
+{
+       acfg->cur_section->addr = addr;
+       acfg->cur_section->has_addr = TRUE;
+}
+
 static void
 bin_writer_emit_symbol_inner (MonoImageWriter *acfg, const char *name, const char *end_label, gboolean is_global, gboolean func)
 {
@@ -324,7 +360,7 @@ bin_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target)
        acfg->relocations = reloc;
        if (strcmp (reloc->section->name, ".data") == 0) {
                acfg->num_relocs++;
-               g_print ("reloc: %s at %d\n", target, acfg->cur_section->cur_offset);
+               //g_print ("reloc: %s at %d\n", target, acfg->cur_section->cur_offset);
        }
        acfg->cur_section->cur_offset += sizeof (gpointer);
 }
@@ -517,10 +553,16 @@ append_subsection (MonoImageWriter *acfg, ElfSectHeader *sheaders, BinSection *s
        int offset = sect->cur_offset;
        /*offset += (sheaders [sect->shidx].sh_addralign - 1);
        offset &= ~(sheaders [sect->shidx].sh_addralign - 1);*/
-       offset += (8 - 1);
-       offset &= ~(8 - 1);
+       /* 
+        * FIXME: we shouldn't align subsections at all, but if we don't then the
+        * stuff inside the subsections which is aligned won't get aligned.
+        */
+       if (strcmp (sect->name, ".debug_line") != 0) {
+               offset += (8 - 1);
+               offset &= ~(8 - 1);
+       }
        bin_writer_emit_ensure_buffer (sect, offset);
-       g_print ("section %s aligned to %d from %d\n", sect->name, offset, sect->cur_offset);
+       //g_print ("section %s aligned to %d from %d\n", sect->name, offset, sect->cur_offset);
        sect->cur_offset = offset;
 
        bin_writer_emit_ensure_buffer (sect, add->cur_offset);
@@ -528,7 +570,7 @@ append_subsection (MonoImageWriter *acfg, ElfSectHeader *sheaders, BinSection *s
        add->parent = sect;
        sect->cur_offset += add->cur_offset;
        add->cur_offset = offset; /* it becomes the offset in the parent section */
-       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);
+       //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);
        add->data = NULL;
        add->data_len = 0;
 }
@@ -867,19 +909,24 @@ resolve_relocations (MonoImageWriter *acfg)
 static void
 do_reloc (MonoImageWriter *acfg, BinReloc *reloc, guint8 *data, gssize addr)
 {
-#ifdef __arm__
+#ifdef TARGET_ARM
        /*
         * We use the official ARM relocation types, but implement only the stuff actually
         * needed by the code we generate.
         */
        switch (reloc->reloc_type) {
-       case R_ARM_CALL: {
+       case R_ARM_CALL:
+       case R_ARM_JUMP24: {
                guint32 *code = (guint32*)(gpointer)data;
                guint32 ins = *code;
                int diff = addr;
 
-               /* bl */
-               g_assert (data [3] == 0xeb);
+               if (reloc->reloc_type == R_ARM_CALL)
+                       /* bl */
+                       g_assert (data [3] == 0xeb);
+               else
+                       /* b */
+                       g_assert (data [3] == 0xea);
                if (diff >= 0 && diff <= 33554431) {
                        diff >>= 2;
                        ins = (ins & 0xff000000) | diff;
@@ -898,8 +945,11 @@ do_reloc (MonoImageWriter *acfg, BinReloc *reloc, guint8 *data, gssize addr)
                guint8 *code = data;
                guint32 val = addr;
 
-               g_assert (val <= 0xffff);
-               ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_PC, 0, 0);
+               g_assert (val <= 0xffffff);
+               if (val & 0xff0000)
+                       ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_PC, (val & 0xFF0000) >> 16, 16);
+               else
+                       ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_PC, 0, 0);
                ARM_ADD_REG_IMM (code, ARMREG_IP, ARMREG_IP, (val & 0xFF00) >> 8, 24);
                ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, val & 0xFF);
                break;
@@ -951,6 +1001,29 @@ resolve_relocations (MonoImageWriter *acfg)
 
 #endif /* USE_ELF_RELA */
 
+static void
+bin_writer_fwrite (MonoImageWriter *acfg, void *val, size_t size, size_t nmemb)
+{
+       if (acfg->fp)
+               fwrite (val, size, nmemb, acfg->fp);
+       else {
+               g_assert (acfg->out_buf_pos + (size * nmemb) <= acfg->out_buf_size);
+               memcpy (acfg->out_buf + acfg->out_buf_pos, val, size * nmemb);
+               acfg->out_buf_pos += (size * nmemb);
+       }
+}
+
+static void
+bin_writer_fseek (MonoImageWriter *acfg, int offset)
+{
+       if (acfg->fp)
+               fseek (acfg->fp, offset, SEEK_SET);
+       else
+               acfg->out_buf_pos = offset;
+}
+
+static int normal_sections [] = { SECT_DATA, SECT_DEBUG_FRAME, SECT_DEBUG_INFO, SECT_DEBUG_ABBREV, SECT_DEBUG_LINE, SECT_DEBUG_LOC };
+
 static int
 bin_writer_emit_writeout (MonoImageWriter *acfg)
 {
@@ -1001,12 +1074,13 @@ bin_writer_emit_writeout (MonoImageWriter *acfg)
        num_sections = collect_sections (acfg, secth, all_sections, 16);
        hash = build_hash (acfg, num_sections, &dyn_str_table);
        num_symtab = hash [1]; /* FIXME */
+#if 0
        g_print ("num_sections: %d\n", num_sections);
        g_print ("dynsym: %d, dynstr size: %d\n", hash [1], (int)dyn_str_table.data->len);
        for (i = 0; i < num_sections; ++i) {
                g_print ("section %s, size: %d, %x\n", all_sections [i]->name, all_sections [i]->cur_offset, all_sections [i]->cur_offset);
        }
-
+#endif
        /* Associate the bin sections with the ELF sections */
        memset (sections, 0, sizeof (sections));
        for (i = 0; i < num_sections; ++i) {
@@ -1064,6 +1138,10 @@ bin_writer_emit_writeout (MonoImageWriter *acfg)
        virt_offset = file_offset;
        secth [SECT_TEXT].sh_addr = secth [SECT_TEXT].sh_offset = file_offset;
        if (sections [SECT_TEXT]) {
+               if (sections [SECT_TEXT]->has_addr) {
+                       secth [SECT_TEXT].sh_addr = sections [SECT_TEXT]->addr;
+                       secth [SECT_TEXT].sh_flags &= ~SHF_ALLOC;
+               }
                size = sections [SECT_TEXT]->cur_offset;
                secth [SECT_TEXT].sh_size = size;
                file_offset += size;
@@ -1187,11 +1265,11 @@ bin_writer_emit_writeout (MonoImageWriter *acfg)
                header.e_ident [i] = 0;
 
        header.e_type = ET_DYN;
-#if defined(__i386__)
+#if defined(TARGET_X86)
        header.e_machine = EM_386;
-#elif defined(__x86_64__)
+#elif defined(TARGET_AMD64)
        header.e_machine = EM_X86_64;
-#elif defined(__arm__)
+#elif defined(TARGET_ARM)
        header.e_machine = EM_ARM;
 #else
        g_assert_not_reached ();
@@ -1284,63 +1362,58 @@ bin_writer_emit_writeout (MonoImageWriter *acfg)
        reloc_symbols (acfg, symtab, secth, &str_table, FALSE);
        relocs = resolve_relocations (acfg);
 
-       fwrite (&header, sizeof (header), 1, file);
-       fwrite (&progh, sizeof (progh), 1, file);
-       fwrite (hash, sizeof (int) * (hash [0] + hash [1] + 2), 1, file);
-       fwrite (dynsym, sizeof (ElfSymbol) * hash [1], 1, file);
-       fwrite (dyn_str_table.data->str, dyn_str_table.data->len, 1, file);
+       if (!acfg->fp) {
+               acfg->out_buf_size = file_offset + sizeof (secth);
+               acfg->out_buf = g_malloc (acfg->out_buf_size);
+       }
+
+       bin_writer_fwrite (acfg, &header, sizeof (header), 1);
+       bin_writer_fwrite (acfg, &progh, sizeof (progh), 1);
+       bin_writer_fwrite (acfg, hash, sizeof (int) * (hash [0] + hash [1] + 2), 1);
+       bin_writer_fwrite (acfg, dynsym, sizeof (ElfSymbol) * hash [1], 1);
+       bin_writer_fwrite (acfg, dyn_str_table.data->str, dyn_str_table.data->len, 1);
        /* .rel.dyn */
-       fseek (file, secth [SECT_REL_DYN].sh_offset, SEEK_SET);
-       fwrite (relocs, sizeof (ElfReloc), acfg->num_relocs, file);
+       bin_writer_fseek (acfg, secth [SECT_REL_DYN].sh_offset);
+       bin_writer_fwrite (acfg, relocs, sizeof (ElfReloc), acfg->num_relocs);
 
        /* .rela.dyn */
-       fseek (file, secth [SECT_RELA_DYN].sh_offset, SEEK_SET);
-       fwrite (relocs, secth [SECT_RELA_DYN].sh_size, 1, file);
+       bin_writer_fseek (acfg, secth [SECT_RELA_DYN].sh_offset);
+       bin_writer_fwrite (acfg, relocs, secth [SECT_RELA_DYN].sh_size, 1);
 
        /* .text */
        if (sections [SECT_TEXT]) {
-               fseek (file, secth [SECT_TEXT].sh_offset, SEEK_SET);
-               fwrite (sections [SECT_TEXT]->data, sections [SECT_TEXT]->cur_offset, 1, file);
+               bin_writer_fseek (acfg, secth [SECT_TEXT].sh_offset);
+               bin_writer_fwrite (acfg, sections [SECT_TEXT]->data, sections [SECT_TEXT]->cur_offset, 1);
        }
        /* .dynamic */
-       fwrite (dynamic, sizeof (dynamic), 1, file);
+       bin_writer_fwrite (acfg, dynamic, sizeof (dynamic), 1);
 
        /* .got.plt */
        size = secth [SECT_DYNAMIC].sh_addr;
-       fwrite (&size, sizeof (size), 1, file);
-
-       /* .data */
-       if (sections [SECT_DATA]) {
-               fseek (file, secth [SECT_DATA].sh_offset, SEEK_SET);
-               fwrite (sections [SECT_DATA]->data, sections [SECT_DATA]->cur_offset, 1, file);
+       bin_writer_fwrite (acfg, &size, sizeof (size), 1);
+
+       /* normal sections */
+       for (i = 0; i < sizeof (normal_sections) / sizeof (normal_sections [0]); ++i) {
+               int sect = normal_sections [i];
+               if (sections [sect]) {
+                       bin_writer_fseek (acfg, secth [sect].sh_offset);
+                       bin_writer_fwrite (acfg, sections [sect]->data, sections [sect]->cur_offset, 1);
+               }
        }
 
-       fseek (file, secth [SECT_DEBUG_FRAME].sh_offset, SEEK_SET);
-       if (sections [SECT_DEBUG_FRAME])
-               fwrite (sections [SECT_DEBUG_FRAME]->data, sections [SECT_DEBUG_FRAME]->cur_offset, 1, file);
-       fseek (file, secth [SECT_DEBUG_INFO].sh_offset, SEEK_SET);
-       if (sections [SECT_DEBUG_INFO])
-               fwrite (sections [SECT_DEBUG_INFO]->data, sections [SECT_DEBUG_INFO]->cur_offset, 1, file);
-       fseek (file, secth [SECT_DEBUG_ABBREV].sh_offset, SEEK_SET);
-       if (sections [SECT_DEBUG_ABBREV])
-               fwrite (sections [SECT_DEBUG_ABBREV]->data, sections [SECT_DEBUG_ABBREV]->cur_offset, 1, file);
-       fseek (file, secth [SECT_DEBUG_LINE].sh_offset, SEEK_SET);
-       if (sections [SECT_DEBUG_LINE])
-               fwrite (sections [SECT_DEBUG_LINE]->data, sections [SECT_DEBUG_LINE]->cur_offset, 1, file);
-       fseek (file, secth [SECT_DEBUG_LINE].sh_offset, SEEK_SET);
-       if (sections [SECT_DEBUG_LOC])
-               fwrite (sections [SECT_DEBUG_LOC]->data, sections [SECT_DEBUG_LOC]->cur_offset, 1, file);
-       fseek (file, secth [SECT_SHSTRTAB].sh_offset, SEEK_SET);
-       fwrite (sh_str_table.data->str, sh_str_table.data->len, 1, file);
-       fseek (file, secth [SECT_SYMTAB].sh_offset, SEEK_SET);
-       fwrite (symtab, sizeof (ElfSymbol) * num_local_syms, 1, file);
-       fseek (file, secth [SECT_STRTAB].sh_offset, SEEK_SET);
-       fwrite (str_table.data->str, str_table.data->len, 1, file);
+       bin_writer_fseek (acfg, secth [SECT_SHSTRTAB].sh_offset);
+       bin_writer_fwrite (acfg, sh_str_table.data->str, sh_str_table.data->len, 1);
+       bin_writer_fseek (acfg, secth [SECT_SYMTAB].sh_offset);
+       bin_writer_fwrite (acfg, symtab, sizeof (ElfSymbol) * num_local_syms, 1);
+       bin_writer_fseek (acfg, secth [SECT_STRTAB].sh_offset);
+       bin_writer_fwrite (acfg, str_table.data->str, str_table.data->len, 1);
        /*g_print ("file_offset %d vs %d\n", file_offset, ftell (file));*/
        /*g_assert (file_offset >= ftell (file));*/
-       fseek (file, file_offset, SEEK_SET);
-       fwrite (&secth, sizeof (secth), 1, file);
-       fclose (file);
+       bin_writer_fseek (acfg, file_offset);
+       bin_writer_fwrite (acfg, &secth, sizeof (secth), 1);
+
+       if (acfg->fp)
+               fclose (acfg->fp);
 
        return 0;
 }
@@ -1377,17 +1450,15 @@ static void
 asm_writer_emit_section_change (MonoImageWriter *acfg, const char *section_name, int subsection_index)
 {
        asm_writer_emit_unset_mode (acfg);
-#if defined(PLATFORM_WIN32)
-       fprintf (acfg->fp, ".section %s\n", section_name);
-#elif defined(__MACH__)
+#if defined(TARGET_ASM_APPLE)
        if (strcmp(section_name, ".bss") == 0)
                fprintf (acfg->fp, "%s\n", ".data");
-       else
+       else if (strstr (section_name, ".debug") == section_name) {
+               //g_assert (subsection_index == 0);
+               fprintf (acfg->fp, ".section __DWARF, __%s,regular,debug\n", section_name + 1);
+       } else
                fprintf (acfg->fp, "%s\n", section_name);
-#elif defined(sparc)
-       /* For solaris as, GNU as should accept the same */
-       fprintf (acfg->fp, ".section \"%s\"\n", section_name);
-#elif defined(__arm__)
+#elif defined(TARGET_ARM) || defined(TARGET_POWERPC)
        /* ARM gas doesn't seem to like subsections of .bss */
        if (!strcmp (section_name, ".text") || !strcmp (section_name, ".data")) {
                fprintf (acfg->fp, "%s %d\n", section_name, subsection_index);
@@ -1395,6 +1466,8 @@ asm_writer_emit_section_change (MonoImageWriter *acfg, const char *section_name,
                fprintf (acfg->fp, ".section \"%s\"\n", section_name);
                fprintf (acfg->fp, ".subsection %d\n", subsection_index);
        }
+#elif defined(HOST_WIN32)
+       fprintf (acfg->fp, ".section %s\n", section_name);
 #else
        if (!strcmp (section_name, ".text") || !strcmp (section_name, ".data") || !strcmp (section_name, ".bss")) {
                fprintf (acfg->fp, "%s %d\n", section_name, subsection_index);
@@ -1405,6 +1478,17 @@ asm_writer_emit_section_change (MonoImageWriter *acfg, const char *section_name,
 #endif
 }
 
+static inline
+const char *get_label (const char *s)
+{
+#ifdef TARGET_ASM_APPLE
+       if (s [0] == '.' && s [1] == 'L')
+               /* apple uses "L" instead of ".L" to mark temporary labels */
+               s ++;
+#endif
+       return s;
+}
+
 static void
 asm_writer_emit_symbol_type (MonoImageWriter *acfg, const char *name, gboolean func)
 {
@@ -1416,14 +1500,10 @@ asm_writer_emit_symbol_type (MonoImageWriter *acfg, const char *name, gboolean f
                stype = "object";
 
        asm_writer_emit_unset_mode (acfg);
-#if defined(__MACH__)
+#if defined(TARGET_ASM_APPLE)
 
-#elif defined(sparc) || defined(__arm__)
+#elif defined(TARGET_ARM)
        fprintf (acfg->fp, "\t.type %s,#%s\n", name, stype);
-#elif defined(PLATFORM_WIN32)
-
-#elif defined(__x86_64__) || defined(__i386__)
-       fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
 #else
        fprintf (acfg->fp, "\t.type %s,@%s\n", name, stype);
 #endif
@@ -1433,7 +1513,7 @@ static void
 asm_writer_emit_global (MonoImageWriter *acfg, const char *name, gboolean func)
 {
        asm_writer_emit_unset_mode (acfg);
-#if  (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
+#if  (defined(__ppc__) && defined(TARGET_ASM_APPLE)) || (defined(HOST_WIN32) && !defined(MONO_CROSS_COMPILE))
     // mach-o always uses a '_' prefix.
        fprintf (acfg->fp, "\t.globl _%s\n", name);
 #else
@@ -1448,26 +1528,37 @@ asm_writer_emit_local_symbol (MonoImageWriter *acfg, const char *name, const cha
 {
        asm_writer_emit_unset_mode (acfg);
 
+#ifndef TARGET_ASM_APPLE
        fprintf (acfg->fp, "\t.local %s\n", name);
+#endif
 
        asm_writer_emit_symbol_type (acfg, name, func);
 }
 
 static void
-asm_writer_emit_label (MonoImageWriter *acfg, const char *name)
+asm_writer_emit_symbol_size (MonoImageWriter *acfg, const char *name, const char *end_label)
 {
        asm_writer_emit_unset_mode (acfg);
-#if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
-    // mach-o always uses a '_' prefix.
-       fprintf (acfg->fp, "_%s:\n", name);
-#else
-       fprintf (acfg->fp, "%s:\n", name);
+
+#ifndef TARGET_ASM_APPLE
+       fprintf (acfg->fp, "\t.size %s,%s-%s\n", name, end_label, name);
 #endif
+}
 
-#if defined(PLATFORM_WIN32)
+static void
+asm_writer_emit_label (MonoImageWriter *acfg, const char *name)
+{
+       asm_writer_emit_unset_mode (acfg);
+#if defined(HOST_WIN32) && (defined(TARGET_X86) || defined(TARGET_AMD64))
+       fprintf (acfg->fp, "_%s:\n", name);
+#if defined(HOST_WIN32)
        /* Emit a normal label too */
        fprintf (acfg->fp, "%s:\n", name);
 #endif
+#else
+       fprintf (acfg->fp, "%s:\n", get_label (name));
+#endif
+
 }
 
 static void
@@ -1488,13 +1579,13 @@ static void
 asm_writer_emit_alignment (MonoImageWriter *acfg, int size)
 {
        asm_writer_emit_unset_mode (acfg);
-#if defined(__arm__)
+#if defined(TARGET_ARM)
        fprintf (acfg->fp, "\t.align %d\n", ilog2 (size));
-#elif defined(__ppc__) && defined(__MACH__)
+#elif defined(__ppc__) && defined(TARGET_ASM_APPLE)
        // the mach-o assembler specifies alignments as powers of 2.
        fprintf (acfg->fp, "\t.align %d\t; ilog2\n", ilog2(size));
-#elif defined(__powerpc__)
-       /* ignore on linux/ppc */
+#elif defined(TARGET_ASM_GAS)
+       fprintf (acfg->fp, "\t.balign %d\n", size);
 #else
        fprintf (acfg->fp, "\t.align %d\n", size);
 #endif
@@ -1504,13 +1595,7 @@ static void
 asm_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target)
 {
        asm_writer_emit_unset_mode (acfg);
-#if defined(__x86_64__)
-       fprintf (acfg->fp, "\t.quad %s\n", target ? target : "0");
-#elif defined(sparc) && SIZEOF_VOID_P == 8
-       fprintf (acfg->fp, "\t.xword %s\n", target ? target : "0");
-#else
-       fprintf (acfg->fp, "\t.long %s\n", target ? target : "0");
-#endif
+       fprintf (acfg->fp, "\t%s %s\n", AS_POINTER_DIRECTIVE, target ? target : "0");
 }
 
 static void
@@ -1555,14 +1640,7 @@ asm_writer_emit_int16 (MonoImageWriter *acfg, int value)
                acfg->col_count = 0;
        }
        if ((acfg->col_count++ % 8) == 0)
-#if defined(__MACH__)
-               fprintf (acfg->fp, "\n\t.short ");
-#elif defined(__arm__)
-               /* FIXME: Use .hword on other archs as well */
-               fprintf (acfg->fp, "\n\t.hword ");
-#else
-               fprintf (acfg->fp, "\n\t.word ");
-#endif
+               fprintf (acfg->fp, "\n\t%s ", AS_INT16_DIRECTIVE);
        else
                fprintf (acfg->fp, ", ");
        fprintf (acfg->fp, "%d", value);
@@ -1576,7 +1654,7 @@ asm_writer_emit_int32 (MonoImageWriter *acfg, int value)
                acfg->col_count = 0;
        }
        if ((acfg->col_count++ % 8) == 0)
-               fprintf (acfg->fp, "\n\t.long ");
+               fprintf (acfg->fp, "\n\t%s ", AS_INT32_DIRECTIVE);
        else
                fprintf (acfg->fp, ",");
        fprintf (acfg->fp, "%d", value);
@@ -1585,12 +1663,37 @@ asm_writer_emit_int32 (MonoImageWriter *acfg, int value)
 static void
 asm_writer_emit_symbol_diff (MonoImageWriter *acfg, const char *end, const char* start, int offset)
 {
+#ifdef TARGET_ASM_APPLE
+       char symbol [128];
+#endif
+
        if (acfg->mode != EMIT_LONG) {
                acfg->mode = EMIT_LONG;
                acfg->col_count = 0;
        }
+
+       // FIXME: This doesn't seem to work on the iphone
+#if 0
+       //#ifdef TARGET_ASM_APPLE
+       /* The apple assembler needs a separate symbol to be able to handle complex expressions */
+       sprintf (symbol, "LTMP_SYM%d", acfg->label_gen);
+       start = get_label (start);
+       end = get_label (end);
+       acfg->label_gen ++;
+       if (offset > 0)
+               fprintf (acfg->fp, "\n%s=%s - %s + %d", symbol, end, start, offset);
+       else if (offset < 0)
+               fprintf (acfg->fp, "\n%s=%s - %s %d", symbol, end, start, offset);
+       else
+               fprintf (acfg->fp, "\n%s=%s - %s", symbol, end, start);
+
+       fprintf (acfg->fp, "\n\t%s ", AS_INT32_DIRECTIVE);
+       fprintf (acfg->fp, "%s", symbol);
+#else
+       start = get_label (start);
+       end = get_label (end);
        if ((acfg->col_count++ % 8) == 0)
-               fprintf (acfg->fp, "\n\t.long ");
+               fprintf (acfg->fp, "\n\t%s ", AS_INT32_DIRECTIVE);
        else
                fprintf (acfg->fp, ",");
        if (offset > 0)
@@ -1599,17 +1702,14 @@ asm_writer_emit_symbol_diff (MonoImageWriter *acfg, const char *end, const char*
                fprintf (acfg->fp, "%s - %s %d", end, start, offset);
        else
                fprintf (acfg->fp, "%s - %s", end, start);
+#endif
 }
 
 static void
 asm_writer_emit_zero_bytes (MonoImageWriter *acfg, int num)
 {
        asm_writer_emit_unset_mode (acfg);
-#if defined(__MACH__)
-       fprintf (acfg->fp, "\t.space %d\n", num);
-#else
-       fprintf (acfg->fp, "\t.skip %d\n", num);
-#endif
+       fprintf (acfg->fp, "\t%s %d\n", AS_SKIP_DIRECTIVE, num);
 }
 
 /* EMIT FUNCTIONS */
@@ -1662,6 +1762,19 @@ img_writer_emit_pop_section (MonoImageWriter *acfg)
        img_writer_emit_section_change (acfg, acfg->section_stack [acfg->stack_pos], acfg->subsection_stack [acfg->stack_pos]);
 }
 
+void
+img_writer_set_section_addr (MonoImageWriter *acfg, guint64 addr)
+{
+#ifdef USE_BIN_WRITER
+       if (!acfg->use_bin_writer)
+               NOT_IMPLEMENTED;
+       else
+               bin_writer_set_section_addr (acfg, addr);
+#else
+       NOT_IMPLEMENTED;
+#endif
+}
+
 void
 img_writer_emit_global (MonoImageWriter *acfg, const char *name, gboolean func)
 {
@@ -1688,6 +1801,13 @@ img_writer_emit_local_symbol (MonoImageWriter *acfg, const char *name, const cha
 #endif
 }
 
+void
+img_writer_emit_symbol_size (MonoImageWriter *acfg, const char *name, const char *end_label)
+{
+       if (!acfg->use_bin_writer)
+               asm_writer_emit_symbol_size (acfg, name, end_label);
+}
+
 void
 img_writer_emit_label (MonoImageWriter *acfg, const char *name)
 {
@@ -1881,6 +2001,30 @@ img_writer_emit_unset_mode (MonoImageWriter *acfg)
                asm_writer_emit_unset_mode (acfg);
 }
 
+/*
+ * img_writer_get_output:
+ *
+ *   Return the output buffer of a binary writer emitting to memory. The returned memory
+ * is from malloc, and it is owned by the caller.
+ */
+guint8*
+img_writer_get_output (MonoImageWriter *acfg, guint32 *size)
+{
+#ifdef USE_BIN_WRITER
+       guint8 *buf;
+
+       g_assert (acfg->use_bin_writer);
+
+       buf = acfg->out_buf;
+       *size = acfg->out_buf_size;
+       acfg->out_buf = NULL;
+       return buf;
+#else
+       g_assert_not_reached ();
+       return NULL;
+#endif
+}
+
 /*
  * Return whenever the binary writer is supported on this platform.
  */
@@ -1894,6 +2038,13 @@ bin_writer_supported (void)
 #endif
 }
 
+/*
+ * img_writer_create:
+ *
+ *   Create an image writer writing to FP. If USE_BIN_WRITER is TRUE, FP can be NULL,
+ * in this case the image writer will write to a memory buffer obtainable by calling
+ * img_writer_get_output ().
+ */
 MonoImageWriter*
 img_writer_create (FILE *fp, gboolean use_bin_writer)
 {
@@ -1903,6 +2054,9 @@ img_writer_create (FILE *fp, gboolean use_bin_writer)
        g_assert (!use_bin_writer);
 #endif
 
+       if (!use_bin_writer)
+               g_assert (fp);
+
        w->fp = fp;
        w->use_bin_writer = use_bin_writer;
        w->mempool = mono_mempool_new ();
@@ -1917,3 +2071,29 @@ img_writer_destroy (MonoImageWriter *w)
        mono_mempool_destroy (w->mempool);
        g_free (w);
 }
+
+gboolean
+img_writer_subsections_supported (MonoImageWriter *acfg)
+{
+#ifdef TARGET_ASM_APPLE
+       return acfg->use_bin_writer;
+#else
+       return TRUE;
+#endif
+}
+
+FILE *
+img_writer_get_fp (MonoImageWriter *acfg)
+{
+       return acfg->fp;
+}
+
+const char *
+img_writer_get_temp_label_prefix (MonoImageWriter *acfg)
+{
+#ifdef TARGET_ASM_APPLE
+       return "L";
+#else
+       return ".L";
+#endif
+}