@@ -51,15 +51,29 @@ import_address (void *imp)
5151 __try
5252 {
5353#if defined(__aarch64__)
54- // If opcode is an adr instruction.
55- uint32_t opcode = *(uint32_t *) imp;
56- if ((opcode & 0x9f000000 ) == 0x10000000 )
54+ // If opcode1 is an adr instruction (https://www.scs.stanford.edu/~zyedidia/arm64/adr.html)
55+ uint32_t opcode1 = *((uint32_t *) imp);
56+ uint32_t opcode2 = *(((uint32_t *) imp) + 1 );
57+ if ((opcode1 & 0x9f000000 ) == 0x10000000 )
5758 {
58- uint32_t immhi = (opcode >> 5 ) & 0x7ffff ;
59- uint32_t immlo = (opcode >> 29 ) & 0x3 ;
60- int64_t sign_extend = (0l - (immhi >> 18 )) << 21 ;
59+ uint32_t immhi = (opcode1 >> 5 ) & 0x7ffff ;
60+ uint32_t immlo = (opcode1 >> 29 ) & 0x3 ;
61+ int64_t sign_extend = (0l - (immhi >> 20 )) << 21 ; // sign extend from 21 to 64 bits
6162 int64_t imm = sign_extend | (immhi << 2 ) | immlo;
62- uintptr_t jmpto = *(uintptr_t *) ((uint8_t *) imp + imm);
63+ uintptr_t jmpto = *(uintptr_t *) ((int64_t ) imp + imm);
64+ return (void *) jmpto;
65+ }
66+ // If opcode1 is an adrp and opcode2 is ldr instruction (https://www.scs.stanford.edu/~zyedidia/arm64/adrp.html,
67+ // https://www.scs.stanford.edu/~zyedidia/arm64/ldr_imm_gen.html).
68+ else if (((opcode1 & 0x9f000000 ) == 0x90000000 ) && ((opcode2 & 0xbfc00000 ) == 0xb9400000 ))
69+ {
70+ uint32_t immhi = (opcode1 >> 5 ) & 0x7ffff ;
71+ uint32_t immlo = (opcode1 >> 29 ) & 0x3 ;
72+ uint32_t imm12 = ((opcode2 >> 10 ) & 0xfff ) * 8 ; // 64 bit scale
73+ int64_t sign_extend = (0l - ((int64_t ) immhi >> 32 )) << 33 ; // sign extend from 33 to 64 bits
74+ int64_t imm = sign_extend | (((immhi << 2 ) | immlo) << 12 );
75+ int64_t base = (int64_t ) imp & ~0xfff ;
76+ uintptr_t jmpto = *(uintptr_t *) (base + imm + imm12);
6377 return (void *) jmpto;
6478 }
6579#else
0 commit comments