Revert "Revert "Merge branch 'master' of https://github.com/mono/mono""
[mono.git] / mono / mini / image-writer.c
index 94ca5b5ca33b0302d5c5d3e73af76f31c2a8ad21..62b2b3525a5509a9f2dded8a9443218af17b6711 100644 (file)
 
 #if (defined(TARGET_AMD64) || defined(TARGET_POWERPC64)) && !defined(__mono_ilp32__)
 #define AS_POINTER_DIRECTIVE ".quad"
+#elif defined(TARGET_ARM64)
+
+#ifdef TARGET_ASM_APPLE
+#define AS_POINTER_DIRECTIVE ".quad"
+#else
+#define AS_POINTER_DIRECTIVE ".xword"
+#endif
+
 #else
 #define AS_POINTER_DIRECTIVE ".long"
 #endif
 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
 
-#if defined(TARGET_AMD64) && !defined(HOST_WIN32)
+#if defined(TARGET_AMD64) && !defined(HOST_WIN32) && !defined(__APPLE__)
 #define USE_ELF_WRITER 1
 #define USE_ELF_RELA 1
 #endif
 #define USE_ELF_WRITER 1
 #endif
 
-#if defined(USE_ELF_WRITER)
+#if defined(TARGET_X86) && defined(__APPLE__)
+//#define USE_MACH_WRITER
+#endif
+
+#if defined(USE_ELF_WRITER) || defined(USE_MACH_WRITER)
 #define USE_BIN_WRITER 1
 #endif
 
@@ -481,6 +493,206 @@ bin_writer_emit_zero_bytes (MonoImageWriter *acfg, int num)
        acfg->cur_section->cur_offset += num;
 }
 
