From 666125ad64fc694aafe6b816822ab446db14f5fe Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Sat, 2 Nov 2024 06:58:15 +0000 Subject: [PATCH] Fix maximum offset prediction for jump operations --- sljit_src/sljitNativeARM_32.c | 45 ++++++++++++---- sljit_src/sljitNativeARM_64.c | 29 ++++++++-- sljit_src/sljitNativeARM_T2_32.c | 32 +++++++++-- sljit_src/sljitNativePPC_common.c | 22 ++++++-- sljit_src/sljitNativeRISCV_common.c | 82 +++++++++++++++++------------ sljit_src/sljitNativeX86_common.c | 24 ++++++--- test_src/sljitTest.c | 3 +- test_src/sljitTestCall.h | 64 ++++++++++++++++++++++ 8 files changed, 236 insertions(+), 65 deletions(-) diff --git a/sljit_src/sljitNativeARM_32.c b/sljit_src/sljitNativeARM_32.c index b22894b7..8da4eee5 100644 --- a/sljit_src/sljitNativeARM_32.c +++ b/sljit_src/sljitNativeARM_32.c @@ -478,6 +478,14 @@ static SLJIT_INLINE sljit_s32 emit_imm(struct sljit_compiler *compiler, sljit_s3 static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw *code_ptr, sljit_uw *code, sljit_sw executable_offset) { sljit_sw diff; + sljit_uw target_addr; + sljit_uw jump_addr = (sljit_uw)code_ptr; + sljit_uw orig_addr = jump->addr; + SLJIT_UNUSED_ARG(executable_offset); + +#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) + jump->addr = jump_addr; +#endif if (jump->flags & SLJIT_REWRITABLE_JUMP) return 0; @@ -488,12 +496,17 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw #endif /* SLJIT_CONFIG_ARM_V6 */ if (jump->flags & JUMP_ADDR) - diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset); + target_addr = jump->u.target; else { SLJIT_ASSERT(jump->u.label != NULL); - diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2)); + target_addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + if (jump->u.label->size > orig_addr) + jump_addr = (sljit_uw)(code + orig_addr); } + diff = (sljit_sw)target_addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr + 8, executable_offset); + /* Branch to Thumb code has not been optimized yet. */ if (diff & 0x3) return 0; @@ -505,12 +518,9 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw jump->flags |= PATCH_B; return 1; } - } - else { - if (diff <= 0x01ffffff && diff >= -0x02000000) { - *code_ptr = (B - CONDITIONAL) | (*code_ptr & COND_MASK); - jump->flags |= PATCH_B; - } + } else if (diff <= 0x01ffffff && diff >= -0x02000000) { + *code_ptr = (B - CONDITIONAL) | (*code_ptr & COND_MASK); + jump->flags |= PATCH_B; } #else /* !SLJIT_CONFIG_ARM_V6 */ if (diff <= 0x01ffffff && diff >= -0x02000000) { @@ -716,16 +726,21 @@ static void set_const_value(sljit_uw addr, sljit_sw executable_offset, sljit_uw static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) { sljit_uw addr; + sljit_uw jump_addr = (sljit_uw)code_ptr; sljit_sw diff; SLJIT_UNUSED_ARG(executable_offset); if (jump->flags & JUMP_ADDR) addr = jump->u.target; - else + else { addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + if (jump->u.label->size > jump->addr) + jump_addr = (sljit_uw)(code + jump->addr); + } + /* The pc+8 offset is represented by the 2 * SSIZE_OF(ins) below. */ - diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr, executable_offset); if ((diff & 0x3) == 0 && diff <= (0x3fc + 2 * SSIZE_OF(ins)) && diff >= (-0x3fc + 2 * SSIZE_OF(ins))) { jump->flags |= PATCH_B; @@ -786,6 +801,10 @@ static void reduce_code_size(struct sljit_compiler *compiler) if (!(jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR))) { /* Unit size: instruction. */ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr - 2; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } if (diff <= (0x01ffffff / SSIZE_OF(ins)) && diff >= (-0x02000000 / SSIZE_OF(ins))) total_size = 1 - 1; @@ -798,6 +817,11 @@ static void reduce_code_size(struct sljit_compiler *compiler) if (!(jump->flags & JUMP_ADDR)) { diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } + if (diff <= 0xff + 2 && diff >= -0xff + 2) total_size = 0; } @@ -919,7 +943,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil jump->addr = (sljit_uw)code_ptr; #else /* !SLJIT_CONFIG_ARM_V6 */ word_count += jump->flags >> JUMP_SIZE_SHIFT; - jump->addr = (sljit_uw)code_ptr; if (!detect_jump_type(jump, code_ptr, code, executable_offset)) { code_ptr[2] = code_ptr[0]; addr = ((code_ptr[0] & 0xf) << 12); diff --git a/sljit_src/sljitNativeARM_64.c b/sljit_src/sljitNativeARM_64.c index fbd0d208..223d0a10 100644 --- a/sljit_src/sljitNativeARM_64.c +++ b/sljit_src/sljitNativeARM_64.c @@ -210,7 +210,11 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i { sljit_sw diff; sljit_uw target_addr; + sljit_uw jump_addr = (sljit_uw)code_ptr; + sljit_uw orig_addr = jump->addr; + SLJIT_UNUSED_ARG(executable_offset); + jump->addr = jump_addr; if (jump->flags & SLJIT_REWRITABLE_JUMP) goto exit; @@ -218,10 +222,13 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i target_addr = jump->u.target; else { SLJIT_ASSERT(jump->u.label != NULL); - target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; + target_addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + if (jump->u.label->size > orig_addr) + jump_addr = (sljit_uw)(code + orig_addr); } - diff = (sljit_sw)target_addr - (sljit_sw)code_ptr - executable_offset; + diff = (sljit_sw)target_addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr, executable_offset); if (jump->flags & IS_COND) { diff += SSIZE_OF(ins); @@ -273,16 +280,21 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) { sljit_uw addr; + sljit_uw jump_addr = (sljit_uw)code_ptr; sljit_sw diff; SLJIT_UNUSED_ARG(executable_offset); SLJIT_ASSERT(jump->flags < ((sljit_uw)4 << JUMP_SIZE_SHIFT)); if (jump->flags & JUMP_ADDR) addr = jump->u.target; - else + else { addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); - diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + if (jump->u.label->size > jump->addr) + jump_addr = (sljit_uw)(code + jump->addr); + } + + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr, executable_offset); if (diff <= 0xfffff && diff >= -0x100000) { jump->flags |= PATCH_B; @@ -424,6 +436,10 @@ static void reduce_code_size(struct sljit_compiler *compiler) } else { /* Unit size: instruction. */ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } if ((jump->flags & IS_COND) && (diff + 1) <= (0xfffff / SSIZE_OF(ins)) && (diff + 1) >= (-0x100000 / SSIZE_OF(ins))) total_size = 0; @@ -441,6 +457,10 @@ static void reduce_code_size(struct sljit_compiler *compiler) if (!(jump->flags & JUMP_ADDR)) { diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } if (diff <= (0xfffff / SSIZE_OF(ins)) && diff >= (-0x100000 / SSIZE_OF(ins))) total_size = 0; @@ -518,7 +538,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil if (next_min_addr == next_jump_addr) { if (!(jump->flags & JUMP_MOV_ADDR)) { word_count = word_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT); - jump->addr = (sljit_uw)code_ptr; code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset); SLJIT_ASSERT((jump->flags & PATCH_COND) || ((sljit_uw)code_ptr - jump->addr < (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins))); } else { diff --git a/sljit_src/sljitNativeARM_T2_32.c b/sljit_src/sljitNativeARM_T2_32.c index 233e1327..e76c533e 100644 --- a/sljit_src/sljitNativeARM_T2_32.c +++ b/sljit_src/sljitNativeARM_T2_32.c @@ -322,7 +322,12 @@ static SLJIT_INLINE void modify_imm32_const(sljit_u16 *inst, sljit_uw new_imm) static SLJIT_INLINE sljit_u16* detect_jump_type(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset) { sljit_sw diff; + sljit_uw target_addr; + sljit_uw jump_addr = (sljit_uw)code_ptr; + sljit_uw orig_addr = jump->addr; + SLJIT_UNUSED_ARG(executable_offset); + jump->addr = jump_addr; if (jump->flags & SLJIT_REWRITABLE_JUMP) goto exit; @@ -330,12 +335,17 @@ static SLJIT_INLINE sljit_u16* detect_jump_type(struct sljit_jump *jump, sljit_u /* Branch to ARM code is not optimized yet. */ if (!(jump->u.target & 0x1)) goto exit; - diff = (sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset; + target_addr = jump->u.target; } else { SLJIT_ASSERT(jump->u.label != NULL); - diff = (sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2); + target_addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + if (jump->u.label->size > orig_addr) + jump_addr = (sljit_uw)(code + orig_addr); } + diff = (sljit_sw)target_addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr + 4, executable_offset); + if (jump->flags & IS_COND) { SLJIT_ASSERT(!(jump->flags & IS_BL)); /* Size of the prefix IT instruction. */ @@ -382,16 +392,21 @@ static SLJIT_INLINE sljit_u16* detect_jump_type(struct sljit_jump *jump, sljit_u static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset) { sljit_uw addr; + sljit_uw jump_addr = (sljit_uw)code_ptr; sljit_sw diff; SLJIT_UNUSED_ARG(executable_offset); if (jump->flags & JUMP_ADDR) addr = jump->u.target; - else + else { addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + if (jump->u.label->size > jump->addr) + jump_addr = (sljit_uw)(code + jump->addr); + } + /* The pc+4 offset is represented by the 2 * SSIZE_OF(sljit_u16) below. */ - diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr, executable_offset); /* Note: ADR with imm8 does not set the last bit (Thumb2 flag). */ @@ -519,6 +534,10 @@ static void reduce_code_size(struct sljit_compiler *compiler) if (!(jump->flags & (SLJIT_REWRITABLE_JUMP | JUMP_ADDR))) { /* Unit size: instruction. */ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr - 2; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } if (jump->flags & IS_COND) { diff++; @@ -542,6 +561,10 @@ static void reduce_code_size(struct sljit_compiler *compiler) if (!(jump->flags & JUMP_ADDR)) { diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } if (diff <= (0xffd / SSIZE_OF(u16)) && diff >= (-0xfff / SSIZE_OF(u16))) total_size = 1; @@ -614,7 +637,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil if (next_min_addr == next_jump_addr) { if (!(jump->flags & JUMP_MOV_ADDR)) { half_count = half_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT); - jump->addr = (sljit_uw)code_ptr; code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset); SLJIT_ASSERT((sljit_uw)code_ptr - jump->addr < ((jump->flags >> JUMP_SIZE_SHIFT) + ((jump->flags & 0xf0) <= PATCH_TYPE2)) * sizeof(sljit_u16)); diff --git a/sljit_src/sljitNativePPC_common.c b/sljit_src/sljitNativePPC_common.c index 8c3e4224..1fdd5996 100644 --- a/sljit_src/sljitNativePPC_common.c +++ b/sljit_src/sljitNativePPC_common.c @@ -319,7 +319,11 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i { sljit_sw diff; sljit_uw target_addr; + sljit_uw jump_addr = (sljit_uw)code_ptr; + sljit_uw orig_addr = jump->addr; + SLJIT_UNUSED_ARG(executable_offset); + jump->addr = jump_addr; #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) if (jump->flags & (SLJIT_REWRITABLE_JUMP | IS_CALL)) goto exit; @@ -333,6 +337,9 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i else { SLJIT_ASSERT(jump->u.label != NULL); target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; + + if (jump->u.label->size > orig_addr) + jump_addr = (sljit_uw)(code + orig_addr); } #if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) @@ -340,7 +347,7 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i goto keep_address; #endif - diff = (sljit_sw)target_addr - (sljit_sw)code_ptr - executable_offset; + diff = (sljit_sw)target_addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr, executable_offset); if (jump->flags & IS_COND) { if (diff <= 0x7fff && diff >= -0x8000) { @@ -552,6 +559,10 @@ static void reduce_code_size(struct sljit_compiler *compiler) } else { /* Unit size: instruction. */ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } if (jump->flags & IS_COND) { if (diff <= (0x7fff / SSIZE_OF(ins)) && diff >= (-0x8000 / SSIZE_OF(ins))) @@ -597,6 +608,9 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil sljit_ins *buf_ptr; sljit_ins *buf_end; sljit_uw word_count; +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + sljit_uw jump_addr; +#endif SLJIT_NEXT_DEFINE_TYPES; sljit_sw executable_offset; @@ -653,9 +667,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil if (next_min_addr == next_jump_addr) { if (!(jump->flags & JUMP_MOV_ADDR)) { word_count += jump->flags >> JUMP_SIZE_SHIFT; - jump->addr = (sljit_uw)code_ptr; +#if (defined SLJIT_DEBUG && SLJIT_DEBUG) + jump_addr = (sljit_uw)code_ptr; +#endif code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset); - SLJIT_ASSERT(((sljit_uw)code_ptr - jump->addr <= (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins))); + SLJIT_ASSERT(((sljit_uw)code_ptr - jump_addr <= (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins))); } else { jump->addr = (sljit_uw)code_ptr; #if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) diff --git a/sljit_src/sljitNativeRISCV_common.c b/sljit_src/sljitNativeRISCV_common.c index e487b79b..36f4238f 100644 --- a/sljit_src/sljitNativeRISCV_common.c +++ b/sljit_src/sljitNativeRISCV_common.c @@ -244,14 +244,15 @@ static sljit_s32 push_imm_s_inst(struct sljit_compiler *compiler, sljit_ins ins, return push_inst(compiler, ins | IMM_S(imm)); } -static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code, sljit_sw executable_offset) +static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) { sljit_sw diff; sljit_uw target_addr; - sljit_ins *inst; - - inst = (sljit_ins *)jump->addr; + sljit_uw jump_addr = (sljit_uw)code_ptr; + sljit_uw orig_addr = jump->addr; + SLJIT_UNUSED_ARG(executable_offset); + jump->addr = jump_addr; if (jump->flags & SLJIT_REWRITABLE_JUMP) goto exit; @@ -259,20 +260,23 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i target_addr = jump->u.target; else { SLJIT_ASSERT(jump->u.label != NULL); - target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset; + target_addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); + + if (jump->u.label->size > orig_addr) + jump_addr = (sljit_uw)(code + orig_addr); } - diff = (sljit_sw)target_addr - (sljit_sw)inst - executable_offset; + diff = (sljit_sw)target_addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr, executable_offset); if (jump->flags & IS_COND) { diff += SSIZE_OF(ins); if (diff >= BRANCH_MIN && diff <= BRANCH_MAX) { - inst--; - inst[0] = (inst[0] & 0x1fff07f) ^ 0x1000; + code_ptr--; + code_ptr[0] = (code_ptr[0] & 0x1fff07f) ^ 0x1000; jump->flags |= PATCH_B; - jump->addr = (sljit_uw)inst; - return inst; + jump->addr = (sljit_uw)code_ptr; + return code_ptr; } diff -= SSIZE_OF(ins); @@ -281,61 +285,61 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i if (diff >= JUMP_MIN && diff <= JUMP_MAX) { if (jump->flags & IS_COND) { #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - inst[-1] -= (sljit_ins)(1 * sizeof(sljit_ins)) << 7; + code_ptr[-1] -= (sljit_ins)(1 * sizeof(sljit_ins)) << 7; #else - inst[-1] -= (sljit_ins)(5 * sizeof(sljit_ins)) << 7; + code_ptr[-1] -= (sljit_ins)(5 * sizeof(sljit_ins)) << 7; #endif } jump->flags |= PATCH_J; - return inst; + return code_ptr; } #if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) if (diff >= S32_MIN && diff <= S32_MAX) { if (jump->flags & IS_COND) - inst[-1] -= (sljit_ins)(4 * sizeof(sljit_ins)) << 7; + code_ptr[-1] -= (sljit_ins)(4 * sizeof(sljit_ins)) << 7; jump->flags |= PATCH_REL32; - inst[1] = inst[0]; - return inst + 1; + code_ptr[1] = code_ptr[0]; + return code_ptr + 1; } if (target_addr <= (sljit_uw)S32_MAX) { if (jump->flags & IS_COND) - inst[-1] -= (sljit_ins)(4 * sizeof(sljit_ins)) << 7; + code_ptr[-1] -= (sljit_ins)(4 * sizeof(sljit_ins)) << 7; jump->flags |= PATCH_ABS32; - inst[1] = inst[0]; - return inst + 1; + code_ptr[1] = code_ptr[0]; + return code_ptr + 1; } if (target_addr <= S44_MAX) { if (jump->flags & IS_COND) - inst[-1] -= (sljit_ins)(2 * sizeof(sljit_ins)) << 7; + code_ptr[-1] -= (sljit_ins)(2 * sizeof(sljit_ins)) << 7; jump->flags |= PATCH_ABS44; - inst[3] = inst[0]; - return inst + 3; + code_ptr[3] = code_ptr[0]; + return code_ptr + 3; } if (target_addr <= S52_MAX) { if (jump->flags & IS_COND) - inst[-1] -= (sljit_ins)(1 * sizeof(sljit_ins)) << 7; + code_ptr[-1] -= (sljit_ins)(1 * sizeof(sljit_ins)) << 7; jump->flags |= PATCH_ABS52; - inst[4] = inst[0]; - return inst + 4; + code_ptr[4] = code_ptr[0]; + return code_ptr + 4; } #endif exit: #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) - inst[1] = inst[0]; - return inst + 1; + code_ptr[1] = code_ptr[0]; + return code_ptr + 1; #else - inst[5] = inst[0]; - return inst + 5; + code_ptr[5] = code_ptr[0]; + return code_ptr + 5; #endif } @@ -344,16 +348,21 @@ static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_i static SLJIT_INLINE sljit_sw mov_addr_get_length(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset) { sljit_uw addr; + sljit_uw jump_addr = (sljit_uw)code_ptr; sljit_sw diff; SLJIT_UNUSED_ARG(executable_offset); SLJIT_ASSERT(jump->flags < ((sljit_uw)6 << JUMP_SIZE_SHIFT)); if (jump->flags & JUMP_ADDR) addr = jump->u.target; - else + else { addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code + jump->u.label->size, executable_offset); - diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset); + if (jump->u.label->size > jump->addr) + jump_addr = (sljit_uw)(code + jump->addr); + } + + diff = (sljit_sw)addr - (sljit_sw)SLJIT_ADD_EXEC_OFFSET(jump_addr, executable_offset); if (diff >= S32_MIN && diff <= S32_MAX) { SLJIT_ASSERT(jump->flags >= ((sljit_uw)1 << JUMP_SIZE_SHIFT)); @@ -530,6 +539,10 @@ static void reduce_code_size(struct sljit_compiler *compiler) } else { /* Unit size: instruction. */ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } if ((jump->flags & IS_COND) && (diff + 1) <= (BRANCH_MAX / SSIZE_OF(ins)) && (diff + 1) >= (BRANCH_MIN / SSIZE_OF(ins))) total_size = 0; @@ -551,6 +564,10 @@ static void reduce_code_size(struct sljit_compiler *compiler) if (!(jump->flags & JUMP_ADDR)) { /* Real size minus 1. Unit size: instruction. */ diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } if (diff >= (S32_MIN / SSIZE_OF(ins)) && diff <= (S32_MAX / SSIZE_OF(ins))) total_size = 1; @@ -629,8 +646,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil if (next_min_addr == next_jump_addr) { if (!(jump->flags & JUMP_MOV_ADDR)) { word_count = word_count - 1 + (jump->flags >> JUMP_SIZE_SHIFT); - jump->addr = (sljit_uw)code_ptr; - code_ptr = detect_jump_type(jump, code, executable_offset); + code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset); SLJIT_ASSERT((jump->flags & PATCH_B) || ((sljit_uw)code_ptr - jump->addr < (jump->flags >> JUMP_SIZE_SHIFT) * sizeof(sljit_ins))); } else { #if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) diff --git a/sljit_src/sljitNativeX86_common.c b/sljit_src/sljitNativeX86_common.c index 5bb0e8b2..9f599d5f 100644 --- a/sljit_src/sljitNativeX86_common.c +++ b/sljit_src/sljitNativeX86_common.c @@ -680,18 +680,23 @@ static sljit_u8* detect_near_jump_type(struct sljit_jump *jump, sljit_u8 *code_p sljit_uw type = jump->flags >> TYPE_SHIFT; sljit_s32 short_jump; sljit_uw label_addr; + sljit_uw jump_addr; - if (jump->flags & JUMP_ADDR) - label_addr = jump->u.target - (sljit_uw)executable_offset; - else + jump_addr = (sljit_uw)code_ptr; + if (!(jump->flags & JUMP_ADDR)) { label_addr = (sljit_uw)(code + jump->u.label->size); + if (jump->u.label->size > jump->addr) + jump_addr = (sljit_uw)(code + jump->addr); + } else + label_addr = jump->u.target - (sljit_uw)executable_offset; + #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - if ((sljit_sw)(label_addr - (sljit_uw)(code_ptr + 6)) > HALFWORD_MAX || (sljit_sw)(label_addr - (sljit_uw)(code_ptr + 5)) < HALFWORD_MIN) + if ((sljit_sw)(label_addr - (jump_addr + 6)) > HALFWORD_MAX || (sljit_sw)(label_addr - (jump_addr + 5)) < HALFWORD_MIN) return detect_far_jump_type(jump, code_ptr); #endif /* SLJIT_CONFIG_X86_64 */ - short_jump = (sljit_sw)(label_addr - (sljit_uw)(code_ptr + 2)) >= -0x80 && (sljit_sw)(label_addr - (sljit_uw)(code_ptr + 2)) <= 0x7f; + short_jump = (sljit_sw)(label_addr - (jump_addr + 2)) >= -0x80 && (sljit_sw)(label_addr - (jump_addr + 2)) <= 0x7f; if (type == SLJIT_JUMP) { if (short_jump) @@ -813,6 +818,7 @@ static void reduce_code_size(struct sljit_compiler *compiler) if (next_min_addr != next_jump_addr) continue; + jump->addr -= size_reduce; if (!(jump->flags & JUMP_MOV_ADDR)) { #if (defined SLJIT_DEBUG && SLJIT_DEBUG) size_reduce_max = size_reduce + (((jump->flags >> TYPE_SHIFT) < SLJIT_JUMP) ? CJUMP_MAX_SIZE : JUMP_MAX_SIZE); @@ -826,7 +832,11 @@ static void reduce_code_size(struct sljit_compiler *compiler) #endif /* SLJIT_CONFIG_X86_64 */ } else { /* Unit size: instruction. */ - diff = (sljit_sw)jump->u.label->size - (sljit_sw)(jump->addr - size_reduce); + diff = (sljit_sw)jump->u.label->size - (sljit_sw)jump->addr; + if (jump->u.label->size > jump->addr) { + SLJIT_ASSERT(jump->u.label->size - size_reduce >= jump->addr); + diff -= (sljit_sw)size_reduce; + } type = jump->flags >> TYPE_SHIFT; #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) @@ -866,7 +876,7 @@ static void reduce_code_size(struct sljit_compiler *compiler) #endif /* SLJIT_DEBUG */ if (!(jump->flags & JUMP_ADDR)) { - diff = (sljit_sw)jump->u.label->size - (sljit_sw)(jump->addr - size_reduce - 3); + diff = (sljit_sw)jump->u.label->size - (sljit_sw)(jump->addr - 3); if (diff <= HALFWORD_MAX && diff >= HALFWORD_MIN) size_reduce += 3; diff --git a/test_src/sljitTest.c b/test_src/sljitTest.c index 61339deb..c4068ecd 100644 --- a/test_src/sljitTest.c +++ b/test_src/sljitTest.c @@ -9135,6 +9135,7 @@ int sljit_test(int argc, char* argv[]) test_call10(); test_call11(); test_call12(); + test_call13(); if (sljit_has_cpu_feature(SLJIT_HAS_FPU)) { if (verbose) @@ -9198,7 +9199,7 @@ int sljit_test(int argc, char* argv[]) sljit_free_unused_memory_exec(); #endif -# define TEST_COUNT 123 +# define TEST_COUNT 124 printf("SLJIT tests: "); if (successful_tests == TEST_COUNT) diff --git a/test_src/sljitTestCall.h b/test_src/sljitTestCall.h index 18329f6e..4c9c8d0a 100644 --- a/test_src/sljitTestCall.h +++ b/test_src/sljitTestCall.h @@ -2028,3 +2028,67 @@ static void test_call12(void) successful_tests++; } + +static void test_call13(void) +{ + /* Test get return address. */ + executable_code code; + struct sljit_compiler* compiler; + struct sljit_jump *jump; + void *simple_func; + sljit_s32 i; + + if (verbose) + printf("Run test_call13\n"); + + compiler = sljit_create_compiler(NULL); + FAILED(!compiler, "cannot create compiler\n"); + + /* This tests expects that the two compiled codes are very close + to each other, and above the 4GByte address space on 64 bit. */ + sljit_emit_enter(compiler, 0, SLJIT_ARGS0V(), 0, 0, 0); + sljit_emit_op2(compiler, SLJIT_ADD32, SLJIT_MEM0(), (sljit_sw)&i, SLJIT_MEM0(), (sljit_sw)&i, SLJIT_IMM, 1); + sljit_emit_return_void(compiler); + + simple_func = sljit_generate_code(compiler, 0, NULL); + sljit_free_compiler(compiler); + + compiler = sljit_create_compiler(NULL); + if (compiler == NULL) { + sljit_free_code(simple_func, NULL); + FAILED(!compiler, "cannot create compiler\n"); + } + + sljit_emit_enter(compiler, 0, SLJIT_ARGS0(W), 1, 0, 0); + + for (i = 0; i < 65536; i++) + sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS0V(), SLJIT_IMM, SLJIT_FUNC_ADDR(simple_func)); + + /* Forward jump. */ + jump = sljit_emit_jump(compiler, SLJIT_JUMP); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, 1); + sljit_set_label(jump, sljit_emit_label(compiler)); + + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, 5); + jump = sljit_emit_cmp(compiler, SLJIT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 5); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, 1); + sljit_set_label(jump, sljit_emit_label(compiler)); + + /* Forward label. */ + jump = sljit_emit_mov_addr(compiler, SLJIT_R0, 0); + sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_R0, 0, SLJIT_IMM, 1); + sljit_set_label(jump, sljit_emit_label(compiler)); + + sljit_emit_return(compiler, SLJIT_MOV, SLJIT_IMM, 0x12345678); + + code.code = sljit_generate_code(compiler, 0, NULL); + CHECK(compiler); + sljit_free_compiler(compiler); + + i = 0; + FAILED(code.func0() != 0x12345678, "test_call13 case 1 failed\n"); + FAILED(i != 65536, "test_call13 case 2 failed\n"); + + sljit_free_code(code.code, NULL); + successful_tests++; +}