mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-30 00:40:20 +02:00
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.
This commit is contained in:
parent
52ec8aefa0
commit
11b9d3744e
3 changed files with 25 additions and 14 deletions
|
@ -90,9 +90,9 @@ DEFINE_ENCODER(size, 2, 22, unsigned, uint32_t)
|
||||||
{ \
|
{ \
|
||||||
return read_signed_bitfield(*loc, kind##_width, kind##_shift); \
|
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 \
|
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); \
|
return in_signed_range(diff, kind##_width); \
|
||||||
} \
|
} \
|
||||||
|
|
|
@ -186,6 +186,8 @@
|
||||||
|
|
||||||
#define _NOREG (jit_gpr_regno(_PC))
|
#define _NOREG (jit_gpr_regno(_PC))
|
||||||
|
|
||||||
|
#define JIT_RELOC_B JIT_RELOC_FLAG_0
|
||||||
|
|
||||||
static void
|
static void
|
||||||
emit_wide_thumb(jit_state_t *_jit, uint32_t inst)
|
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
|
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
|
static int32_t
|
||||||
|
@ -295,7 +300,7 @@ static const uint32_t thumb_jump_mask = 0xf800d000;
|
||||||
static uint32_t
|
static uint32_t
|
||||||
encode_thumb_jump(int32_t v)
|
encode_thumb_jump(int32_t v)
|
||||||
{
|
{
|
||||||
ASSERT(offset_in_jmp_range(v));
|
ASSERT(offset_in_jmp_range(v, 0));
|
||||||
v >>= 1;
|
v >>= 1;
|
||||||
uint32_t s = !!(v & 0x800000);
|
uint32_t s = !!(v & 0x800000);
|
||||||
uint32_t i1 = !!(v & 0x400000);
|
uint32_t i1 = !!(v & 0x400000);
|
||||||
|
@ -339,8 +344,10 @@ emit_thumb_jump(jit_state_t *_jit, uint32_t inst)
|
||||||
while (1) {
|
while (1) {
|
||||||
uint8_t *pc_base = _jit->pc.uc + 4;
|
uint8_t *pc_base = _jit->pc.uc + 4;
|
||||||
int32_t off = (uint8_t*)jit_address(_jit) - pc_base;
|
int32_t off = (uint8_t*)jit_address(_jit) - pc_base;
|
||||||
jit_reloc_t ret =
|
enum jit_reloc_kind kind = JIT_RELOC_JMP_WITH_VENEER;
|
||||||
jit_reloc (_jit, JIT_RELOC_JMP_WITH_VENEER, 0, _jit->pc.uc, pc_base, 0);
|
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;
|
uint8_t thumb_jump_width = 24;
|
||||||
if (add_pending_literal(_jit, ret, thumb_jump_width - 1)) {
|
if (add_pending_literal(_jit, ret, thumb_jump_width - 1)) {
|
||||||
emit_wide_thumb(_jit, patch_thumb_jump(inst, off));
|
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
|
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
|
static int32_t
|
||||||
|
@ -378,7 +388,7 @@ static const uint32_t thumb_cc_jump_mask = 0xfbc0d000;
|
||||||
static uint32_t
|
static uint32_t
|
||||||
encode_thumb_cc_jump(int32_t v)
|
encode_thumb_cc_jump(int32_t v)
|
||||||
{
|
{
|
||||||
ASSERT(offset_in_jcc_range(v));
|
ASSERT(offset_in_jcc_range(v, 0));
|
||||||
v >>= 1;
|
v >>= 1;
|
||||||
uint32_t s = !!(v & 0x80000);
|
uint32_t s = !!(v & 0x80000);
|
||||||
uint32_t j2 = !!(v & 0x40000);
|
uint32_t j2 = !!(v & 0x40000);
|
||||||
|
|
|
@ -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 void emit_literal_pool(jit_state_t *_jit, enum guard_pool guard);
|
||||||
|
|
||||||
static int32_t read_jmp_offset(uint32_t *loc);
|
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_jmp_offset(uint32_t *loc, ptrdiff_t offset);
|
||||||
static void patch_veneer_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 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_jcc_offset(uint32_t *loc, ptrdiff_t offset);
|
||||||
static void patch_veneer_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);
|
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;
|
ptrdiff_t diff = (uint8_t*)addr - pc_base;
|
||||||
ASSERT((diff & ((1 << reloc.rsh) - 1)) == 0);
|
ASSERT((diff & ((1 << reloc.rsh) - 1)) == 0);
|
||||||
diff >>= reloc.rsh;
|
diff >>= reloc.rsh;
|
||||||
|
int flags = reloc.kind & ~JIT_RELOC_MASK;
|
||||||
|
|
||||||
switch (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);
|
uint8_t *target = pc_base + (voff << reloc.rsh);
|
||||||
if (target == loc.uc) {
|
if (target == loc.uc) {
|
||||||
// PC still in range to reify direct branch.
|
// 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.
|
// Target also in range: reify direct branch.
|
||||||
patch_jmp_offset(loc.ui, diff);
|
patch_jmp_offset(loc.ui, diff);
|
||||||
remove_pending_literal(_jit, reloc);
|
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);
|
int32_t voff = read_jcc_offset(loc.ui);
|
||||||
uint8_t *target = pc_base + (voff << reloc.rsh);
|
uint8_t *target = pc_base + (voff << reloc.rsh);
|
||||||
if (target == loc.uc) {
|
if (target == loc.uc) {
|
||||||
if (offset_in_jcc_range(diff)) {
|
if (offset_in_jcc_range(diff, flags)) {
|
||||||
patch_jcc_offset(loc.ui, diff);
|
patch_jcc_offset(loc.ui, diff);
|
||||||
remove_pending_literal(_jit, reloc);
|
remove_pending_literal(_jit, reloc);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue