X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Ftramp-arm.c;h=5711ef1f180ddc800105fa07612a4de5a281876d;hb=46733c1a6700a7158cea01bd6c38dc05ac9d1cbb;hp=4e18e5655a46201179f2bb9b02df87fc5603fde0;hpb=5b558abeeb255a3179d4ca6a85617e051c6abd38;p=mono.git diff --git a/mono/mini/tramp-arm.c b/mono/mini/tramp-arm.c index 4e18e5655a4..5711ef1f180 100644 --- a/mono/mini/tramp-arm.c +++ b/mono/mini/tramp-arm.c @@ -4,7 +4,9 @@ * Authors: * Paolo Molaro (lupus@ximian.com) * - * (C) 2001 Ximian, Inc. + * (C) 2001-2003 Ximian, Inc. + * Copyright 2003-2011 Novell Inc + * Copyright 2011 Xamarin Inc */ #include @@ -18,6 +20,8 @@ #include "mini.h" #include "mini-arm.h" +#define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1)) + static guint8* nullified_class_init_trampoline; void @@ -127,7 +131,7 @@ emit_bx (guint8* code, int reg) /* Stack size for trampoline function */ -#define STACK (sizeof (MonoLMF)) +#define STACK ALIGN_TO (sizeof (MonoLMF), 8) /* Method-specific trampoline code fragment size */ #define METHOD_TRAMPOLINE_SIZE 64 @@ -141,7 +145,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf guint8 *buf, *code = NULL; guint8 *load_get_lmf_addr, *load_trampoline; gpointer *constants; - int cfa_offset; + int cfa_offset, lmf_offset, regsave_size, lr_offset; GSList *unwind_ops = NULL; MonoJumpInfo *ji = NULL; int buf_len; @@ -157,18 +161,23 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf * regs on the stack (all but PC and SP). The original LR value has been * saved as sp + LR_OFFSET by the push in the specific trampoline */ -#define LR_OFFSET (sizeof (gpointer) * 13) + + /* The offset of lmf inside the stack frame */ + lmf_offset = STACK - sizeof (MonoLMF); + /* The size of the area already allocated by the push in the specific trampoline */ + regsave_size = 14 * sizeof (mgreg_t); + /* The offset where lr was saved inside the regsave area */ + lr_offset = 13 * sizeof (mgreg_t); // FIXME: Finish the unwind info, the current info allows us to unwind // when the trampoline is not in the epilog // CFA = SP + (num registers pushed) * 4 - cfa_offset = 14 * sizeof (gpointer); + cfa_offset = 14 * sizeof (mgreg_t); mono_add_unwind_op_def_cfa (unwind_ops, code, buf, ARMREG_SP, cfa_offset); // PC saved at sp+LR_OFFSET mono_add_unwind_op_offset (unwind_ops, code, buf, ARMREG_LR, -4); - ARM_MOV_REG_REG (code, ARMREG_V1, ARMREG_SP); if (aot && tramp_type != MONO_TRAMPOLINE_GENERIC_CLASS_INIT) { /* * The trampoline contains a pc-relative offset to the got slot @@ -184,7 +193,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf else ARM_MOV_REG_REG (code, ARMREG_V2, MONO_ARCH_VTABLE_REG); } - ARM_LDR_IMM (code, ARMREG_V3, ARMREG_SP, LR_OFFSET); + ARM_LDR_IMM (code, ARMREG_V3, ARMREG_SP, lr_offset); /* ok, now we can continue with the MonoLMF setup, mostly untouched * from emit_prolog in mini-arm.c @@ -208,42 +217,52 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf * The pointer to the struct is put in r1. * the iregs array is already allocated on the stack by push. */ - ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, sizeof (MonoLMF) - sizeof (guint) * 14); - cfa_offset += sizeof (MonoLMF) - sizeof (guint) * 14; + ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, STACK - regsave_size); + cfa_offset += STACK - regsave_size; mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset); - ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_SP, STACK - sizeof (MonoLMF)); + /* V1 == lmf */ + ARM_ADD_REG_IMM8 (code, ARMREG_V1, ARMREG_SP, STACK - sizeof (MonoLMF)); + + /* + * The stack now looks like: + * + * v1 -> + * sp -> + */ + /* r0 is the result from mono_get_lmf_addr () */ - ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, lmf_addr)); + ARM_STR_IMM (code, ARMREG_R0, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, lmf_addr)); /* new_lmf->previous_lmf = *lmf_addr */ ARM_LDR_IMM (code, ARMREG_R2, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf)); - ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf)); + ARM_STR_IMM (code, ARMREG_R2, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, previous_lmf)); /* *(lmf_addr) = r1 */ - ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf)); + ARM_STR_IMM (code, ARMREG_V1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf)); /* save method info (it's in v2) */ if ((tramp_type == MONO_TRAMPOLINE_JIT) || (tramp_type == MONO_TRAMPOLINE_JUMP)) - ARM_STR_IMM (code, ARMREG_V2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, method)); + ARM_STR_IMM (code, ARMREG_V2, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, method)); else { ARM_MOV_REG_IMM8 (code, ARMREG_R2, 0); - ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, method)); + ARM_STR_IMM (code, ARMREG_R2, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, method)); } - /* Save sp into lmf->iregs, the eh code expects it to be at IP */ + /* save caller SP */ ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, cfa_offset); - ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, iregs) + (ARMREG_IP * 4)); - ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, esp)); + ARM_STR_IMM (code, ARMREG_R2, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, sp)); + /* save caller FP */ + ARM_LDR_IMM (code, ARMREG_R2, ARMREG_V1, (G_STRUCT_OFFSET (MonoLMF, iregs) + ARMREG_FP*4)); + ARM_STR_IMM (code, ARMREG_R2, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, fp)); /* save the IP (caller ip) */ if (tramp_type == MONO_TRAMPOLINE_JUMP) { ARM_MOV_REG_IMM8 (code, ARMREG_R2, 0); } else { - /* assumes STACK == sizeof (MonoLMF) */ - ARM_LDR_IMM (code, ARMREG_R2, ARMREG_SP, (G_STRUCT_OFFSET (MonoLMF, iregs) + 13*4)); + ARM_LDR_IMM (code, ARMREG_R2, ARMREG_V1, (G_STRUCT_OFFSET (MonoLMF, iregs) + 13*4)); } - ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip)); + ARM_STR_IMM (code, ARMREG_R2, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, ip)); /* * Now we're ready to call xxx_trampoline (). */ - /* Arg 1: the saved registers. It was put in v1 */ - ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_V1); + /* Arg 1: the saved registers */ + ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, iregs)); /* Arg 2: code (next address to the instruction that called us) */ if (tramp_type == MONO_TRAMPOLINE_JUMP) { @@ -271,13 +290,13 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); code = emit_bx (code, ARMREG_IP); - + /* OK, code address is now on r0. Move it to the place on the stack * where IP was saved (it is now no more useful to us and it can be * clobbered). This way we can just restore all the regs in one inst * and branch to IP. */ - ARM_STR_IMM (code, ARMREG_R0, ARMREG_V1, (ARMREG_R12 * 4)); + ARM_STR_IMM (code, ARMREG_R0, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, iregs) + (ARMREG_R12 * sizeof (mgreg_t))); /* Check for thread interruption */ /* This is not perf critical code so no need to check the interrupt flag */ @@ -304,13 +323,11 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf * Now we restore the MonoLMF (see emit_epilogue in mini-arm.c) * and the rest of the registers, so the method called will see * the same state as before we executed. - * The pointer to MonoLMF is in r2. */ - ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_SP); /* ip = previous_lmf */ - ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, previous_lmf)); + ARM_LDR_IMM (code, ARMREG_IP, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, previous_lmf)); /* lr = lmf_addr */ - ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, lmf_addr)); + ARM_LDR_IMM (code, ARMREG_LR, ARMREG_V1, G_STRUCT_OFFSET (MonoLMF, lmf_addr)); /* *(lmf_addr) = previous_lmf */ ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf)); @@ -320,12 +337,11 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Restore the registers and jump to the code: * Note that IP has been conveniently set to the method addr. */ - ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, sizeof (MonoLMF) - sizeof (guint) * 14); + ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, STACK - regsave_size); ARM_POP_NWB (code, 0x5fff); if (tramp_type == MONO_TRAMPOLINE_RGCTX_LAZY_FETCH) ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_IP); - /* do we need to set sp? */ - ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, (14 * 4)); + ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, regsave_size); if ((tramp_type == MONO_TRAMPOLINE_CLASS_INIT) || (tramp_type == MONO_TRAMPOLINE_GENERIC_CLASS_INIT) || (tramp_type == MONO_TRAMPOLINE_RGCTX_LAZY_FETCH)) code = emit_bx (code, ARMREG_LR); else @@ -389,7 +405,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty mono_domain_lock (domain); code = buf = mono_domain_code_reserve_align (domain, size, 4); - if ((short_branch = branch_for_target_reachable (code + 8, tramp))) { + if ((short_branch = branch_for_target_reachable (code + 4, tramp))) { size = 12; mono_domain_code_commit (domain, code, SPEC_TRAMP_SIZE, size); } @@ -760,7 +776,7 @@ mono_arm_get_thumb_plt_entry (guint8 *code) t1 = ((guint16*)bl) [0]; t2 = ((guint16*)bl) [1]; - g_assert ((t1 >> 11) == 0b11110); + g_assert ((t1 >> 11) == 0x1e); s = (t1 >> 10) & 0x1; imm10 = (t1 >> 0) & 0x3ff;