+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;
+}
+
+#ifdef USE_MACH_WRITER
+
+/*
+ * This is a minimal implementation designed to support xdebug on 32 bit osx
+ * FIXME: 64 bit support
+ */
+
+#include <mach-o/loader.h>
+
+static gsize
+get_label_addr (MonoImageWriter *acfg, const char *name)
+{
+       int offset;
+       BinLabel *lab;
+       BinSection *section;
+       gsize value;
+
+       lab = g_hash_table_lookup (acfg->labels, name);
+       if (!lab)
+               g_error ("Undefined label: '%s'.\n", name);
+       section = lab->section;
+       offset = lab->offset;
+       if (section->parent) {
+               value = section->parent->virt_offset + section->cur_offset + offset;
+       } else {
+               value = section->virt_offset + offset;
+       }
+       return value;
+}
+
+
+static void
+resolve_reloc (MonoImageWriter *acfg, BinReloc *reloc, guint8 **out_data, gsize *out_vaddr, gsize *out_start_val, gsize *out_end_val)
+{
+       guint8 *data;
+       gssize end_val, start_val;
+       gsize vaddr;
+
+       end_val = get_label_addr (acfg, reloc->val1);
+       if (reloc->val2) {
+               start_val = get_label_addr (acfg, reloc->val2);
+       } else if (reloc->val2_section) {
+               start_val = reloc->val2_offset;
+               if (reloc->val2_section->parent)
+                       start_val += reloc->val2_section->parent->virt_offset + reloc->val2_section->cur_offset;
+               else
+                       start_val += reloc->val2_section->virt_offset;
+       } else {
+               start_val = 0;
+       }
+       end_val = end_val - start_val + reloc->offset;
+       if (reloc->section->parent) {
+               data = reloc->section->parent->data;
+               data += reloc->section->cur_offset;
+               data += reloc->section_offset;
+               vaddr = reloc->section->parent->virt_offset;
+               vaddr += reloc->section->cur_offset;
+               vaddr += reloc->section_offset;
+       } else {
+               data = reloc->section->data;
+               data += reloc->section_offset;
+               vaddr = reloc->section->virt_offset;
+               vaddr += reloc->section_offset;
+       }
+
+       *out_start_val = start_val;
+       *out_end_val = end_val;
+       *out_data = data;
+       *out_vaddr = vaddr;
+}
+
+static void
+resolve_relocations (MonoImageWriter *acfg)
+{
+       BinReloc *reloc;
+       guint8 *data;
+       gsize end_val, start_val;
+       gsize vaddr;
+
+       /* Only resolve static relocations */
+       for (reloc = acfg->relocations; reloc; reloc = reloc->next) {
+               resolve_reloc (acfg, reloc, &data, &vaddr, &start_val, &end_val);
+               data [0] = end_val;
+               data [1] = end_val >> 8;
+               data [2] = end_val >> 16;
+               data [3] = end_val >> 24;
+       }
+}
+
+static int
+bin_writer_emit_writeout (MonoImageWriter *acfg)
+{
+       BinSection *s;
+       int sindex, file_size, nsections, file_offset, vmaddr;
+       struct mach_header header;
+       struct segment_command segment;
+       struct section *sections;
+
+       /* Assing vm addresses to sections */
+       nsections = 0;
+       vmaddr = 0;
+       for (s = acfg->sections; s; s = s->next) {
+               s->virt_offset = vmaddr;
+               vmaddr += s->cur_offset;
+               nsections ++;
+       }
+
+       resolve_relocations (acfg);
+
+       file_offset = 0;
+
+       memset (&header, 0, sizeof (header));
+       header.magic = MH_MAGIC;
+       header.cputype = CPU_TYPE_X86;
+       header.cpusubtype = CPU_SUBTYPE_X86_ALL;
+       header.filetype = MH_OBJECT;
+       header.ncmds = 0;
+       header.sizeofcmds = 0;
+       header.flags = 0;
+
+       file_offset += sizeof (header);
+
+       memset (&segment, 0, sizeof (segment));
+       segment.cmd = LC_SEGMENT;
+       segment.cmdsize = sizeof (segment);
+       segment.maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+       segment.initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
+
+       file_offset += sizeof (segment);
+       file_offset += nsections * sizeof (struct section);
+
+       sections = g_new0 (struct section, nsections);
+       sindex = 0;
+       for (s = acfg->sections; s; s = s->next) {
+               s->file_offset = file_offset;
+
+               /* .debug_line -> __debug_line */
+               sprintf (sections [sindex].sectname, "__%s", s->name + 1);
+               sprintf (sections [sindex].segname, "%s", "__DWARF");
+               sections [sindex].addr = s->virt_offset;
+               sections [sindex].size = s->cur_offset;
+               sections [sindex].offset = s->file_offset;
+
+               file_offset += s->cur_offset;
+
+               segment.nsects ++;
+               segment.cmdsize += sizeof (struct section);
+
+               sindex ++;
+       }
+
+       header.ncmds ++;
+       header.sizeofcmds += segment.cmdsize;
+
+       /* Emit data */
+       file_size = file_offset;
+
+       if (!acfg->fp) {
+               acfg->out_buf_size = file_size;
+               acfg->out_buf = g_malloc (acfg->out_buf_size);
+       }
+
+       bin_writer_fwrite (acfg, &header, sizeof (header), 1);
+       bin_writer_fwrite (acfg, &segment, sizeof (segment), 1);
+       bin_writer_fwrite (acfg, sections, sizeof (struct section), nsections);
+       for (s = acfg->sections; s; s = s->next) {
+               if (!acfg->fp)
+                       g_assert (acfg->out_buf_pos == s->file_offset);
+               bin_writer_fwrite (acfg, s->data, s->cur_offset, 1);
+       }
+
+       if (acfg->fp)
+               fclose (acfg->fp);
+
+       return 0;
+}
+
+#endif
+
 #ifdef USE_ELF_WRITER
 
 enum {
@@ -1042,27 +1254,6 @@ 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
@@ -1530,7 +1721,7 @@ asm_writer_emit_section_change (MonoImageWriter *acfg, const char *section_name,
                fprintf (acfg->fp, ".section __DWARF, __%s,regular,debug\n", section_name + 1);
        } else
                fprintf (acfg->fp, "%s\n", section_name);
-#elif defined(TARGET_ARM) || defined(TARGET_POWERPC)
+#elif defined(TARGET_ARM) || defined(TARGET_ARM64) || 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);
@@ -1585,15 +1776,8 @@ static void
 asm_writer_emit_global (MonoImageWriter *acfg, const char *name, gboolean func)
 {
        asm_writer_emit_unset_mode (acfg);
-#if  ((defined(__ppc__) || defined(TARGET_X86)) && defined(TARGET_ASM_APPLE)) || (defined(HOST_WIN32) && !defined(MONO_CROSS_COMPILE))
-       if (name[0] != '_')
-               // mach-o always uses a '_' prefix.
-               fprintf (acfg->fp, "\t.globl _%s\n", name);
-       else
-               fprintf (acfg->fp, "\t.globl %s\n", name);
-#else
+
        fprintf (acfg->fp, "\t.globl %s\n", name);
-#endif
 
        asm_writer_emit_symbol_type (acfg, name, func);
 }
@@ -1624,22 +1808,7 @@ static void
 asm_writer_emit_label (MonoImageWriter *acfg, const char *name)
 {
        asm_writer_emit_unset_mode (acfg);
-#if (defined(TARGET_X86) && defined(TARGET_ASM_APPLE))
-        name = get_label(name);
-        fprintf (acfg->fp, "%s:\n", name);
-        if (name[0] != 'L' && name[0] != '_')
-            fprintf (acfg->fp, "_%s:\n", name);
-
-#elif (defined(HOST_WIN32) && (defined(TARGET_X86) || defined(TARGET_AMD64))) || (defined(TARGET_X86) && defined(TARGET_ASM_APPLE))
-       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