1+ #include " KittyArm64.h"
2+
3+ // refs to
4+ // https://github.com/CAS-Atlantic/AArch64-Encoding
5+ // https://github.com/bminor/binutils-gdb
6+ // https://github.com/capstone-engine/capstone
7+ // https://github.com/qemu/QEMU
8+ // https://reverseengineering.stackexchange.com/questions/15418/getting-function-address-by-reading-adrp-and-add-instruction-values
9+ // https://stackoverflow.com/questions/41906688/what-are-the-semantics-of-adrp-and-adrl-instructions-in-arm-assembly
10+
11+ namespace KittyArm64
12+ {
13+
14+ int32_t bit_from (uint32_t insn, int pos)
15+ {
16+ return ((1 << pos) & insn) >> pos;
17+ }
18+
19+ int32_t bits_from (uint32_t insn, int pos, int l)
20+ {
21+ return (insn >> pos) & ((1 << l) - 1 );
22+ }
23+
24+ bool is_insn_adr (uint32_t insn)
25+ {
26+ return (insn & 0x9F000000 ) == 0x10000000 ;
27+ }
28+
29+ bool is_insn_adrp (uint32_t insn)
30+ {
31+ return (insn & 0x9F000000 ) == 0x90000000 ;
32+ }
33+
34+ // decode adr/adrp
35+ bool decode_adr_imm (uint32_t insn, int64_t *imm)
36+ {
37+ if (is_insn_adr (insn) || is_insn_adrp (insn))
38+ {
39+ // 21-bit imm encoded in adrp.
40+ int64_t imm_val = bits_from (insn, 5 , 19 ) << 2 ; // immhi
41+ imm_val |= bits_from (insn, 29 , 2 ); // immlo
42+
43+ if (is_insn_adrp (insn))
44+ {
45+ // Retrieve msb of 21-bit-signed imm for sign extension.
46+ uint64_t msbt = (imm_val >> 20 ) & 1 ;
47+
48+ // Real value is imm multiplied by 4k. Value now has 33-bit information.
49+ imm_val <<= 12 ;
50+
51+ // Sign extend to 64-bit by repeating msbt 31 (64-33) times and merge it
52+ // with value.
53+ *imm = ((((uint64_t )(1 ) << 32 ) - msbt) << 33 ) | imm_val;
54+ }
55+ else // adr
56+ {
57+ // Sign-extend the 21-bit immediate.
58+ if (imm_val & (1 << (21 - 1 )))
59+ imm_val |= ~((1LL << 21 ) - 1 );
60+
61+ *imm = imm_val;
62+ }
63+
64+ return true ;
65+ }
66+
67+ return false ;
68+ }
69+
70+ /*
71+ * 31 30 29 28 23 22 21 10 9 5 4 0
72+ * +--+--+--+-------------+--+-------------+-----+-----+
73+ * |sf|op| S| 1 0 0 0 1 0 |sh| imm12 | Rn | Rd |
74+ * +--+--+--+-------------+--+-------------+-----+-----+
75+ *
76+ * sf: 0 -> 32bit, 1 -> 64bit
77+ * op: 0 -> add , 1 -> sub
78+ * S: 1 -> set flags
79+ * sh: 1 -> LSL imm by 12
80+ */
81+
82+ int32_t decode_addsub_imm (uint32_t insn)
83+ {
84+ int32_t imm12 = bits_from (insn, 10 , 12 );
85+
86+ bool shift = bit_from (insn, 22 ) == 1 ;
87+
88+ if (shift)
89+ {
90+ imm12 <<= 12 ;
91+ }
92+
93+ return imm12;
94+ }
95+
96+ bool is_insn_ld (uint32_t insn)
97+ {
98+ // L bit
99+ return bit_from (insn, 22 ) == 1 ;
100+ }
101+
102+ bool is_insn_ldst (uint32_t insn)
103+ {
104+ return (insn & 0x0a000000 ) == 0x08000000 ;
105+ }
106+
107+ bool is_insn_ldst_uimm (uint32_t insn)
108+ {
109+ return (insn & 0x3b000000 ) == 0x39000000 ;
110+ }
111+
112+ // decode Load/store unsigned immediate
113+ bool decode_ldrstr_uimm (uint32_t insn, int32_t *imm12)
114+ {
115+ if (is_insn_ldst_uimm (insn))
116+ {
117+ *imm12 = bits_from (insn, 10 , 12 );
118+ // shift with scale value
119+ *imm12 <<= bits_from (insn, 30 , 2 ); // size bits
120+
121+ return true ;
122+ }
123+
124+ return false ;
125+ }
126+
127+ }
0 commit comments