1111 #include "fde64/fde64.h"
1212#endif
1313
14+ int32_t sign_extend (uint32_t x , int N ) {
15+ return (int32_t )(x << (32 - N )) >> (32 - N );
16+ }
17+
1418bool need_far_jump (const void * src , const void * dst ) {
1519 long long distance = dst > src ? dst - src : src - dst ;
1620#ifdef __aarch64__
@@ -78,7 +82,8 @@ static inline void save_header(void **src, void **dst, int min_len) {
7882 insn = * (uint32_t * )* src ;
7983 if (((insn ^ 0x90000000 ) & 0x9f000000 ) == 0 ) {
8084 // adrp
81- int64_t addr = ((int64_t )* src >> 12 ) + ((insn >> 29 & 0x3 ) | ((insn >> 3 ) & 0x1ffffc ));
85+ int32_t imm21 = sign_extend ((insn >> 29 & 0x3 ) | (insn >> 3 & 0x1ffffc ), 21 );
86+ int64_t addr = ((int64_t )* src >> 12 ) + imm21 ;
8287 int64_t len = addr - ((int64_t )* dst >> 12 );
8388 if ((len << 12 ) < 4 * GB ) {
8489 // modify the immediate (len: 4 -> 4)
@@ -105,7 +110,7 @@ static inline void save_header(void **src, void **dst, int min_len) {
105110 else if (((insn ^ 0x14000000 ) & 0xfc000000 ) == 0 || ((insn ^ 0x94000000 ) & 0xfc000000 ) == 0 ) {
106111 // b or bl
107112 bool link = insn >> 31 ;
108- int32_t imm26 = ( int32_t )( insn << 6 ) >> 6 ; // sign extend
113+ int32_t imm26 = sign_extend ( insn , 26 );
109114 void * addr = * src + (imm26 << 2 );
110115 * dst += calc_jump (* dst , * dst , addr , link );
111116 }
@@ -136,7 +141,7 @@ static inline void save_header(void **src, void **dst, int min_len) {
136141 * dst += sizeof (uint8_t );
137142 }
138143 else if ((insn .opcode & 0xf0 ) == 0x70 ) {
139- // Jcc (short)
144+ // jcc (short)
140145 // revert the condition and insert a jump (len: 2 -> 2+14)
141146 void * jmp_dst = * src + insn .len + insn .imm8 ;
142147 int jmp_len = calc_jump (* dst + 2 , * dst + 2 , jmp_dst , false);
@@ -145,13 +150,19 @@ static inline void save_header(void **src, void **dst, int min_len) {
145150 * dst += 2 + jmp_len ;
146151 }
147152 else if (insn .opcode_len == 2 && insn .opcode == 0x0f && (insn .opcode2 & 0xf0 ) == 0x80 ) {
148- // Jcc (near) (len: 6 -> 2+14)
153+ // jcc (near) (len: 6 -> 2+14)
149154 void * jmp_dst = * src + insn .len + insn .imm32 ;
150155 int jmp_len = calc_jump (* dst + 2 , * dst + 2 , jmp_dst , false);
151156 * (uint8_t * )* dst = (0x70 | (insn .opcode2 & 0xf )) ^ 1 ; // invert the condition
152157 * (int8_t * )(* dst + 1 ) = jmp_len ;
153158 * dst += 2 + jmp_len ;
154159 }
160+ else if (insn .opcode == 0xe8 || insn .opcode == 0xe9 ) {
161+ // call or jmp (rel32) (len: 5 -> 5/14)
162+ bool link = (insn .opcode == 0xe8 );
163+ void * jmp_dst = * src + insn .len + insn .imm32 ;
164+ * dst += calc_jump (* dst , * dst , jmp_dst , link );
165+ }
155166 else {
156167 memcpy (* dst , * src , insn .len );
157168 * dst += insn .len ;
0 commit comments