X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Farm%2Fmd.c;h=e4549a1b7a67bfd8eb8bc8c305adf67c5e63b658;hb=47c66292ef4ef12d5f0ff597dc078d346d942892;hp=b150f1a14831499f59267ff14222b67708e1627d;hpb=bbc14f3688db91816c8112c1a899c9a44c7305af;p=cacao.git diff --git a/src/vm/jit/arm/md.c b/src/vm/jit/arm/md.c index b150f1a14..e4549a1b7 100644 --- a/src/vm/jit/arm/md.c +++ b/src/vm/jit/arm/md.c @@ -28,6 +28,7 @@ #include #include +#include "vm/jit/arm/codegen.h" #include "vm/jit/arm/md.h" #include "vm/jit/arm/md-abi.h" @@ -59,10 +60,18 @@ void md_init(void) or e590b000 ldr fp, [r0] - e59bc000 ldr ip, [fp] + e59bc004 ldr ip, [fp, #4] e1a0e00f mov lr, pc e1a0f00c mov pc, ip + or + + e590b000 ldr fp, [r0] + e28bca01 add ip, fp, #4096 ; 0x1000 + e59cc004 ldr ip, [ip, #4] + e1a0e00f mov lr, pc + e1a0f00c mov pc, ip + How we find out the patching address to store new method pointer: - loaded IP with LDR IP,[METHODPTR]? yes=INVOKEVIRTUAL or INVOKEINTERFACE (things are easy!) @@ -76,7 +85,7 @@ void *md_jit_method_patch_address(void *pv, void *ra, void *mptr) { uint32_t *pc; uint32_t mcode; - int32_t offset; + int32_t disp; void *pa; /* patch address */ /* Go back to the actual load instruction. */ @@ -87,22 +96,39 @@ void *md_jit_method_patch_address(void *pv, void *ra, void *mptr) mcode = pc[0]; - /* sanity check: are we inside jit code? */ + /* Sanity check: Are we inside jit code? */ assert(pc[1] == 0xe1a0e00f /*MOV LR,PC*/); assert(pc[2] == 0xe1a0f00c /*MOV PC,IP*/); - /* get the load instruction and offset */ - - offset = (int32_t) (mcode & 0x0fff); + /* Sanity check: We unconditionally loaded a word into REG_PV? */ assert ((mcode & 0xff70f000) == 0xe510c000); - if ((mcode & 0x000f0000) == 0x000b0000) { - /* sanity check: offset was positive */ + /* Get load displacement. */ + + disp = (int32_t) (mcode & 0x0fff); + + /* Case: We loaded from base REG_PV with negative displacement. */ + + if (M_MEM_GET_Rbase(mcode) == REG_PV && (mcode & 0x00800000) == 0) { + /* We loaded from data segment, displacement can be larger. */ + + mcode = pc[-1]; + + /* check for "SUB IP, IP, #??, ROTL 12" */ + + if ((mcode & 0xffffff00) == 0xe24cca00) + disp += (int32_t) ((mcode & 0x00ff) << 12); + + /* and get the final data segment address */ + + pa = ((uint8_t *) pv) - disp; + } - assert((mcode & 0x00800000) == 0x00800000); + /* Case: We loaded from base REG_METHODPTR with positive displacement. */ + else if (M_MEM_GET_Rbase(mcode) == REG_METHODPTR && (mcode & 0x00800000) == 0x00800000) { /* return NULL if no mptr was specified (used for replacement) */ if (mptr == NULL) @@ -110,26 +136,57 @@ void *md_jit_method_patch_address(void *pv, void *ra, void *mptr) /* we loaded from REG_METHODPTR */ - pa = ((uint8_t *) mptr) + offset; + pa = ((uint8_t *) mptr) + disp; } - else { - /* sanity check: we loaded from REG_IP; offset was negative or zero */ - assert((mcode & 0x008f0000) == 0x000c0000 || - (mcode & 0x008f0fff) == 0x008c0000); + /* Case: We loaded from base REG_PV with positive offset. */ - /* we loaded from data segment; offset can be larger */ + else if (M_MEM_GET_Rbase(mcode) == REG_PV && (mcode & 0x00800000) == 0x00800000) { + /* We loaded with a larger displacement. Normally this means we loaded + from REG_METHODPTR. However there is a corner case if we loaded + from the data segment at an address aligned to 12 bit, which leads to a + zero (positive) displacement for the last instruction. */ mcode = pc[-1]; - /* check for "SUB IP, IP, #??, ROTL 12" */ + /* check for "ADD IP, FP, #??, ROTL 12" */ - if ((mcode & 0xffffff00) == 0xe24cca00) - offset += (int32_t) ((mcode & 0x00ff) << 12); + if ((mcode & 0xffffff00) == 0xe28bca00) { + /* We loaded from REG_METHODPTR with a larger displacement. */ - /* and get the final data segment address */ + assert(mptr != NULL); + disp += (int32_t) ((mcode & 0x00ff) << 12); + pa = ((uint8_t *) mptr) + disp; + } + + /* check for "SUB IP, IP, #??, ROTL 12" (corner case) */ + + else if ((mcode & 0xffffff00) == 0xe24cca00 && disp == 0) { + /* We loaded from data segment with a larger displacement aligned to 12 bit. */ + + disp += (int32_t) ((mcode & 0x00ff) << 12); + pa = ((uint8_t *) pv) - disp; + } + + /* Case is not covered, something is severely wrong. */ + + else { + vm_abort_disassemble(pc - 1, 4, "md_jit_method_patch_address: unknown instruction %x", mcode); + + /* Keep compiler happy. */ + + pa = NULL; + } + } + + /* Case is not covered, something is severely wrong. */ + + else { + vm_abort_disassemble(pc, 3, "md_jit_method_patch_address: unknown instruction %x", mcode); + + /* Keep compiler happy. */ - pa = ((uint8_t *) pv) - offset; + pa = NULL; } return pa;