X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fimage-writer.c;h=986fe5d1d502e59ff6aba0195e6a1b38b63a6fd5;hb=7bbda0750f055c7823f85694d9e54f1ea7bcb094;hp=6f7460c5186dc75cfcdd74fdedafddd420408c33;hpb=0e5ba7097b8e61a87ed70c534b22e2ffb6238e5a;p=mono.git diff --git a/mono/mini/image-writer.c b/mono/mini/image-writer.c index 6f7460c5186..986fe5d1d50 100644 --- a/mono/mini/image-writer.c +++ b/mono/mini/image-writer.c @@ -20,7 +20,7 @@ #include #include #include -#ifndef PLATFORM_WIN32 +#ifndef HOST_WIN32 #include #else #include @@ -36,7 +36,7 @@ #include "image-writer.h" -#ifndef PLATFORM_WIN32 +#ifndef HOST_WIN32 #include #include #endif @@ -47,42 +47,77 @@ #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) +#if defined(__MACH__) && !defined(__native_client_codegen__) +#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. +#if defined(TARGET_ASM_APPLE) +#define AS_GLOBAL_PREFIX "_" +#else +#define AS_GLOBAL_PREFIX "" +#endif + +#ifdef TARGET_ASM_APPLE +#define AS_TEMP_LABEL_PREFIX "L" +#else +#define AS_TEMP_LABEL_PREFIX ".L" +#endif #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) && !defined(__APPLE__) #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 +163,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 +224,8 @@ struct _BinSection { int file_offset; int virt_offset; int shidx; + guint64 addr; + gboolean has_addr; }; static void @@ -218,6 +258,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) { @@ -266,6 +313,11 @@ bin_writer_emit_ensure_buffer (BinSection *section, int size) while (new_size <= new_offset) new_size *= 2; data = g_malloc0 (new_size); +#ifdef __native_client_codegen__ + /* for Native Client, fill empty space with HLT instruction */ + /* instead of 00. */ + memset(data, 0xf4, new_size); +#endif memcpy (data, section->data, section->data_len); g_free (section->data); section->data = data; @@ -308,14 +360,32 @@ bin_writer_emit_alignment (MonoImageWriter *acfg, int size) } } +#ifdef __native_client_codegen__ +static void +bin_writer_emit_nacl_call_alignment (MonoImageWriter *acfg) { + int offset = acfg->cur_section->cur_offset; + int padding = kNaClAlignment - (offset & kNaClAlignmentMask) - kNaClLengthOfCallImm; + guint8 padc = '\x90'; + + if (padding < 0) padding += kNaClAlignment; + + while (padding > 0) { + bin_writer_emit_bytes(acfg, &padc, 1); + padding -= 1; + } +} +#endif /* __native_client_codegen__ */ + static void bin_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target) { BinReloc *reloc; - if (!target) - // FIXME: - g_assert_not_reached (); + if (!target) { + acfg->cur_section->cur_offset += sizeof (gpointer); + return; + } + reloc = g_new0 (BinReloc, 1); reloc->val1 = g_strdup (target); reloc->section = acfg->cur_section; @@ -324,7 +394,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); } @@ -421,6 +491,7 @@ enum { SECT_REL_DYN, SECT_RELA_DYN, SECT_TEXT, + SECT_RODATA, SECT_DYNAMIC, SECT_GOT_PLT, SECT_DATA, @@ -474,6 +545,7 @@ static SectInfo section_info [] = { {".rel.dyn", SHT_REL, sizeof (ElfReloc), 2, SIZEOF_VOID_P}, {".rela.dyn", SHT_RELA, sizeof (ElfRelocA), 2, SIZEOF_VOID_P}, {".text", SHT_PROGBITS, 0, 6, 4096}, + {".rodata", SHT_PROGBITS, 0, SHF_ALLOC, 4096}, {".dynamic", SHT_DYNAMIC, sizeof (ElfDynamic), 3, SIZEOF_VOID_P}, {".got.plt", SHT_PROGBITS, SIZEOF_VOID_P, 3, SIZEOF_VOID_P}, {".data", SHT_PROGBITS, 0, 3, 8}, @@ -517,10 +589,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 +606,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; } @@ -663,6 +741,11 @@ collect_syms (MonoImageWriter *acfg, int *hash, ElfStrTable *strtab, ElfSectHead section->shidx = SECT_TEXT; section->file_offset = 4096; symbols [i].st_value = section->virt_offset; + } else if (strcmp (section->name, ".rodata") == 0) { + symbols [i].st_shndx = SECT_RODATA; + section->shidx = SECT_RODATA; + section->file_offset = 4096; + symbols [i].st_value = section->virt_offset; } else if (strcmp (section->name, ".data") == 0) { symbols [i].st_shndx = SECT_DATA; section->shidx = SECT_DATA; @@ -867,19 +950,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 +986,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,12 +1042,35 @@ 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) { FILE *file; ElfHeader header; - ElfProgHeader progh [3]; + ElfProgHeader progh [4]; ElfSectHeader secth [SECT_NUM]; #ifdef USE_ELF_RELA ElfRelocA *relocs; @@ -1001,12 +1115,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,11 +1179,26 @@ 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; } + file_offset = ALIGN_TO (file_offset, secth [SECT_RODATA].sh_addralign); + virt_offset = file_offset; + secth [SECT_RODATA].sh_addr = virt_offset; + secth [SECT_RODATA].sh_offset = file_offset; + if (sections [SECT_RODATA]) { + size = sections [SECT_RODATA]->cur_offset; + secth [SECT_RODATA].sh_size = size; + file_offset += size; + virt_offset += size; + } + file_offset = ALIGN_TO (file_offset, secth [SECT_DYNAMIC].sh_addralign); virt_offset = file_offset; @@ -1086,7 +1216,7 @@ bin_writer_emit_writeout (MonoImageWriter *acfg) virt_offset = ALIGN_TO (virt_offset, secth [SECT_GOT_PLT].sh_addralign); secth [SECT_GOT_PLT].sh_addr = virt_offset; secth [SECT_GOT_PLT].sh_offset = file_offset; - size = 12; + size = 3 * SIZEOF_VOID_P; secth [SECT_GOT_PLT].sh_size = size; file_offset += size; virt_offset += size; @@ -1171,6 +1301,11 @@ bin_writer_emit_writeout (MonoImageWriter *acfg) secth [SECT_STRTAB].sh_size = size; file_offset += size; + for (i = 1; i < SECT_NUM; ++i) { + if (section_info [i].esize != 0) + g_assert (secth [i].sh_size % section_info [i].esize == 0); + } + file_offset += 4-1; file_offset &= ~(4-1); @@ -1187,11 +1322,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 (); @@ -1201,7 +1336,7 @@ bin_writer_emit_writeout (MonoImageWriter *acfg) header.e_phoff = sizeof (header); header.e_ehsize = sizeof (header); header.e_phentsize = sizeof (ElfProgHeader); - header.e_phnum = 3; + header.e_phnum = 4; header.e_entry = secth [SECT_TEXT].sh_addr; header.e_shstrndx = SECT_SHSTRTAB; header.e_shentsize = sizeof (ElfSectHeader); @@ -1272,6 +1407,13 @@ bin_writer_emit_writeout (MonoImageWriter *acfg) progh [2].p_align = SIZEOF_VOID_P; progh [2].p_flags = 6; + progh [3].p_type = PT_GNU_STACK; + progh [3].p_offset = secth [SECT_DYNAMIC].sh_offset; + progh [3].p_vaddr = progh [3].p_paddr = secth [SECT_DYNAMIC].sh_addr; + progh [3].p_filesz = progh [3].p_memsz = secth [SECT_DYNAMIC].sh_size; + progh [3].p_align = SIZEOF_VOID_P; + progh [3].p_flags = 6; + /* Compute the addresses of the bin sections, so relocation can be done */ for (i = 0; i < SECT_NUM; ++i) { if (sections [i]) { @@ -1284,63 +1426,66 @@ 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); + } + /* .rodata */ + if (sections [SECT_RODATA]) { + bin_writer_fseek (acfg, secth [SECT_RODATA].sh_offset); + bin_writer_fwrite (acfg, sections [SECT_RODATA]->data, sections [SECT_RODATA]->cur_offset, 1); } /* .dynamic */ - fwrite (dynamic, sizeof (dynamic), 1, file); + bin_writer_fseek (acfg, secth [SECT_DYNAMIC].sh_offset); + bin_writer_fwrite (acfg, dynamic, sizeof (dynamic), 1); /* .got.plt */ size = secth [SECT_DYNAMIC].sh_addr; - fwrite (&size, sizeof (size), 1, file); + bin_writer_fseek (acfg, secth [SECT_GOT_PLT].sh_offset); + bin_writer_fwrite (acfg, &size, sizeof (size), 1); - /* .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); + /* 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 (§h, sizeof (secth), 1, file); - fclose (file); + bin_writer_fseek (acfg, file_offset); + bin_writer_fwrite (acfg, §h, sizeof (secth), 1); + + if (acfg->fp) + fclose (acfg->fp); return 0; } @@ -1377,17 +1522,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 +1538,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 +1550,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 +1572,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 +1585,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_X86)) && 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 +1600,43 @@ 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 +} + +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') + fprintf (acfg->fp, "_%s:\n", name); -#if defined(PLATFORM_WIN32) +#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 @@ -1488,30 +1657,39 @@ 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); +#elif defined(TARGET_ASM_APPLE) + fprintf (acfg->fp, "\t.align %d\n", ilog2 (size)); #else fprintf (acfg->fp, "\t.align %d\n", size); #endif } +#ifdef __native_client_codegen__ +static void +asm_writer_emit_nacl_call_alignment (MonoImageWriter *acfg) { + int padding = kNaClAlignment - kNaClLengthOfCallImm; + guint8 padc = '\x90'; + + fprintf (acfg->fp, "\n\t.align %d", kNaClAlignment); + while (padding > 0) { + fprintf (acfg->fp, "\n\t.byte %d", padc); + padding -= 1; + } +} +#endif /* __native_client_codegen__ */ + static void asm_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target) { asm_writer_emit_unset_mode (acfg); - asm_writer_emit_alignment (acfg, sizeof (gpointer)); -#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 @@ -1556,14 +1734,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); @@ -1577,7 +1748,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); @@ -1586,12 +1757,48 @@ 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 (offset == 0 && strcmp (start, ".") != 0) { + char symbol [128]; + sprintf (symbol, ".LDIFF_SYM%d", acfg->label_gen); + acfg->label_gen ++; + fprintf (acfg->fp, "\n%s=%s - %s", symbol, end, start); + fprintf (acfg->fp, "\n\t%s ", AS_INT32_DIRECTIVE); + fprintf (acfg->fp, "%s", symbol); + return; + } + 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) @@ -1600,17 +1807,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 */ @@ -1663,6 +1867,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) { @@ -1689,6 +1906,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) { @@ -1754,6 +1978,20 @@ img_writer_emit_alignment (MonoImageWriter *acfg, int size) #endif } +#ifdef __native_client_codegen__ +void +img_writer_emit_nacl_call_alignment (MonoImageWriter *acfg) { +#ifdef USE_BIN_WRITER + if (acfg->use_bin_writer) + bin_writer_emit_nacl_call_alignment (acfg); + else + asm_writer_emit_nacl_call_alignment (acfg); +#else + g_assert_not_reached(); +#endif +} +#endif /* __native_client_codegen__ */ + void img_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target) { @@ -1882,6 +2120,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. */ @@ -1895,6 +2157,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) { @@ -1904,6 +2173,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 (); @@ -1918,3 +2190,25 @@ 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) +{ + return AS_TEMP_LABEL_PREFIX; +}