typedef struct MonoAotOptions {
char *outfile;
+ char *llvm_outfile;
gboolean save_temps;
gboolean write_symbols;
gboolean metadata_only;
int jit_time, gen_time, link_time;
} MonoAotStats;
+typedef struct GotInfo {
+ GHashTable *patch_to_got_offset;
+ GHashTable **patch_to_got_offset_by_type;
+ GPtrArray *got_patches;
+} GotInfo;
+
typedef struct MonoAotCompile {
MonoImage *image;
GPtrArray *methods;
int cfgs_size;
GHashTable **patch_to_plt_entry;
GHashTable *plt_offset_to_entry;
- GHashTable *patch_to_got_offset;
- GHashTable **patch_to_got_offset_by_type;
- GPtrArray *got_patches;
+ //GHashTable *patch_to_got_offset;
+ //GHashTable **patch_to_got_offset_by_type;
+ //GPtrArray *got_patches;
+ GotInfo got_info, llvm_got_info;
GHashTable *image_hash;
GHashTable *method_to_cfg;
GHashTable *token_info_hash;
/* Maps MonoMethod* -> blob offset */
GHashTable *method_blob_hash;
guint32 *plt_got_info_offsets;
- guint32 got_offset, plt_offset, plt_got_offset_base;
- guint32 final_got_size;
+ guint32 got_offset, llvm_got_offset, plt_offset, plt_got_offset_base;
/* Number of GOT entries reserved for trampolines */
guint32 num_trampoline_got_entries;
guint32 tramp_page_size;
mono_mutex_t mutex;
gboolean use_bin_writer;
gboolean gas_line_numbers;
+ /* Whenever to emit LLVM code into a separate object file */
+ gboolean llvm_separate;
+ /* Whenever to emit an object file directly from llc */
+ gboolean llvm_owriter;
MonoImageWriter *w;
MonoDwarfWriter *dwarf;
FILE *fp;
char *tmpbasename;
char *tmpfname;
+ char *llvm_sfile;
+ char *llvm_ofile;
GSList *cie_program;
GHashTable *unwind_info_offsets;
GPtrArray *unwind_ops;
guint32 unwind_info_offset;
char *got_symbol_base;
+ char *llvm_got_symbol_base;
char *got_symbol;
+ char *llvm_got_symbol;
char *plt_symbol;
char *methods_symbol;
+ char *llvm_eh_frame_symbol;
GHashTable *method_label_hash;
const char *temp_prefix;
const char *user_symbol_prefix;
const char *llvm_label_prefix;
const char *inst_directive;
+ int align_pad_value;
guint32 label_generator;
gboolean llvm;
MonoAotFileFlags flags;
GHashTable *ginst_hash;
GHashTable *dwarf_ln_filenames;
gboolean global_symbols;
- gboolean direct_method_addresses;
int objc_selector_index, objc_selector_index_2;
GPtrArray *objc_selectors;
GHashTable *objc_selector_to_index;
}
static inline void
-emit_alignment (MonoAotCompile *acfg, int size)
+emit_alignment (MonoAotCompile *acfg, int size)
{
- img_writer_emit_alignment (acfg->w, size);
+ img_writer_emit_alignment (acfg->w, size);
+}
+
+static inline void
+emit_alignment_code (MonoAotCompile *acfg, int size)
+{
+ if (acfg->align_pad_value)
+ img_writer_emit_alignment_fill (acfg->w, size, acfg->align_pad_value);
+ else
+ img_writer_emit_alignment (acfg->w, size);
+}
+
+static inline void
+emit_padding (MonoAotCompile *acfg, int size)
+{
+ int i;
+ guint8 buf [16];
+
+ if (acfg->align_pad_value) {
+ for (i = 0; i < 16; ++i)
+ buf [i] = acfg->align_pad_value;
+ } else {
+ memset (buf, 0, sizeof (buf));
+ }
+
+ for (i = 0; i < size; i += 16) {
+ if (size - i < 16)
+ emit_bytes (acfg, buf, size - i);
+ else
+ emit_bytes (acfg, buf, 16);
+ }
}
static inline void
#if defined(TARGET_AMD64)
g_string_append (acfg->llc_args, " -march=x86-64 -mattr=sse4.1");
+ /* NOP */
+ acfg->align_pad_value = 0x90;
#endif
#ifdef TARGET_ARM
#endif
#ifdef MONOTOUCH
- acfg->direct_method_addresses = TRUE;
acfg->global_symbols = TRUE;
#endif
}
{
#if defined(TARGET_X86) || defined(TARGET_AMD64)
/* Need to make sure this is exactly 5 bytes long */
- if (external && !acfg->use_bin_writer) {
+ if (!acfg->use_bin_writer) {
emit_unset_mode (acfg);
fprintf (acfg->fp, "call %s\n", target);
} else {
static void
arch_emit_got_access (MonoAotCompile *acfg, guint8 *code, int got_slot, int *code_size)
{
- /* Emit beginning of instruction */
- emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
+ /* This needs to emit the same code as OP_AOTCONST */
- /* Emit the offset */
#ifdef TARGET_AMD64
- emit_symbol_diff (acfg, acfg->got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
- *code_size = mono_arch_get_patch_offset (code) + 4;
+ /* mov reg, got+offset(%rip) */
+ if (acfg->llvm_separate) {
+ /* The GOT symbol is in the LLVM module, the clang assembler has problems emitting symbol diffs for it */
+ int dreg;
+ int rex_r;
+
+ /* Decode reg, see amd64_mov_reg_membase () */
+ rex_r = code [0] & AMD64_REX_R;
+ g_assert (code [0] == 0x49 + rex_r);
+ g_assert (code [1] == 0x8b);
+ dreg = ((code [2] >> 3) & 0x7) + (rex_r ? 8 : 0);
+
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, "mov %s+%d(%%rip), %s\n", acfg->got_symbol, (unsigned int) ((got_slot * sizeof (gpointer))), mono_arch_regname (dreg));
+ *code_size = 7;
+ } else {
+ emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
+ *code_size = mono_arch_get_patch_offset (code) + 4;
+ }
#elif defined(TARGET_X86)
+ emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
emit_int32 (acfg, (unsigned int) ((got_slot * sizeof (gpointer))));
*code_size = mono_arch_get_patch_offset (code) + 4;
#elif defined(TARGET_ARM)
+ emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
emit_symbol_diff (acfg, acfg->got_symbol, ".", (unsigned int) ((got_slot * sizeof (gpointer))) - 12);
*code_size = mono_arch_get_patch_offset (code) + 4;
#elif defined(TARGET_ARM64)
+ emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
arm64_emit_got_access (acfg, code, got_slot, code_size);
#elif defined(TARGET_POWERPC)
{
guint8 buf [32];
guint8 *code;
+ emit_bytes (acfg, code, mono_arch_get_patch_offset (code));
code = buf;
ppc_load32 (code, ppc_r0, got_slot * sizeof (gpointer));
g_assert (code - buf == 8);
#endif /*__native_client_codegen__*/
#elif defined(TARGET_AMD64)
#if defined(__default_codegen__)
- /*
- * We can't emit jumps because they are 32 bits only so they can't be patched.
- * So we make indirect calls through GOT entries which are patched by the AOT
- * loader to point to .Lpd entries.
- */
- /* jmpq *<offset>(%rip) */
- emit_byte (acfg, '\xff');
- emit_byte (acfg, '\x25');
- emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4);
+ if (acfg->use_bin_writer) {
+ emit_byte (acfg, '\xff');
+ emit_byte (acfg, '\x25');
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", ((acfg->plt_got_offset_base + index) * sizeof (gpointer)) -4);
+ } else {
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, "jmp *%s+%d(%%rip)\n", acfg->got_symbol, (int)((acfg->plt_got_offset_base + index) * sizeof (gpointer)));
+ }
/* Used by mono_aot_get_plt_info_offset */
emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
acfg->stats.plt_size += 10;
*/
#if defined(TARGET_AMD64)
#if defined(__default_codegen__)
- /* This should be exactly 16 bytes long */
- *tramp_size = 16;
+ /* This should be exactly 8 bytes long */
+ *tramp_size = 8;
/* call *<offset>(%rip) */
- emit_byte (acfg, '\x41');
- emit_byte (acfg, '\xff');
- emit_byte (acfg, '\x15');
- emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
- /* This should be relative to the start of the trampoline */
- emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset+1) * sizeof (gpointer)) + 7);
- emit_zero_bytes (acfg, 5);
+ if (acfg->llvm_separate) {
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, "call *%s+%d(%%rip)\n", acfg->got_symbol, (int)(offset * sizeof (gpointer)));
+ emit_zero_bytes (acfg, 2);
+ } else {
+ emit_byte (acfg, '\x41');
+ emit_byte (acfg, '\xff');
+ emit_byte (acfg, '\x15');
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
+ emit_zero_bytes (acfg, 1);
+ }
#elif defined(__native_client_codegen__)
guint8 buf [256];
guint8 *buf_aligned = ALIGN_TO(buf, kNaClAlignment);
/* We clobber ECX, since EAX is used as MONO_ARCH_MONITOR_OBJECT_REG */
#ifdef MONO_ARCH_MONITOR_OBJECT_REG
g_assert (MONO_ARCH_MONITOR_OBJECT_REG != X86_ECX);
+#ifdef MONO_ARCH_MONITOR_LOCK_TAKEN_REG
+ g_assert (MONO_ARCH_MONITOR_LOCK_TAKEN_REG != X86_ECX);
+#endif
#endif
code = buf;
emit_bytes (acfg, buf, code - buf);
/* jump <method> */
- emit_byte (acfg, '\xe9');
- emit_symbol_diff (acfg, call_target, ".", -4);
+ if (acfg->llvm_separate) {
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, "jmp %s\n", call_target);
+ } else {
+ emit_byte (acfg, '\xe9');
+ emit_symbol_diff (acfg, call_target, ".", -4);
+ }
#elif defined(TARGET_X86)
guint8 buf [32];
guint8 *code;
/* This should be exactly 13 bytes long */
*tramp_size = 13;
- /* mov <OFFSET>(%rip), %r10 */
- emit_byte (acfg, '\x4d');
- emit_byte (acfg, '\x8b');
- emit_byte (acfg, '\x15');
- emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
+ if (acfg->llvm_separate) {
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, "mov %s+%d(%%rip), %%r10\n", acfg->got_symbol, (int)(offset * sizeof (gpointer)));
+ fprintf (acfg->fp, "jmp *%s+%d(%%rip)\n", acfg->got_symbol, (int)((offset + 1) * sizeof (gpointer)));
+ } else {
+ /* mov <OFFSET>(%rip), %r10 */
+ emit_byte (acfg, '\x4d');
+ emit_byte (acfg, '\x8b');
+ emit_byte (acfg, '\x15');
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
- /* jmp *<offset>(%rip) */
- emit_byte (acfg, '\xff');
- emit_byte (acfg, '\x25');
- emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4);
+ /* jmp *<offset>(%rip) */
+ emit_byte (acfg, '\xff');
+ emit_byte (acfg, '\x25');
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", ((offset + 1) * sizeof (gpointer)) - 4);
+ }
#elif defined(__native_client_codegen__)
guint8 buf [128];
guint8 *buf_aligned = ALIGN_TO(buf, kNaClAlignment);
/* MONO_ARCH_IMT_SCRATCH_REG is a free register */
+ if (acfg->llvm_separate) {
+ emit_unset_mode (acfg);
+ fprintf (acfg->fp, "mov %s+%d(%%rip), %s\n", acfg->got_symbol, (int)(offset * sizeof (gpointer)), mono_arch_regname (MONO_ARCH_IMT_SCRATCH_REG));
+ }
+
labels [0] = code;
amd64_alu_membase_imm (code, X86_CMP, MONO_ARCH_IMT_SCRATCH_REG, 0, 0);
labels [1] = code;
mono_amd64_patch (labels [3], code);
x86_breakpoint (code);
- /* mov <OFFSET>(%rip), MONO_ARCH_IMT_SCRATCH_REG */
- amd64_emit_rex (mov_buf_ptr, sizeof(gpointer), MONO_ARCH_IMT_SCRATCH_REG, 0, AMD64_RIP);
- *(mov_buf_ptr)++ = (unsigned char)0x8b; /* mov opcode */
- x86_address_byte (mov_buf_ptr, 0, MONO_ARCH_IMT_SCRATCH_REG & 0x7, 5);
- emit_bytes (acfg, mov_buf, mov_buf_ptr - mov_buf);
- emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
-
+ if (!acfg->llvm_separate) {
+ /* mov <OFFSET>(%rip), MONO_ARCH_IMT_SCRATCH_REG */
+ amd64_emit_rex (mov_buf_ptr, sizeof(gpointer), MONO_ARCH_IMT_SCRATCH_REG, 0, AMD64_RIP);
+ *(mov_buf_ptr)++ = (unsigned char)0x8b; /* mov opcode */
+ x86_address_byte (mov_buf_ptr, 0, MONO_ARCH_IMT_SCRATCH_REG & 0x7, 5);
+ emit_bytes (acfg, mov_buf, mov_buf_ptr - mov_buf);
+ emit_symbol_diff (acfg, acfg->got_symbol, ".", (offset * sizeof (gpointer)) - 4);
+ }
emit_bytes (acfg, buf, code - buf);
-
+
*tramp_size = code - buf + kSizeOfMove;
#if defined(__native_client_codegen__)
/* The tramp will be padded to the next kNaClAlignment bundle. */
case MONO_PATCH_INFO_RGCTX_FETCH:
case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
case MONO_PATCH_INFO_MONITOR_ENTER:
+ case MONO_PATCH_INFO_MONITOR_ENTER_V4:
case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
return TRUE;
acfg->patch_to_plt_entry [patch_info->type] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
res = g_hash_table_lookup (acfg->patch_to_plt_entry [patch_info->type], patch_info);
- // FIXME: This breaks the calculation of final_got_size
if (!acfg->llvm && patch_info->type == MONO_PATCH_INFO_METHOD && (patch_info->data.method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
/*
* Allocate a separate PLT slot for each such patch, since some plt
if (!res) {
MonoJumpInfo *new_ji;
- g_assert (!acfg->final_got_size);
-
new_ji = mono_patch_info_dup_mp (acfg->mempool, patch_info);
res = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoPltEntry));
* JI could be found if it exists, otherwise allocates a new one.
*/
static guint32
-get_got_offset (MonoAotCompile *acfg, MonoJumpInfo *ji)
+get_got_offset (MonoAotCompile *acfg, gboolean llvm, MonoJumpInfo *ji)
{
guint32 got_offset;
+ GotInfo *info = llvm ? &acfg->llvm_got_info : &acfg->got_info;
- got_offset = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_got_offset_by_type [ji->type], ji));
+ got_offset = GPOINTER_TO_UINT (g_hash_table_lookup (info->patch_to_got_offset_by_type [ji->type], ji));
if (got_offset)
return got_offset - 1;
- got_offset = acfg->got_offset;
- acfg->got_offset ++;
-
- if (acfg->final_got_size)
- g_assert (got_offset < acfg->final_got_size);
+ if (llvm) {
+ got_offset = acfg->llvm_got_offset;
+ acfg->llvm_got_offset ++;
+ } else {
+ got_offset = acfg->got_offset;
+ acfg->got_offset ++;
+ }
acfg->stats.got_slots ++;
acfg->stats.got_slot_types [ji->type] ++;
- g_hash_table_insert (acfg->patch_to_got_offset, ji, GUINT_TO_POINTER (got_offset + 1));
- g_hash_table_insert (acfg->patch_to_got_offset_by_type [ji->type], ji, GUINT_TO_POINTER (got_offset + 1));
- g_ptr_array_add (acfg->got_patches, ji);
+ g_hash_table_insert (info->patch_to_got_offset, ji, GUINT_TO_POINTER (got_offset + 1));
+ g_hash_table_insert (info->patch_to_got_offset_by_type [ji->type], ji, GUINT_TO_POINTER (got_offset + 1));
+ g_ptr_array_add (info->got_patches, ji);
return got_offset;
}
}
if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
- MonoMethodDesc *desc;
- MonoMethod *orig_method;
int nallocators;
/* Runtime invoke wrappers */
if (m)
add_method (acfg, m);
}
-
- /* Monitor Enter/Exit */
- desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
- orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
- /* This is a v4 method */
- if (orig_method) {
- method = mono_monitor_get_fast_path (orig_method);
- if (method)
- add_method (acfg, method);
- }
- mono_method_desc_free (desc);
-
- desc = mono_method_desc_new ("Monitor:Exit(object)", FALSE);
- orig_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
- g_assert (orig_method);
- mono_method_desc_free (desc);
- method = mono_monitor_get_fast_path (orig_method);
- if (method)
- add_method (acfg, method);
}
/* Stelemref wrappers */
/* isinst_with_check wrapper */
add_method (acfg, mono_marshal_get_isinst_with_cache ());
-#if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
- {
- MonoMethodDesc *desc;
- MonoMethod *m;
-
- desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
- m = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
- mono_method_desc_free (desc);
- if (m) {
- m = mono_monitor_get_fast_path (m);
- if (m)
- add_method (acfg, m);
- }
- }
-#endif
-
/* JIT icall wrappers */
/* FIXME: locking - this is "safe" as full-AOT threads don't mutate the icall hash*/
g_hash_table_foreach (mono_get_jit_icall_info (), add_jit_icall_wrapper, acfg);
if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
if (method->is_generic) {
// FIXME:
- } else if (method->klass->generic_container) {
+ } else if ((acfg->opts & MONO_OPT_GSHAREDVT) && method->klass->generic_container) {
MonoGenericContext ctx;
MonoMethod *inst, *gshared, *m;
} else {
int code_size;
- got_slot = get_got_offset (acfg, patch_info);
+ got_slot = get_got_offset (acfg, FALSE, patch_info);
arch_emit_got_access (acfg, code + i, got_slot, &code_size);
i += code_size - INST_LEN;
{
char *name1, *name2, *cached;
int i, j, len, count;
+ MonoMethod *cached_method;
name1 = mono_method_full_name (method, TRUE);
g_free (name1);
count = 0;
- while (g_hash_table_lookup (cache, name2)) {
+ while (TRUE) {
+ cached_method = g_hash_table_lookup (cache, name2);
+ if (!(cached_method && cached_method != method))
+ break;
sprintf (name2 + j, "_%d", count);
count ++;
}
cached = g_strdup (name2);
- g_hash_table_insert (cache, cached, cached);
+ g_hash_table_insert (cache, cached, method);
return name2;
}
method_index = get_method_index (acfg, method);
symbol = g_strdup_printf ("%sme_%x", acfg->temp_prefix, method_index);
-
/* Make the labels local */
emit_section_change (acfg, ".text", 0);
- emit_alignment (acfg, func_alignment);
+ emit_alignment_code (acfg, func_alignment);
if (acfg->global_symbols && acfg->need_no_dead_strip)
fprintf (acfg->fp, " .no_dead_strip %s\n", cfg->asm_symbol);
emit_label (acfg, cfg->asm_symbol);
- if (acfg->aot_opts.write_symbols && !acfg->global_symbols) {
+ if (acfg->aot_opts.write_symbols && !acfg->global_symbols && !acfg->llvm_separate) {
/*
* Write a C style symbol for every method, this has two uses:
* - it works on platforms where the dwarf debugging info is not
}
case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
case MONO_PATCH_INFO_MONITOR_ENTER:
+ case MONO_PATCH_INFO_MONITOR_ENTER_V4:
case MONO_PATCH_INFO_MONITOR_EXIT:
case MONO_PATCH_INFO_SEQ_POINT_INFO:
break;
}
break;
}
+ case MONO_PATCH_INFO_LDSTR_LIT: {
+ const char *s = patch_info->data.target;
+
+ encode_value (strlen (s), p, &p);
+ memcpy (p, s, strlen (s) + 1);
+ break;
+ }
default:
g_warning ("unable to handle jump info %d", patch_info->type);
g_assert_not_reached ();
}
static void
-encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, int first_got_offset, guint8 *buf, guint8 **endbuf)
+encode_patch_list (MonoAotCompile *acfg, GPtrArray *patches, int n_patches, gboolean llvm, int first_got_offset, guint8 *buf, guint8 **endbuf)
{
guint8 *p = buf;
guint32 pindex, offset;
/* Nothing to do */
continue;
- offset = get_got_offset (acfg, patch_info);
+ offset = get_got_offset (acfg, llvm, patch_info);
encode_value (offset, p, &p);
}
if (n_patches)
g_assert (cfg->has_got_slots);
- encode_patch_list (acfg, patches, n_patches, first_got_offset, p, &p);
+ encode_patch_list (acfg, patches, n_patches, cfg->compile_llvm, first_got_offset, p, &p);
acfg->stats.info_size += p - buf;
{
char *debug_sym = NULL;
char *s;
+ char *prefix;
+
+ if (acfg->llvm_separate && llvm_acfg->aot_opts.static_link) {
+ /* Need to add a prefix to create unique symbols */
+ prefix = g_strdup_printf ("plt_%s_", acfg->assembly_name_sym);
+ } else {
+ prefix = g_strdup ("plt_");
+ }
switch (ji->type) {
case MONO_PATCH_INFO_METHOD:
- debug_sym = get_debug_sym (ji->data.method, "plt_", cache);
+ debug_sym = get_debug_sym (ji->data.method, prefix, cache);
break;
case MONO_PATCH_INFO_INTERNAL_METHOD:
- debug_sym = g_strdup_printf ("plt__jit_icall_%s", ji->data.name);
+ debug_sym = g_strdup_printf ("%s_jit_icall_%s", prefix, ji->data.name);
break;
case MONO_PATCH_INFO_CLASS_INIT:
s = mono_type_get_name (&ji->data.klass->byval_arg);
- debug_sym = g_strdup_printf ("plt__class_init_%s", s);
+ debug_sym = g_strdup_printf ("%s__class_init_%s", prefix, s);
g_free (s);
break;
case MONO_PATCH_INFO_RGCTX_FETCH:
- debug_sym = g_strdup_printf ("plt__rgctx_fetch_%d", acfg->label_generator ++);
+ debug_sym = g_strdup_printf ("%s_rgctx_fetch_%d", prefix, acfg->label_generator ++);
break;
case MONO_PATCH_INFO_ICALL_ADDR: {
char *s = get_debug_sym (ji->data.method, "", cache);
- debug_sym = g_strdup_printf ("plt__icall_native_%s", s);
+ debug_sym = g_strdup_printf ("%s_icall_native_%s", prefix, s);
g_free (s);
break;
}
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
- debug_sym = g_strdup_printf ("plt__jit_icall_native_%s", ji->data.name);
+ debug_sym = g_strdup_printf ("%s_jit_icall_native_%s", prefix, ji->data.name);
break;
case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
- debug_sym = g_strdup_printf ("plt__generic_class_init");
+ debug_sym = g_strdup_printf ("%s_generic_class_init", prefix);
break;
default:
break;
}
+ g_free (prefix);
+
return sanitize_symbol (acfg, debug_sym);
}
sprintf (symbol, "plt");
emit_section_change (acfg, ".text", 0);
- emit_alignment (acfg, NACL_SIZE(16, kNaClAlignment));
+ emit_alignment_code (acfg, NACL_SIZE(16, kNaClAlignment));
emit_label (acfg, symbol);
emit_label (acfg, acfg->plt_symbol);
if (!plt_entry->jit_used && !plt_entry->llvm_used)
continue;
- if (acfg->llvm && !acfg->thumb_mixed)
+ if (acfg->llvm && !acfg->thumb_mixed) {
emit_label (acfg, plt_entry->llvm_symbol);
+ if (acfg->llvm_separate) {
+ emit_global (acfg, plt_entry->llvm_symbol, TRUE);
+ fprintf (acfg->fp, ".private_extern %s\n", plt_entry->llvm_symbol);
+ }
+ }
if (debug_sym) {
if (acfg->need_no_dead_strip) {
emit_section_change (acfg, ".text", 0);
emit_global (acfg, start_symbol, TRUE);
- emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+ emit_alignment_code (acfg, AOT_FUNC_ALIGNMENT);
emit_label (acfg, start_symbol);
sprintf (symbol, "%snamed_%s", acfg->temp_prefix, name);
buf = g_malloc (buf_size);
p = buf;
- encode_patch_list (acfg, patches, patches->len, got_offset, p, &p);
+ encode_patch_list (acfg, patches, patches->len, FALSE, got_offset, p, &p);
g_assert (p - buf < buf_size);
sprintf (symbol, "%s%s_p", acfg->user_symbol_prefix, name);
mono_arch_get_nullified_class_init_trampoline (&info);
emit_trampoline (acfg, acfg->got_offset, info);
#if defined(MONO_ARCH_MONITOR_OBJECT_REG)
- mono_arch_create_monitor_enter_trampoline (&info, TRUE);
+ mono_arch_create_monitor_enter_trampoline (&info, FALSE, TRUE);
+ emit_trampoline (acfg, acfg->got_offset, info);
+#if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
+ mono_arch_create_monitor_enter_trampoline (&info, TRUE, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
+#endif
mono_arch_create_monitor_exit_trampoline (&info, TRUE);
emit_trampoline (acfg, acfg->got_offset, info);
#endif
if (acfg->aot_opts.write_symbols)
emit_local_symbol (acfg, symbol, end_symbol, TRUE);
- emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+ emit_alignment_code (acfg, AOT_FUNC_ALIGNMENT);
emit_label (acfg, symbol);
acfg->trampoline_got_offset_base [ntype] = tramp_got_offset;
if (str_begins_with (arg, "outfile=")) {
opts->outfile = g_strdup (arg + strlen ("outfile="));
+ } else if (str_begins_with (arg, "llvm-outfile=")) {
+ opts->llvm_outfile = g_strdup (arg + strlen ("llvm-outfile="));
} else if (str_begins_with (arg, "save-temps")) {
opts->save_temps = TRUE;
} else if (str_begins_with (arg, "keep-temps")) {
} else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) {
printf ("Supported options for --aot:\n");
printf (" outfile=\n");
+ printf (" llvm-outfile=\n");
printf (" save-temps\n");
printf (" keep-temps\n");
printf (" write-symbols\n");
guint32
mono_aot_get_got_offset (MonoJumpInfo *ji)
{
- return get_got_offset (llvm_acfg, ji);
+ return get_got_offset (llvm_acfg, TRUE, ji);
}
char*
static gboolean
emit_llvm_file (MonoAotCompile *acfg)
{
- char *command, *opts, *tempbc;
- int i;
- MonoJumpInfo *patch_info;
-
- /*
- * When using LLVM, we let llvm emit the got since the LLVM IL needs to refer
- * to it.
- */
-
- /* Compute the final size of the got */
- for (i = 0; i < acfg->nmethods; ++i) {
- if (acfg->cfgs [i]) {
- for (patch_info = acfg->cfgs [i]->patch_info; patch_info; patch_info = patch_info->next) {
- if (patch_info->type != MONO_PATCH_INFO_NONE) {
- if (!is_plt_patch (patch_info))
- get_got_offset (acfg, patch_info);
- else
- get_plt_entry (acfg, patch_info);
- }
- }
- }
- }
-
- acfg->final_got_size = acfg->got_offset + acfg->plt_offset;
-
- if (acfg->aot_opts.full_aot) {
- int ntype;
-
- /*
- * Need to add the got entries used by the trampolines.
- * This is only a conservative approximation.
- */
- if (strcmp (acfg->image->assembly->aname.name, "mscorlib") == 0) {
- /* For the generic + rgctx trampolines */
- acfg->final_got_size += 400;
- /* For the specific trampolines */
- for (ntype = 0; ntype < MONO_AOT_TRAMP_NUM; ++ntype)
- acfg->final_got_size += acfg->num_trampolines [ntype] * 2;
- }
- }
-
+ char *command, *opts, *tempbc, *output_fname;
tempbc = g_strdup_printf ("%s.bc", acfg->tmpbasename);
- mono_llvm_emit_aot_module (tempbc, g_path_get_basename (acfg->image->name), acfg->final_got_size);
+ mono_llvm_emit_aot_module (tempbc, g_path_get_basename (acfg->image->name));
g_free (tempbc);
/*
/* Verbose asm slows down llc greatly */
g_string_append (acfg->llc_args, " -asm-verbose=false");
+ g_string_append (acfg->llc_args, " -disable-gnu-eh-frame -enable-mono-eh-frame");
+
if (acfg->aot_opts.mtriple)
g_string_append_printf (acfg->llc_args, " -mtriple=%s", acfg->aot_opts.mtriple);
+ if (acfg->llvm_separate)
+ g_string_append_printf (acfg->llc_args, " -mono-eh-frame-symbol=%s", acfg->llvm_eh_frame_symbol);
+
#if defined(TARGET_MACH) && defined(TARGET_ARM)
/* ios requires PIC code now */
g_string_append_printf (acfg->llc_args, " -relocation-model=pic");
#endif
unlink (acfg->tmpfname);
- command = g_strdup_printf ("%sllc %s -disable-gnu-eh-frame -enable-mono-eh-frame -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, acfg->tmpfname, acfg->tmpbasename);
+ if (acfg->llvm_separate) {
+ if (acfg->llvm_owriter) {
+ /* Emit an object file directly */
+ output_fname = g_strdup_printf ("%s", acfg->llvm_ofile);
+ g_string_append_printf (acfg->llc_args, " -filetype=obj");
+ } else {
+ output_fname = g_strdup_printf ("%s", acfg->llvm_sfile);
+ }
+ } else {
+ output_fname = g_strdup (acfg->tmpfname);
+ }
+ command = g_strdup_printf ("%sllc %s -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, output_fname, acfg->tmpbasename);
aot_printf (acfg, "Executing llc: %s\n", command);
* AOT code, so it must be equal to the address of the first emitted method.
*/
emit_section_change (acfg, ".text", 0);
- emit_alignment (acfg, 8);
+ emit_alignment_code (acfg, 8);
if (acfg->llvm) {
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i] && acfg->cfgs [i]->compile_llvm) {
emit_label (acfg, symbol);
acfg->methods_symbol = g_strdup (symbol);
}
+ emit_label (acfg, "jit_code_start");
/*
* Emit some padding so the local symbol for the first method doesn't have the
* same address as 'methods'.
*/
#if defined(__default_codegen__)
- emit_zero_bytes (acfg, 16);
+ emit_padding (acfg, 16);
#elif defined(__native_client_codegen__)
{
const int kPaddingSize = 16;
arch_emit_unbox_trampoline (acfg, cfg, cfg->orig_method, cfg->asm_symbol);
- if (acfg->thumb_mixed && cfg->compile_llvm) {
+ if (acfg->thumb_mixed && cfg->compile_llvm)
emit_set_arm_mode (acfg);
- }
}
if (cfg->compile_llvm)
sprintf (symbol, "methods_end");
emit_section_change (acfg, ".text", 0);
- emit_alignment (acfg, 8);
+ emit_alignment_code (acfg, 8);
emit_label (acfg, symbol);
+
+ emit_label (acfg, "jit_code_end");
+
/* To distinguish it from the next symbol */
- emit_int32 (acfg, 0);
+ emit_padding (acfg, 4);
/*
* Add .no_dead_strip directives for all LLVM methods to prevent the OSX linker
}
}
- if (acfg->direct_method_addresses) {
- acfg->flags |= MONO_AOT_FILE_FLAG_DIRECT_METHOD_ADDRESSES;
-
- /*
- * To work around linker issues, we emit a table of branches, and disassemble them at runtime.
- * This is PIE code, and the linker can update it if needed.
- */
- sprintf (symbol, "method_addresses");
- emit_section_change (acfg, ".text", 1);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
- emit_local_symbol (acfg, symbol, "method_addresses_end", TRUE);
- emit_unset_mode (acfg);
- if (acfg->need_no_dead_strip)
- fprintf (acfg->fp, " .no_dead_strip %s\n", symbol);
+ /*
+ * To work around linker issues, we emit a table of branches, and disassemble them at runtime.
+ * This is PIE code, and the linker can update it if needed.
+ */
+ sprintf (symbol, "method_addresses");
+ emit_section_change (acfg, ".text", 1);
+ emit_alignment_code (acfg, 8);
+ emit_label (acfg, symbol);
+ emit_local_symbol (acfg, symbol, "method_addresses_end", TRUE);
+ emit_unset_mode (acfg);
+ if (acfg->need_no_dead_strip)
+ fprintf (acfg->fp, " .no_dead_strip %s\n", symbol);
- for (i = 0; i < acfg->nmethods; ++i) {
+ for (i = 0; i < acfg->nmethods; ++i) {
#ifdef MONO_ARCH_AOT_SUPPORTED
- int call_size;
+ int call_size;
- if (acfg->cfgs [i])
- arch_emit_direct_call (acfg, acfg->cfgs [i]->asm_symbol, FALSE, acfg->thumb_mixed && acfg->cfgs [i]->compile_llvm, NULL, &call_size);
- else
- arch_emit_direct_call (acfg, "method_addresses", FALSE, FALSE, NULL, &call_size);
+ if (acfg->cfgs [i])
+ arch_emit_direct_call (acfg, acfg->cfgs [i]->asm_symbol, FALSE, acfg->thumb_mixed && acfg->cfgs [i]->compile_llvm, NULL, &call_size);
+ else
+ arch_emit_direct_call (acfg, "method_addresses", FALSE, FALSE, NULL, &call_size);
#endif
- }
-
- sprintf (symbol, "method_addresses_end");
- emit_label (acfg, symbol);
-
- /* Empty */
- sprintf (symbol, "code_offsets");
- emit_section_change (acfg, RODATA_SECT, 1);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
- emit_int32 (acfg, 0);
- } else {
- sprintf (symbol, "code_offsets");
- emit_section_change (acfg, RODATA_SECT, 1);
- emit_alignment (acfg, 8);
- emit_label (acfg, symbol);
-
- acfg->stats.offsets_size += acfg->nmethods * 4;
-
- for (i = 0; i < acfg->nmethods; ++i) {
- if (acfg->cfgs [i]) {
- emit_symbol_diff (acfg, acfg->cfgs [i]->asm_symbol, acfg->methods_symbol, 0);
- } else {
- emit_int32 (acfg, 0xffffffff);
- }
- }
}
+
+ sprintf (symbol, "method_addresses_end");
+ emit_label (acfg, symbol);
emit_line (acfg);
- /* Emit a sorted table mapping methods to their unbox trampolines */
+ /* Emit a sorted table mapping methods to the index of their unbox trampolines */
sprintf (symbol, "unbox_trampolines");
- if (acfg->direct_method_addresses)
- emit_section_change (acfg, ".text", 0);
- else
- emit_section_change (acfg, RODATA_SECT, 0);
+ emit_section_change (acfg, RODATA_SECT, 0);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
method = cfg->orig_method;
if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
-#ifdef MONO_ARCH_AOT_SUPPORTED
- int call_size;
-#endif
-
index = get_method_index (acfg, method);
- sprintf (symbol, "ut_%d", index);
emit_int32 (acfg, index);
- if (acfg->direct_method_addresses) {
-#ifdef MONO_ARCH_AOT_SUPPORTED
- arch_emit_direct_call (acfg, symbol, FALSE, acfg->thumb_mixed && cfg->compile_llvm, NULL, &call_size);
-#endif
- } else {
- emit_symbol_diff (acfg, symbol, acfg->methods_symbol, 0);
- }
/* Make sure the table is sorted by index */
g_assert (index > prev_index);
prev_index = index;
sprintf (symbol, "unbox_trampolines_end");
emit_label (acfg, symbol);
emit_int32 (acfg, 0);
+
+ /* Emit a separate table with the trampoline addresses/offsets */
+ sprintf (symbol, "unbox_trampoline_addresses");
+ emit_section_change (acfg, ".text", 0);
+ emit_alignment_code (acfg, 8);
+ emit_label (acfg, symbol);
+
+ for (i = 0; i < acfg->nmethods; ++i) {
+ MonoCompile *cfg;
+ MonoMethod *method;
+ int index;
+
+ cfg = acfg->cfgs [i];
+ if (!cfg)
+ continue;
+
+ method = cfg->orig_method;
+
+ if (acfg->aot_opts.full_aot && cfg->orig_method->klass->valuetype) {
+#ifdef MONO_ARCH_AOT_SUPPORTED
+ int call_size;
+
+ index = get_method_index (acfg, method);
+ sprintf (symbol, "ut_%d", index);
+
+ arch_emit_direct_call (acfg, symbol, FALSE, acfg->thumb_mixed && cfg->compile_llvm, NULL, &call_size);
+#endif
+ }
+ }
}
static void
}
static void
-emit_got_info (MonoAotCompile *acfg)
+emit_got_info (MonoAotCompile *acfg, gboolean llvm)
{
char symbol [256];
int i, first_plt_got_patch, buf_size;
guint8 *p, *buf;
guint32 *got_info_offsets;
+ GotInfo *info = llvm ? &acfg->llvm_got_info : &acfg->got_info;
/* Add the patches needed by the PLT to the GOT */
- acfg->plt_got_offset_base = acfg->got_offset;
- first_plt_got_patch = acfg->got_patches->len;
- for (i = 1; i < acfg->plt_offset; ++i) {
- MonoPltEntry *plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
+ if (!llvm) {
+ acfg->plt_got_offset_base = acfg->got_offset;
+ first_plt_got_patch = info->got_patches->len;
+ for (i = 1; i < acfg->plt_offset; ++i) {
+ MonoPltEntry *plt_entry = g_hash_table_lookup (acfg->plt_offset_to_entry, GUINT_TO_POINTER (i));
- g_ptr_array_add (acfg->got_patches, plt_entry->ji);
+ g_ptr_array_add (info->got_patches, plt_entry->ji);
- acfg->stats.got_slot_types [plt_entry->ji->type] ++;
- }
+ acfg->stats.got_slot_types [plt_entry->ji->type] ++;
+ }
- acfg->got_offset += acfg->plt_offset;
+ acfg->got_offset += acfg->plt_offset;
+ }
/**
* FIXME:
*/
/* Encode info required to decode shared GOT entries */
- buf_size = acfg->got_patches->len * 128;
+ buf_size = info->got_patches->len * 128;
p = buf = mono_mempool_alloc (acfg->mempool, buf_size);
- got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->got_patches->len * sizeof (guint32));
- acfg->plt_got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->plt_offset * sizeof (guint32));
- /* Unused */
- if (acfg->plt_offset)
- acfg->plt_got_info_offsets [0] = 0;
- for (i = 0; i < acfg->got_patches->len; ++i) {
- MonoJumpInfo *ji = g_ptr_array_index (acfg->got_patches, i);
+ got_info_offsets = mono_mempool_alloc (acfg->mempool, info->got_patches->len * sizeof (guint32));
+ if (!llvm) {
+ acfg->plt_got_info_offsets = mono_mempool_alloc (acfg->mempool, acfg->plt_offset * sizeof (guint32));
+ /* Unused */
+ if (acfg->plt_offset)
+ acfg->plt_got_info_offsets [0] = 0;
+ }
+ for (i = 0; i < info->got_patches->len; ++i) {
+ MonoJumpInfo *ji = g_ptr_array_index (info->got_patches, i);
guint8 *p2;
p = buf;
g_assert (p - buf <= buf_size);
got_info_offsets [i] = add_to_blob (acfg, buf, p - buf);
- if (i >= first_plt_got_patch)
+ if (!llvm && i >= first_plt_got_patch)
acfg->plt_got_info_offsets [i - first_plt_got_patch + 1] = got_info_offsets [i];
acfg->stats.got_info_size += p - buf;
}
/* Emit got_info_offsets table */
- sprintf (symbol, "got_info_offsets");
+ if (llvm)
+ sprintf (symbol, "llvm_got_info_offsets");
+ else
+ sprintf (symbol, "got_info_offsets");
emit_section_change (acfg, RODATA_SECT, 1);
emit_alignment (acfg, 8);
emit_label (acfg, symbol);
/* No need to emit offsets for the got plt entries, the plt embeds them directly */
- acfg->stats.offsets_size += emit_offset_table (acfg, first_plt_got_patch, 10, (gint32*)got_info_offsets);
+ acfg->stats.offsets_size += emit_offset_table (acfg, llvm ? acfg->llvm_got_offset : first_plt_got_patch, 10, (gint32*)got_info_offsets);
}
static void
{
char symbol [256];
- if (!acfg->llvm) {
- /* Don't make GOT global so accesses to it don't need relocations */
- sprintf (symbol, "%s", acfg->got_symbol);
- emit_section_change (acfg, ".bss", 0);
- emit_alignment (acfg, 8);
- emit_local_symbol (acfg, symbol, "got_end", FALSE);
- emit_label (acfg, symbol);
- if (acfg->got_offset > 0)
- emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
+ /* Don't make GOT global so accesses to it don't need relocations */
+ sprintf (symbol, "%s", acfg->got_symbol);
+ emit_section_change (acfg, ".bss", 0);
+ emit_alignment (acfg, 8);
+ emit_local_symbol (acfg, symbol, "got_end", FALSE);
+ emit_label (acfg, symbol);
+ if (acfg->got_offset > 0)
+ emit_zero_bytes (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
- sprintf (symbol, "got_end");
- emit_label (acfg, symbol);
- }
+ sprintf (symbol, "got_end");
+ emit_label (acfg, symbol);
}
typedef struct GlobalsTableEntry {
int i, table_size;
guint32 hash;
GPtrArray *table;
- char symbol [256];
+ char symbol [1024];
GlobalsTableEntry *entry, *new_entry;
if (!acfg->aot_opts.static_link)
sprintf (symbol, "name_%d", i);
emit_pointer (acfg, symbol);
+ g_assert (strlen (name) < sizeof (symbol));
sprintf (symbol, "%s", name);
emit_pointer (acfg, symbol);
}
sprintf (symbol, "mem_end");
emit_section_change (acfg, ".text", 1);
- emit_alignment (acfg, 8);
+ emit_alignment_code (acfg, 8);
emit_label (acfg, symbol);
}
* various problems (i.e. arm/thumb).
*/
emit_pointer (acfg, acfg->got_symbol);
+ if (acfg->llvm)
+ emit_pointer (acfg, acfg->llvm_got_symbol);
+ else
+ emit_pointer (acfg, NULL);
emit_pointer (acfg, acfg->methods_symbol);
+ emit_pointer (acfg, "jit_code_start");
+ emit_pointer (acfg, "jit_code_end");
if (acfg->llvm) {
/*
* Emit a reference to the mono_eh_frame table created by our modified LLVM compiler.
*/
- emit_pointer (acfg, "mono_eh_frame");
+ emit_pointer (acfg, acfg->llvm_eh_frame_symbol);
} else {
emit_pointer (acfg, NULL);
}
emit_pointer (acfg, "class_info_offsets");
emit_pointer (acfg, "method_info_offsets");
emit_pointer (acfg, "ex_info_offsets");
- emit_pointer (acfg, "code_offsets");
- if (acfg->direct_method_addresses)
- emit_pointer (acfg, "method_addresses");
- else
- emit_pointer (acfg, NULL);
+ emit_pointer (acfg, "method_addresses");
emit_pointer (acfg, "extra_method_info_offsets");
emit_pointer (acfg, "extra_method_table");
emit_pointer (acfg, "got_info_offsets");
+ if (acfg->llvm)
+ emit_pointer (acfg, "llvm_got_info_offsets");
+ else
+ emit_pointer (acfg, NULL);
emit_pointer (acfg, "methods_end");
emit_pointer (acfg, "unwind_info");
emit_pointer (acfg, "mem_end");
emit_pointer (acfg, "assembly_name");
emit_pointer (acfg, "unbox_trampolines");
emit_pointer (acfg, "unbox_trampolines_end");
+ emit_pointer (acfg, "unbox_trampoline_addresses");
emit_int32 (acfg, acfg->plt_got_offset_base);
emit_int32 (acfg, (int)(acfg->got_offset * sizeof (gpointer)));
compile_asm (MonoAotCompile *acfg)
{
char *command, *objfile;
- char *outfile_name, *tmp_outfile_name;
+ char *outfile_name, *tmp_outfile_name, *llvm_ofile;
const char *tool_prefix = acfg->aot_opts.tool_prefix ? acfg->aot_opts.tool_prefix : "";
#if defined(TARGET_AMD64) && !defined(TARGET_MACH)
aot_printf (acfg, "Output file: '%s'.\n", acfg->tmpfname);
if (acfg->aot_opts.static_link)
aot_printf (acfg, "Linking symbol: '%s'.\n", acfg->static_linking_symbol);
+ if (acfg->llvm_separate)
+ aot_printf (acfg, "LLVM output file: '%s'.\n", acfg->llvm_sfile);
return 0;
}
return 1;
}
+ if (acfg->llvm_separate && !acfg->llvm_owriter) {
+ command = g_strdup_printf ("%s%s %s %s -o %s %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->as_args ? acfg->as_args->str : "", acfg->llvm_ofile, acfg->llvm_sfile);
+ aot_printf (acfg, "Executing the native assembler: %s\n", command);
+ if (system (command) != 0) {
+ g_free (command);
+ g_free (objfile);
+ return 1;
+ }
+ }
+
g_free (command);
if (acfg->aot_opts.static_link) {
tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
+ if (acfg->llvm_separate) {
+ llvm_ofile = g_strdup (acfg->llvm_ofile);
+ } else {
+ llvm_ofile = g_strdup ("");
+ }
+
#ifdef LD_NAME
- command = g_strdup_printf ("%s -o %s %s.o", LD_NAME, tmp_outfile_name, acfg->tmpfname);
+ command = g_strdup_printf ("%s -o %s %s %s.o", LD_NAME, tmp_outfile_name, llvm_ofile, acfg->tmpfname);
#else
- command = g_strdup_printf ("%sld %s -shared -o %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, acfg->tmpfname);
+ command = g_strdup_printf ("%sld %s -shared -o %s %s %s.o", tool_prefix, LD_OPTIONS, tmp_outfile_name, llvm_ofile, acfg->tmpfname);
#endif
aot_printf (acfg, "Executing the native linker: %s\n", command);
if (system (command) != 0) {
return 0;
}
+static void init_got_info (GotInfo *info)
+{
+ int i;
+
+ info->patch_to_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
+ info->patch_to_got_offset_by_type = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM);
+ for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
+ info->patch_to_got_offset_by_type [i] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
+ info->got_patches = g_ptr_array_new ();
+}
+
static MonoAotCompile*
acfg_create (MonoAssembly *ass, guint32 opts)
{
MonoImage *image = ass->image;
MonoAotCompile *acfg;
- int i;
acfg = g_new0 (MonoAotCompile, 1);
acfg->methods = g_ptr_array_new ();
acfg->method_depth = g_hash_table_new (NULL, NULL);
acfg->plt_offset_to_entry = g_hash_table_new (NULL, NULL);
acfg->patch_to_plt_entry = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM);
- acfg->patch_to_got_offset = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
- acfg->patch_to_got_offset_by_type = g_new0 (GHashTable*, MONO_PATCH_INFO_NUM);
- for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
- acfg->patch_to_got_offset_by_type [i] = g_hash_table_new (mono_patch_info_hash, mono_patch_info_equal);
- acfg->got_patches = g_ptr_array_new ();
acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
acfg->token_info_hash = g_hash_table_new_full (NULL, NULL, NULL, NULL);
acfg->method_to_pinvoke_import = g_hash_table_new_full (NULL, NULL, NULL, g_free);
acfg->plt_entry_debug_sym_cache = g_hash_table_new (g_str_hash, g_str_equal);
mono_mutex_init_recursive (&acfg->mutex);
+ init_got_info (&acfg->got_info);
+ init_got_info (&acfg->llvm_got_info);
+
return acfg;
}
+static void
+got_info_free (GotInfo *info)
+{
+ int i;
+
+ for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
+ g_hash_table_destroy (info->patch_to_got_offset_by_type [i]);
+ g_free (info->patch_to_got_offset_by_type);
+ g_hash_table_destroy (info->patch_to_got_offset);
+ g_ptr_array_free (info->got_patches, TRUE);
+}
+
static void
acfg_free (MonoAotCompile *acfg)
{
g_free (acfg->got_symbol);
g_free (acfg->plt_symbol);
g_ptr_array_free (acfg->methods, TRUE);
- g_ptr_array_free (acfg->got_patches, TRUE);
g_ptr_array_free (acfg->image_table, TRUE);
g_ptr_array_free (acfg->globals, TRUE);
g_ptr_array_free (acfg->unwind_ops, TRUE);
g_hash_table_destroy (acfg->patch_to_plt_entry [i]);
}
g_free (acfg->patch_to_plt_entry);
- g_hash_table_destroy (acfg->patch_to_got_offset);
g_hash_table_destroy (acfg->method_to_cfg);
g_hash_table_destroy (acfg->token_info_hash);
g_hash_table_destroy (acfg->method_to_pinvoke_import);
g_hash_table_destroy (acfg->plt_entry_debug_sym_cache);
g_hash_table_destroy (acfg->klass_blob_hash);
g_hash_table_destroy (acfg->method_blob_hash);
- for (i = 0; i < MONO_PATCH_INFO_NUM; ++i)
- g_hash_table_destroy (acfg->patch_to_got_offset_by_type [i]);
- g_free (acfg->patch_to_got_offset_by_type);
+ got_info_free (&acfg->got_info);
+ got_info_free (&acfg->llvm_got_info);
mono_mempool_destroy (acfg->mempool);
g_free (acfg);
}
}
mini_llvm_init ();
+
+ if (!acfg->aot_opts.asm_only || acfg->aot_opts.llvm_outfile) {
+ /*
+ * Emit all LLVM code into a separate assembly/object file and link with it
+ * normally.
+ */
+#if LLVM_API_VERSION >= 3
+ acfg->llvm_separate = TRUE;
+ if (!acfg->aot_opts.asm_only)
+ acfg->llvm_owriter = TRUE;
+#endif
+ }
+ if (acfg->aot_opts.llvm_outfile && !acfg->llvm_separate) {
+ aot_printerrf (acfg, "The llvm-outputfile= option is not supported on this platform.\n");
+ return 1;
+ }
}
if (acfg->aot_opts.full_aot)
arch_init (acfg);
- acfg->got_symbol_base = g_strdup_printf ("mono_aot_%s_got", acfg->image->assembly->aname.name);
- acfg->plt_symbol = g_strdup_printf ("%smono_aot_%s_plt", acfg->llvm_label_prefix, acfg->image->assembly->aname.name);
acfg->assembly_name_sym = g_strdup (acfg->image->assembly->aname.name);
-
/* Get rid of characters which cannot occur in symbols */
- for (p = acfg->got_symbol_base; *p; ++p) {
- if (!(isalnum (*p) || *p == '_'))
- *p = '_';
- }
- for (p = acfg->plt_symbol; *p; ++p) {
- if (!(isalnum (*p) || *p == '_'))
- *p = '_';
- }
for (p = acfg->assembly_name_sym; *p; ++p) {
if (!(isalnum (*p) || *p == '_'))
*p = '_';
}
+ acfg->got_symbol_base = g_strdup_printf ("mono_aot_%s_got", acfg->assembly_name_sym);
+ acfg->llvm_got_symbol_base = g_strdup_printf ("mono_aot_%s_llvm_got", acfg->assembly_name_sym);
+ acfg->plt_symbol = g_strdup_printf ("%smono_aot_%s_plt", acfg->llvm_label_prefix, acfg->assembly_name_sym);
+
+ acfg->got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->got_symbol_base);
+ if (acfg->llvm) {
+ acfg->llvm_got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->llvm_got_symbol_base);
+ if (acfg->llvm_separate)
+ acfg->llvm_eh_frame_symbol = g_strdup_printf ("mono_aot_%s_eh_frame", acfg->assembly_name_sym);
+ else
+ acfg->llvm_eh_frame_symbol = g_strdup ("mono_eh_frame");
+ }
+
acfg->method_index = 1;
// FIXME:
#ifdef ENABLE_LLVM
if (acfg->llvm) {
llvm_acfg = acfg;
- mono_llvm_create_aot_module (acfg->got_symbol_base);
+ mono_llvm_create_aot_module (acfg->llvm_got_symbol_base, acfg->llvm_separate, acfg->llvm_separate);
}
#endif
ji->type = MONO_PATCH_INFO_IMAGE;
ji->data.image = acfg->image;
- get_got_offset (acfg, ji);
+ get_got_offset (acfg, FALSE, ji);
+ get_got_offset (acfg, TRUE, ji);
/* Slot 1 is reserved for the mscorlib got addr */
ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
ji->type = MONO_PATCH_INFO_MSCORLIB_GOT_ADDR;
- get_got_offset (acfg, ji);
+ get_got_offset (acfg, FALSE, ji);
+ get_got_offset (acfg, TRUE, ji);
/* This is very common */
ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
ji->type = MONO_PATCH_INFO_GC_CARD_TABLE_ADDR;
- get_got_offset (acfg, ji);
+ get_got_offset (acfg, FALSE, ji);
+ get_got_offset (acfg, TRUE, ji);
ji = mono_mempool_alloc0 (acfg->mempool, sizeof (MonoAotCompile));
ji->type = MONO_PATCH_INFO_JIT_TLS_ID;
- get_got_offset (acfg, ji);
+ get_got_offset (acfg, FALSE, ji);
+ get_got_offset (acfg, TRUE, ji);
}
TV_GETTIME (atv);
acfg->tmpbasename = g_strdup_printf ("%s", acfg->image->name);
acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
}
+ if (acfg->llvm_separate) {
+ g_assert (acfg->aot_opts.llvm_outfile);
+ acfg->llvm_sfile = g_strdup (acfg->aot_opts.llvm_outfile);
+ }
} else {
acfg->tmpbasename = g_strdup_printf ("%s", "temp");
acfg->tmpfname = g_strdup_printf ("%s.s", acfg->tmpbasename);
+ acfg->llvm_sfile = g_strdup ("temp-llvm.s");
+ acfg->llvm_ofile = g_strdup ("temp-llvm.o");
}
res = emit_llvm_file (acfg);
acfg->w = img_writer_create (acfg->fp, TRUE);
acfg->use_bin_writer = TRUE;
} else {
- if (acfg->llvm) {
+ if (acfg->llvm && !acfg->llvm_separate) {
/* Append to the .s file created by llvm */
/* FIXME: Use multiple files instead */
acfg->fp = fopen (acfg->tmpfname, "a+");
outfile_name = NULL;
}
- acfg->got_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, acfg->got_symbol_base);
-
/* Compute symbols for methods */
for (i = 0; i < acfg->nmethods; ++i) {
if (acfg->cfgs [i]) {
if (COMPILE_LLVM (cfg))
cfg->asm_symbol = g_strdup_printf ("%s%s", acfg->llvm_label_prefix, cfg->llvm_method_name);
- else if (acfg->global_symbols)
- cfg->asm_symbol = get_debug_sym (cfg->method, "", acfg->method_label_hash);
+ else if (acfg->global_symbols || acfg->llvm_separate)
+ cfg->asm_symbol = get_debug_sym (cfg->orig_method, "", acfg->method_label_hash);
else
cfg->asm_symbol = g_strdup_printf ("%s%sm_%x", acfg->temp_prefix, acfg->llvm_label_prefix, method_index);
}
*/
sprintf (symbol, "thumb_end");
emit_section_change (acfg, ".text", 0);
- emit_alignment (acfg, 8);
+ emit_alignment_code (acfg, 8);
emit_label (acfg, symbol);
emit_zero_bytes (acfg, 16);
emit_class_name_table (acfg);
- emit_got_info (acfg);
+ emit_got_info (acfg, FALSE);
+ if (acfg->llvm)
+ emit_got_info (acfg, TRUE);
emit_exception_info (acfg);
acfg->stats.gen_time = TV_ELAPSED (atv, btv);
- if (acfg->llvm)
- g_assert (acfg->got_offset <= acfg->final_got_size);
-
if (acfg->llvm)
sprintf (llvm_stats_msg, ", LLVM: %d (%d%%)", acfg->stats.llvm_count, acfg->stats.mcount ? (acfg->stats.llvm_count * 100) / acfg->stats.mcount : 100);
else