wingo pushed a commit to branch master in repository guile. commit 11b9d3744e963a121270712199bbfa7edb70d245 Author: Icecream95 <i...@keemail.me> AuthorDate: Thu Apr 9 22:10:15 2020 +1200
Always emit veneers for non-bl jumps to ARM code It is unlikely for any ARM code to be close enough to not have needed a veneer, but it is possible, especially if running in a program with another JIT library. --- lightening/aarch64.c | 4 ++-- lightening/arm-cpu.c | 26 ++++++++++++++++++-------- lightening/lightening.c | 9 +++++---- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/lightening/aarch64.c b/lightening/aarch64.c index b605cc5..2b3ed4d 100644 --- a/lightening/aarch64.c +++ b/lightening/aarch64.c @@ -90,9 +90,9 @@ DEFINE_ENCODER(size, 2, 22, unsigned, uint32_t) { \ return read_signed_bitfield(*loc, kind##_width, kind##_shift); \ } \ - static int offset_in_##name##_range(ptrdiff_t diff) maybe_unused; \ + static int offset_in_##name##_range(ptrdiff_t diff, int flags) maybe_unused; \ static int \ - offset_in_##name##_range(ptrdiff_t diff) \ + offset_in_##name##_range(ptrdiff_t diff, int flags) \ { \ return in_signed_range(diff, kind##_width); \ } \ diff --git a/lightening/arm-cpu.c b/lightening/arm-cpu.c index 192c705..1bb7394 100644 --- a/lightening/arm-cpu.c +++ b/lightening/arm-cpu.c @@ -186,6 +186,8 @@ #define _NOREG (jit_gpr_regno(_PC)) +#define JIT_RELOC_B JIT_RELOC_FLAG_0 + static void emit_wide_thumb(jit_state_t *_jit, uint32_t inst) { @@ -265,9 +267,12 @@ write_wide_thumb(uint32_t *loc, uint32_t v) } static int -offset_in_jmp_range(int32_t offset) +offset_in_jmp_range(int32_t offset, int flags) { - return -0x1000000 <= offset && offset <= 0xffffff; + if (!(offset & 1) && flags | JIT_RELOC_B) + return 0; + else + return -0x1000000 <= offset && offset <= 0xffffff; } static int32_t @@ -295,7 +300,7 @@ static const uint32_t thumb_jump_mask = 0xf800d000; static uint32_t encode_thumb_jump(int32_t v) { - ASSERT(offset_in_jmp_range(v)); + ASSERT(offset_in_jmp_range(v, 0)); v >>= 1; uint32_t s = !!(v & 0x800000); uint32_t i1 = !!(v & 0x400000); @@ -339,8 +344,10 @@ emit_thumb_jump(jit_state_t *_jit, uint32_t inst) while (1) { uint8_t *pc_base = _jit->pc.uc + 4; int32_t off = (uint8_t*)jit_address(_jit) - pc_base; - jit_reloc_t ret = - jit_reloc (_jit, JIT_RELOC_JMP_WITH_VENEER, 0, _jit->pc.uc, pc_base, 0); + enum jit_reloc_kind kind = JIT_RELOC_JMP_WITH_VENEER; + if (inst == THUMB2_B) + kind |= JIT_RELOC_B; + jit_reloc_t ret = jit_reloc (_jit, kind, 0, _jit->pc.uc, pc_base, 0); uint8_t thumb_jump_width = 24; if (add_pending_literal(_jit, ret, thumb_jump_width - 1)) { emit_wide_thumb(_jit, patch_thumb_jump(inst, off)); @@ -350,9 +357,12 @@ emit_thumb_jump(jit_state_t *_jit, uint32_t inst) } static int -offset_in_jcc_range(int32_t v) +offset_in_jcc_range(int32_t v, int flags) { - return -0x100000 <= v && v <= 0xfffff; + if (!(v & 1)) + return 0; + else + return -0x100000 <= v && v <= 0xfffff; } static int32_t @@ -378,7 +388,7 @@ static const uint32_t thumb_cc_jump_mask = 0xfbc0d000; static uint32_t encode_thumb_cc_jump(int32_t v) { - ASSERT(offset_in_jcc_range(v)); + ASSERT(offset_in_jcc_range(v, 0)); v >>= 1; uint32_t s = !!(v & 0x80000); uint32_t j2 = !!(v & 0x40000); diff --git a/lightening/lightening.c b/lightening/lightening.c index 92e40c4..6620788 100644 --- a/lightening/lightening.c +++ b/lightening/lightening.c @@ -105,11 +105,11 @@ enum guard_pool { GUARD_NEEDED, NO_GUARD_NEEDED }; static void emit_literal_pool(jit_state_t *_jit, enum guard_pool guard); static int32_t read_jmp_offset(uint32_t *loc); -static int offset_in_jmp_range(ptrdiff_t offset); +static int offset_in_jmp_range(ptrdiff_t offset, int flags); static void patch_jmp_offset(uint32_t *loc, ptrdiff_t offset); static void patch_veneer_jmp_offset(uint32_t *loc, ptrdiff_t offset); static int32_t read_jcc_offset(uint32_t *loc); -static int offset_in_jcc_range(ptrdiff_t offset); +static int offset_in_jcc_range(ptrdiff_t offset, int flags); static void patch_jcc_offset(uint32_t *loc, ptrdiff_t offset); static void patch_veneer_jcc_offset(uint32_t *loc, ptrdiff_t offset); static void patch_veneer(uint32_t *loc, jit_pointer_t addr); @@ -380,6 +380,7 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr) ptrdiff_t diff = (uint8_t*)addr - pc_base; ASSERT((diff & ((1 << reloc.rsh) - 1)) == 0); diff >>= reloc.rsh; + int flags = reloc.kind & ~JIT_RELOC_MASK; switch (reloc.kind & JIT_RELOC_MASK) { @@ -406,7 +407,7 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr) uint8_t *target = pc_base + (voff << reloc.rsh); if (target == loc.uc) { // PC still in range to reify direct branch. - if (offset_in_jmp_range(diff)) { + if (offset_in_jmp_range(diff, flags)) { // Target also in range: reify direct branch. patch_jmp_offset(loc.ui, diff); remove_pending_literal(_jit, reloc); @@ -425,7 +426,7 @@ jit_patch_there(jit_state_t* _jit, jit_reloc_t reloc, jit_pointer_t addr) int32_t voff = read_jcc_offset(loc.ui); uint8_t *target = pc_base + (voff << reloc.rsh); if (target == loc.uc) { - if (offset_in_jcc_range(diff)) { + if (offset_in_jcc_range(diff, flags)) { patch_jcc_offset(loc.ui, diff); remove_pending_literal(_jit, reloc); } else {