Skip to content

Commit

Permalink
Fix maximum offset prediction for jump operations
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoltan Herczeg committed Nov 2, 2024
1 parent f632608 commit 666125a
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 65 deletions.
45 changes: 34 additions & 11 deletions sljit_src/sljitNativeARM_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
29 changes: 24 additions & 5 deletions sljit_src/sljitNativeARM_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,18 +210,25 @@ 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;

if (jump->flags & JUMP_ADDR)
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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
32 changes: 27 additions & 5 deletions sljit_src/sljitNativeARM_T2_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,20 +322,30 @@ 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;

if (jump->flags & JUMP_ADDR) {
/* 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. */
Expand Down Expand Up @@ -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). */

Expand Down Expand Up @@ -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++;
Expand All @@ -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;
Expand Down Expand Up @@ -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));
Expand Down
22 changes: 19 additions & 3 deletions sljit_src/sljitNativePPC_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -333,14 +337,17 @@ 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)
if (jump->flags & IS_CALL)
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) {
Expand Down Expand Up @@ -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)))
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 666125a

Please sign in to comment.