xref: /aosp_15_r20/external/zucchini/arm_utils.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
1*a03ca8b9SKrzysztof Kosiński // Copyright 2019 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński 
5*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/arm_utils.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/algorithm.h"
8*a03ca8b9SKrzysztof Kosiński 
9*a03ca8b9SKrzysztof Kosiński namespace zucchini {
10*a03ca8b9SKrzysztof Kosiński 
11*a03ca8b9SKrzysztof Kosiński namespace {
12*a03ca8b9SKrzysztof Kosiński 
IsMisaligned(rva_t rva,ArmAlign align)13*a03ca8b9SKrzysztof Kosiński inline bool IsMisaligned(rva_t rva, ArmAlign align) {
14*a03ca8b9SKrzysztof Kosiński   return (rva & (align - 1)) != 0;
15*a03ca8b9SKrzysztof Kosiński }
16*a03ca8b9SKrzysztof Kosiński 
17*a03ca8b9SKrzysztof Kosiński }  // namespace
18*a03ca8b9SKrzysztof Kosiński 
19*a03ca8b9SKrzysztof Kosiński /******** AArch32Rel32Translator ********/
20*a03ca8b9SKrzysztof Kosiński 
21*a03ca8b9SKrzysztof Kosiński AArch32Rel32Translator::AArch32Rel32Translator() = default;
22*a03ca8b9SKrzysztof Kosiński 
23*a03ca8b9SKrzysztof Kosiński // The mapping between ARM instruction "Code" to "Displacement" involves complex
24*a03ca8b9SKrzysztof Kosiński // bit manipulation. The comments below annotate bits mappings using a string.
25*a03ca8b9SKrzysztof Kosiński // * Bits are listed from highest-order to lowerst-order (like in the manual).
26*a03ca8b9SKrzysztof Kosiński // * '0' and '1' denote literals.
27*a03ca8b9SKrzysztof Kosiński // * Uppercase letters denote a single bit in "Code". For example, 'S' denotes
28*a03ca8b9SKrzysztof Kosiński //   a sign bit that gets extended in "Displacement". To follow naming in the
29*a03ca8b9SKrzysztof Kosiński //   manual, these may enumerated, and written as "(I1)", "(I2)", etc.
30*a03ca8b9SKrzysztof Kosiński // * Lowercase letters denote bit fields with orders preserved.
31*a03ca8b9SKrzysztof Kosiński 
32*a03ca8b9SKrzysztof Kosiński // static
DecodeA24(uint32_t code32,arm_disp_t * disp)33*a03ca8b9SKrzysztof Kosiński ArmAlign AArch32Rel32Translator::DecodeA24(uint32_t code32, arm_disp_t* disp) {
34*a03ca8b9SKrzysztof Kosiński   // Handle multiple instructions. Let cccc != 1111:
35*a03ca8b9SKrzysztof Kosiński   // B encoding A1:
36*a03ca8b9SKrzysztof Kosiński   //   Code:         cccc1010 Siiiiiii iiiiiiii iiiiiiii
37*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSSSi iiiiiiii iiiiiiii iiiiii00
38*a03ca8b9SKrzysztof Kosiński   // BL encoding A1:
39*a03ca8b9SKrzysztof Kosiński   //   Code:         cccc1011 Siiiiiii iiiiiiii iiiiiiii
40*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSSSi iiiiiiii iiiiiiii iiiiii00
41*a03ca8b9SKrzysztof Kosiński   // BLX encoding A2:
42*a03ca8b9SKrzysztof Kosiński   //   Code:         1111101H Siiiiiii iiiiiiii iiiiiiii
43*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSSSi iiiiiiii iiiiiiii iiiiiiH0
44*a03ca8b9SKrzysztof Kosiński   uint8_t bits = GetUnsignedBits<24, 27>(code32);
45*a03ca8b9SKrzysztof Kosiński   if (bits == 0xA || bits == 0xB) {  // B, BL, or BLX.
46*a03ca8b9SKrzysztof Kosiński     *disp = GetSignedBits<0, 23>(code32) << 2;
47*a03ca8b9SKrzysztof Kosiński     uint8_t cond = GetUnsignedBits<28, 31>(code32);
48*a03ca8b9SKrzysztof Kosiński     if (cond == 0xF) {  // BLX.
49*a03ca8b9SKrzysztof Kosiński       uint32_t H = GetBit<24>(code32);
50*a03ca8b9SKrzysztof Kosiński       *disp |= H << 1;
51*a03ca8b9SKrzysztof Kosiński       return kArmAlign2;
52*a03ca8b9SKrzysztof Kosiński     }
53*a03ca8b9SKrzysztof Kosiński     return kArmAlign4;
54*a03ca8b9SKrzysztof Kosiński   }
55*a03ca8b9SKrzysztof Kosiński   return kArmAlignFail;
56*a03ca8b9SKrzysztof Kosiński }
57*a03ca8b9SKrzysztof Kosiński 
58*a03ca8b9SKrzysztof Kosiński // static
EncodeA24(arm_disp_t disp,uint32_t * code32)59*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::EncodeA24(arm_disp_t disp, uint32_t* code32) {
60*a03ca8b9SKrzysztof Kosiński   uint32_t t = *code32;
61*a03ca8b9SKrzysztof Kosiński   uint8_t bits = GetUnsignedBits<24, 27>(t);
62*a03ca8b9SKrzysztof Kosiński   if (bits == 0xA || bits == 0xB) {
63*a03ca8b9SKrzysztof Kosiński     // B, BL, or BLX.
64*a03ca8b9SKrzysztof Kosiński     if (!SignedFit<26>(disp))  // Detect overflow.
65*a03ca8b9SKrzysztof Kosiński       return false;
66*a03ca8b9SKrzysztof Kosiński     uint8_t cond = GetUnsignedBits<28, 31>(t);
67*a03ca8b9SKrzysztof Kosiński     if (cond == 0xF) {
68*a03ca8b9SKrzysztof Kosiński       if (disp % 2)  // BLX (encoding A2) requires 2-byte alignment.
69*a03ca8b9SKrzysztof Kosiński         return false;
70*a03ca8b9SKrzysztof Kosiński       uint32_t H = GetBit<1>(disp);
71*a03ca8b9SKrzysztof Kosiński       t = (t & 0xFEFFFFFF) | (H << 24);
72*a03ca8b9SKrzysztof Kosiński     } else {
73*a03ca8b9SKrzysztof Kosiński       if (disp % 4)  // B and BL require 4-byte alignment.
74*a03ca8b9SKrzysztof Kosiński         return false;
75*a03ca8b9SKrzysztof Kosiński     }
76*a03ca8b9SKrzysztof Kosiński     t = (t & 0xFF000000) | ((disp >> 2) & 0x00FFFFFF);
77*a03ca8b9SKrzysztof Kosiński     *code32 = t;
78*a03ca8b9SKrzysztof Kosiński     return true;
79*a03ca8b9SKrzysztof Kosiński   }
80*a03ca8b9SKrzysztof Kosiński   return false;
81*a03ca8b9SKrzysztof Kosiński }
82*a03ca8b9SKrzysztof Kosiński 
83*a03ca8b9SKrzysztof Kosiński // static
ReadA24(rva_t instr_rva,uint32_t code32,rva_t * target_rva)84*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::ReadA24(rva_t instr_rva,
85*a03ca8b9SKrzysztof Kosiński                                      uint32_t code32,
86*a03ca8b9SKrzysztof Kosiński                                      rva_t* target_rva) {
87*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign4;
88*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
89*a03ca8b9SKrzysztof Kosiński     return false;
90*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp;
91*a03ca8b9SKrzysztof Kosiński   ArmAlign target_align = DecodeA24(code32, &disp);
92*a03ca8b9SKrzysztof Kosiński   if (target_align == kArmAlignFail)
93*a03ca8b9SKrzysztof Kosiński     return false;
94*a03ca8b9SKrzysztof Kosiński   *target_rva = GetArmTargetRvaFromDisp(instr_rva, disp, target_align);
95*a03ca8b9SKrzysztof Kosiński   return true;
96*a03ca8b9SKrzysztof Kosiński }
97*a03ca8b9SKrzysztof Kosiński 
98*a03ca8b9SKrzysztof Kosiński // static
WriteA24(rva_t instr_rva,rva_t target_rva,uint32_t * code32)99*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::WriteA24(rva_t instr_rva,
100*a03ca8b9SKrzysztof Kosiński                                       rva_t target_rva,
101*a03ca8b9SKrzysztof Kosiński                                       uint32_t* code32) {
102*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign4;
103*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
104*a03ca8b9SKrzysztof Kosiński     return false;
105*a03ca8b9SKrzysztof Kosiński   // Dummy decode to get |target_align|.
106*a03ca8b9SKrzysztof Kosiński   arm_disp_t dummy_disp;
107*a03ca8b9SKrzysztof Kosiński   ArmAlign target_align = DecodeA24(*code32, &dummy_disp);
108*a03ca8b9SKrzysztof Kosiński   if (target_align == kArmAlignFail || IsMisaligned(target_rva, target_align))
109*a03ca8b9SKrzysztof Kosiński     return false;
110*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp =
111*a03ca8b9SKrzysztof Kosiński       GetArmDispFromTargetRva(instr_rva, target_rva, target_align);
112*a03ca8b9SKrzysztof Kosiński   return EncodeA24(disp, code32);
113*a03ca8b9SKrzysztof Kosiński }
114*a03ca8b9SKrzysztof Kosiński 
115*a03ca8b9SKrzysztof Kosiński // static
DecodeT8(uint16_t code16,arm_disp_t * disp)116*a03ca8b9SKrzysztof Kosiński ArmAlign AArch32Rel32Translator::DecodeT8(uint16_t code16, arm_disp_t* disp) {
117*a03ca8b9SKrzysztof Kosiński   if ((code16 & 0xF000) == 0xD000 && (code16 & 0x0F00) != 0x0F00) {
118*a03ca8b9SKrzysztof Kosiński     // B encoding T1:
119*a03ca8b9SKrzysztof Kosiński     //   Code:         1101cccc Siiiiiii
120*a03ca8b9SKrzysztof Kosiński     //   Displacement: SSSSSSSS SSSSSSSS SSSSSSSS iiiiiii0
121*a03ca8b9SKrzysztof Kosiński     *disp = GetSignedBits<0, 7>(code16) << 1;
122*a03ca8b9SKrzysztof Kosiński     return kArmAlign2;
123*a03ca8b9SKrzysztof Kosiński   }
124*a03ca8b9SKrzysztof Kosiński   return kArmAlignFail;
125*a03ca8b9SKrzysztof Kosiński }
126*a03ca8b9SKrzysztof Kosiński 
127*a03ca8b9SKrzysztof Kosiński // static
EncodeT8(arm_disp_t disp,uint16_t * code16)128*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::EncodeT8(arm_disp_t disp, uint16_t* code16) {
129*a03ca8b9SKrzysztof Kosiński   uint16_t t = *code16;
130*a03ca8b9SKrzysztof Kosiński   if ((t & 0xF000) == 0xD000 && (t & 0x0F00) != 0x0F00) {
131*a03ca8b9SKrzysztof Kosiński     if (disp % 2)  // Require 2-byte alignment.
132*a03ca8b9SKrzysztof Kosiński       return false;
133*a03ca8b9SKrzysztof Kosiński     if (!SignedFit<9>(disp))  // Detect overflow.
134*a03ca8b9SKrzysztof Kosiński       return false;
135*a03ca8b9SKrzysztof Kosiński     t = (t & 0xFF00) | ((disp >> 1) & 0x00FF);
136*a03ca8b9SKrzysztof Kosiński     *code16 = t;
137*a03ca8b9SKrzysztof Kosiński     return true;
138*a03ca8b9SKrzysztof Kosiński   }
139*a03ca8b9SKrzysztof Kosiński   return false;
140*a03ca8b9SKrzysztof Kosiński }
141*a03ca8b9SKrzysztof Kosiński 
142*a03ca8b9SKrzysztof Kosiński // static
ReadT8(rva_t instr_rva,uint16_t code16,rva_t * target_rva)143*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::ReadT8(rva_t instr_rva,
144*a03ca8b9SKrzysztof Kosiński                                     uint16_t code16,
145*a03ca8b9SKrzysztof Kosiński                                     rva_t* target_rva) {
146*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign2;
147*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
148*a03ca8b9SKrzysztof Kosiński     return false;
149*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp;
150*a03ca8b9SKrzysztof Kosiński   ArmAlign target_align = DecodeT8(code16, &disp);
151*a03ca8b9SKrzysztof Kosiński   if (target_align == kArmAlignFail)
152*a03ca8b9SKrzysztof Kosiński     return false;
153*a03ca8b9SKrzysztof Kosiński   *target_rva = GetThumb2TargetRvaFromDisp(instr_rva, disp, target_align);
154*a03ca8b9SKrzysztof Kosiński   return true;
155*a03ca8b9SKrzysztof Kosiński }
156*a03ca8b9SKrzysztof Kosiński 
157*a03ca8b9SKrzysztof Kosiński // static
WriteT8(rva_t instr_rva,rva_t target_rva,uint16_t * code16)158*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::WriteT8(rva_t instr_rva,
159*a03ca8b9SKrzysztof Kosiński                                      rva_t target_rva,
160*a03ca8b9SKrzysztof Kosiński                                      uint16_t* code16) {
161*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign2;
162*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kTargetAlign = kArmAlign2;
163*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign) ||
164*a03ca8b9SKrzysztof Kosiński       IsMisaligned(target_rva, kTargetAlign)) {
165*a03ca8b9SKrzysztof Kosiński     return false;
166*a03ca8b9SKrzysztof Kosiński   }
167*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp =
168*a03ca8b9SKrzysztof Kosiński       GetThumb2DispFromTargetRva(instr_rva, target_rva, kTargetAlign);
169*a03ca8b9SKrzysztof Kosiński   return EncodeT8(disp, code16);
170*a03ca8b9SKrzysztof Kosiński }
171*a03ca8b9SKrzysztof Kosiński 
172*a03ca8b9SKrzysztof Kosiński // static
DecodeT11(uint16_t code16,arm_disp_t * disp)173*a03ca8b9SKrzysztof Kosiński ArmAlign AArch32Rel32Translator::DecodeT11(uint16_t code16, arm_disp_t* disp) {
174*a03ca8b9SKrzysztof Kosiński   if ((code16 & 0xF800) == 0xE000) {
175*a03ca8b9SKrzysztof Kosiński     // B encoding T2:
176*a03ca8b9SKrzysztof Kosiński     //   Code:         11100Sii iiiiiiii
177*a03ca8b9SKrzysztof Kosiński     //   Displacement: SSSSSSSS SSSSSSSS SSSSSiii iiiiiii0
178*a03ca8b9SKrzysztof Kosiński     *disp = GetSignedBits<0, 10>(code16) << 1;
179*a03ca8b9SKrzysztof Kosiński     return kArmAlign2;
180*a03ca8b9SKrzysztof Kosiński   }
181*a03ca8b9SKrzysztof Kosiński   return kArmAlignFail;
182*a03ca8b9SKrzysztof Kosiński }
183*a03ca8b9SKrzysztof Kosiński 
184*a03ca8b9SKrzysztof Kosiński // static
EncodeT11(arm_disp_t disp,uint16_t * code16)185*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::EncodeT11(arm_disp_t disp, uint16_t* code16) {
186*a03ca8b9SKrzysztof Kosiński   uint16_t t = *code16;
187*a03ca8b9SKrzysztof Kosiński   if ((t & 0xF800) == 0xE000) {
188*a03ca8b9SKrzysztof Kosiński     if (disp % 2)  // Require 2-byte alignment.
189*a03ca8b9SKrzysztof Kosiński       return false;
190*a03ca8b9SKrzysztof Kosiński     if (!SignedFit<12>(disp))  // Detect overflow.
191*a03ca8b9SKrzysztof Kosiński       return false;
192*a03ca8b9SKrzysztof Kosiński     t = (t & 0xF800) | ((disp >> 1) & 0x07FF);
193*a03ca8b9SKrzysztof Kosiński     *code16 = t;
194*a03ca8b9SKrzysztof Kosiński     return true;
195*a03ca8b9SKrzysztof Kosiński   }
196*a03ca8b9SKrzysztof Kosiński   return false;
197*a03ca8b9SKrzysztof Kosiński }
198*a03ca8b9SKrzysztof Kosiński 
199*a03ca8b9SKrzysztof Kosiński // static
ReadT11(rva_t instr_rva,uint16_t code16,rva_t * target_rva)200*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::ReadT11(rva_t instr_rva,
201*a03ca8b9SKrzysztof Kosiński                                      uint16_t code16,
202*a03ca8b9SKrzysztof Kosiński                                      rva_t* target_rva) {
203*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign2;
204*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
205*a03ca8b9SKrzysztof Kosiński     return false;
206*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp;
207*a03ca8b9SKrzysztof Kosiński   ArmAlign target_align = DecodeT11(code16, &disp);
208*a03ca8b9SKrzysztof Kosiński   if (target_align == kArmAlignFail)
209*a03ca8b9SKrzysztof Kosiński     return false;
210*a03ca8b9SKrzysztof Kosiński   *target_rva = GetThumb2TargetRvaFromDisp(instr_rva, disp, target_align);
211*a03ca8b9SKrzysztof Kosiński   return true;
212*a03ca8b9SKrzysztof Kosiński }
213*a03ca8b9SKrzysztof Kosiński 
214*a03ca8b9SKrzysztof Kosiński // static
WriteT11(rva_t instr_rva,rva_t target_rva,uint16_t * code16)215*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::WriteT11(rva_t instr_rva,
216*a03ca8b9SKrzysztof Kosiński                                       rva_t target_rva,
217*a03ca8b9SKrzysztof Kosiński                                       uint16_t* code16) {
218*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign2;
219*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kTargetAlign = kArmAlign2;
220*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign) ||
221*a03ca8b9SKrzysztof Kosiński       IsMisaligned(target_rva, kTargetAlign)) {
222*a03ca8b9SKrzysztof Kosiński     return false;
223*a03ca8b9SKrzysztof Kosiński   }
224*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp =
225*a03ca8b9SKrzysztof Kosiński       GetThumb2DispFromTargetRva(instr_rva, target_rva, kTargetAlign);
226*a03ca8b9SKrzysztof Kosiński   return EncodeT11(disp, code16);
227*a03ca8b9SKrzysztof Kosiński }
228*a03ca8b9SKrzysztof Kosiński 
229*a03ca8b9SKrzysztof Kosiński // static
DecodeT20(uint32_t code32,arm_disp_t * disp)230*a03ca8b9SKrzysztof Kosiński ArmAlign AArch32Rel32Translator::DecodeT20(uint32_t code32, arm_disp_t* disp) {
231*a03ca8b9SKrzysztof Kosiński   if ((code32 & 0xF800D000) == 0xF0008000 &&
232*a03ca8b9SKrzysztof Kosiński       (code32 & 0x03C00000) != 0x03C00000) {
233*a03ca8b9SKrzysztof Kosiński     // B encoding T3. Note the reversal of "(J1)" and "(J2)".
234*a03ca8b9SKrzysztof Kosiński     //   Code:         11110Scc cciiiiii 10(J1)0(J2)jjj jjjjjjjj
235*a03ca8b9SKrzysztof Kosiński     //   Displacement: SSSSSSSS SSSS(J2)(J1)ii iiiijjjj jjjjjjj0
236*a03ca8b9SKrzysztof Kosiński     uint32_t imm11 = GetUnsignedBits<0, 10>(code32);  // jj...j.
237*a03ca8b9SKrzysztof Kosiński     uint32_t J2 = GetBit<11>(code32);
238*a03ca8b9SKrzysztof Kosiński     uint32_t J1 = GetBit<13>(code32);
239*a03ca8b9SKrzysztof Kosiński     uint32_t imm6 = GetUnsignedBits<16, 21>(code32);  // ii...i.
240*a03ca8b9SKrzysztof Kosiński     uint32_t S = GetBit<26>(code32);
241*a03ca8b9SKrzysztof Kosiński     uint32_t t = (imm6 << 12) | (imm11 << 1);
242*a03ca8b9SKrzysztof Kosiński     t |= (S << 20) | (J2 << 19) | (J1 << 18);
243*a03ca8b9SKrzysztof Kosiński     *disp = SignExtend<20, int32_t>(t);
244*a03ca8b9SKrzysztof Kosiński     return kArmAlign2;
245*a03ca8b9SKrzysztof Kosiński   }
246*a03ca8b9SKrzysztof Kosiński   return kArmAlignFail;
247*a03ca8b9SKrzysztof Kosiński }
248*a03ca8b9SKrzysztof Kosiński 
249*a03ca8b9SKrzysztof Kosiński // static
EncodeT20(arm_disp_t disp,uint32_t * code32)250*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::EncodeT20(arm_disp_t disp, uint32_t* code32) {
251*a03ca8b9SKrzysztof Kosiński   uint32_t t = *code32;
252*a03ca8b9SKrzysztof Kosiński   if ((t & 0xF800D000) == 0xF0008000 && (t & 0x03C00000) != 0x03C00000) {
253*a03ca8b9SKrzysztof Kosiński     if (disp % 2)  // Require 2-byte alignment.
254*a03ca8b9SKrzysztof Kosiński       return false;
255*a03ca8b9SKrzysztof Kosiński     if (!SignedFit<21>(disp))  // Detect overflow.
256*a03ca8b9SKrzysztof Kosiński       return false;
257*a03ca8b9SKrzysztof Kosiński     uint32_t S = GetBit<20>(disp);
258*a03ca8b9SKrzysztof Kosiński     uint32_t J2 = GetBit<19>(disp);
259*a03ca8b9SKrzysztof Kosiński     uint32_t J1 = GetBit<18>(disp);
260*a03ca8b9SKrzysztof Kosiński     uint32_t imm6 = GetUnsignedBits<12, 17>(disp);  // ii...i.
261*a03ca8b9SKrzysztof Kosiński     uint32_t imm11 = GetUnsignedBits<1, 11>(disp);  // jj...j.
262*a03ca8b9SKrzysztof Kosiński     t &= 0xFBC0D000;
263*a03ca8b9SKrzysztof Kosiński     t |= (S << 26) | (imm6 << 16) | (J1 << 13) | (J2 << 11) | imm11;
264*a03ca8b9SKrzysztof Kosiński     *code32 = t;
265*a03ca8b9SKrzysztof Kosiński     return true;
266*a03ca8b9SKrzysztof Kosiński   }
267*a03ca8b9SKrzysztof Kosiński   return false;
268*a03ca8b9SKrzysztof Kosiński }
269*a03ca8b9SKrzysztof Kosiński 
270*a03ca8b9SKrzysztof Kosiński // static
ReadT20(rva_t instr_rva,uint32_t code32,rva_t * target_rva)271*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::ReadT20(rva_t instr_rva,
272*a03ca8b9SKrzysztof Kosiński                                      uint32_t code32,
273*a03ca8b9SKrzysztof Kosiński                                      rva_t* target_rva) {
274*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign2;
275*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
276*a03ca8b9SKrzysztof Kosiński     return false;
277*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp;
278*a03ca8b9SKrzysztof Kosiński   ArmAlign target_align = DecodeT20(code32, &disp);
279*a03ca8b9SKrzysztof Kosiński   if (target_align == kArmAlignFail)
280*a03ca8b9SKrzysztof Kosiński     return false;
281*a03ca8b9SKrzysztof Kosiński   *target_rva = GetThumb2TargetRvaFromDisp(instr_rva, disp, target_align);
282*a03ca8b9SKrzysztof Kosiński   return true;
283*a03ca8b9SKrzysztof Kosiński }
284*a03ca8b9SKrzysztof Kosiński 
285*a03ca8b9SKrzysztof Kosiński // static
WriteT20(rva_t instr_rva,rva_t target_rva,uint32_t * code32)286*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::WriteT20(rva_t instr_rva,
287*a03ca8b9SKrzysztof Kosiński                                       rva_t target_rva,
288*a03ca8b9SKrzysztof Kosiński                                       uint32_t* code32) {
289*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign2;
290*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kTargetAlign = kArmAlign2;
291*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign) ||
292*a03ca8b9SKrzysztof Kosiński       IsMisaligned(target_rva, kTargetAlign)) {
293*a03ca8b9SKrzysztof Kosiński     return false;
294*a03ca8b9SKrzysztof Kosiński   }
295*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp =
296*a03ca8b9SKrzysztof Kosiński       GetThumb2DispFromTargetRva(instr_rva, target_rva, kTargetAlign);
297*a03ca8b9SKrzysztof Kosiński   return EncodeT20(disp, code32);
298*a03ca8b9SKrzysztof Kosiński }
299*a03ca8b9SKrzysztof Kosiński 
300*a03ca8b9SKrzysztof Kosiński // static
DecodeT24(uint32_t code32,arm_disp_t * disp)301*a03ca8b9SKrzysztof Kosiński ArmAlign AArch32Rel32Translator::DecodeT24(uint32_t code32, arm_disp_t* disp) {
302*a03ca8b9SKrzysztof Kosiński   uint32_t bits = code32 & 0xF800D000;
303*a03ca8b9SKrzysztof Kosiński   if (bits == 0xF0009000 || bits == 0xF000D000 || bits == 0xF000C000) {
304*a03ca8b9SKrzysztof Kosiński     // Let I1 = J1 ^ S ^ 1, I2 = J2 ^ S ^ 1.
305*a03ca8b9SKrzysztof Kosiński     // B encoding T4:
306*a03ca8b9SKrzysztof Kosiński     //   Code:         11110Sii iiiiiiii 10(J1)1(J2)jjj jjjjjjjj
307*a03ca8b9SKrzysztof Kosiński     //   Displacement: SSSSSSSS (I1)(I2)iiiiii iiiijjjj jjjjjjj0
308*a03ca8b9SKrzysztof Kosiński     // BL encoding T1:
309*a03ca8b9SKrzysztof Kosiński     //   Code:         11110Sii iiiiiiii 11(J1)1(J2)jjj jjjjjjjj
310*a03ca8b9SKrzysztof Kosiński     //   Displacement: SSSSSSSS (I1)(I2)iiiiii iiiijjjj jjjjjjj0
311*a03ca8b9SKrzysztof Kosiński     // BLX encoding T2: H should be 0:
312*a03ca8b9SKrzysztof Kosiński     //   Code:         11110Sii iiiiiiii 11(J1)0(J2)jjj jjjjjjjH
313*a03ca8b9SKrzysztof Kosiński     //   Displacement: SSSSSSSS (I1)(I2)iiiiii iiiijjjj jjjjjjH0
314*a03ca8b9SKrzysztof Kosiński     uint32_t imm11 = GetUnsignedBits<0, 10>(code32);  // jj...j.
315*a03ca8b9SKrzysztof Kosiński     uint32_t J2 = GetBit<11>(code32);
316*a03ca8b9SKrzysztof Kosiński     uint32_t J1 = GetBit<13>(code32);
317*a03ca8b9SKrzysztof Kosiński     uint32_t imm10 = GetUnsignedBits<16, 25>(code32);  // ii...i.
318*a03ca8b9SKrzysztof Kosiński     uint32_t S = GetBit<26>(code32);
319*a03ca8b9SKrzysztof Kosiński     uint32_t t = (imm10 << 12) | (imm11 << 1);
320*a03ca8b9SKrzysztof Kosiński     t |= (S << 24) | ((J1 ^ S ^ 1) << 23) | ((J2 ^ S ^ 1) << 22);
321*a03ca8b9SKrzysztof Kosiński     t = SignExtend<24, int32_t>(t);
322*a03ca8b9SKrzysztof Kosiński     // BLX encoding T2 requires final target to be 4-byte aligned by rounding
323*a03ca8b9SKrzysztof Kosiński     // downward. This is applied to |t| *after* clipping.
324*a03ca8b9SKrzysztof Kosiński     ArmAlign target_align = kArmAlign2;
325*a03ca8b9SKrzysztof Kosiński     if (bits == 0xF000C000) {
326*a03ca8b9SKrzysztof Kosiński       uint32_t H = GetBit<0>(code32);
327*a03ca8b9SKrzysztof Kosiński       if (H)
328*a03ca8b9SKrzysztof Kosiński         return kArmAlignFail;  // Illegal instruction: H must be 0.
329*a03ca8b9SKrzysztof Kosiński       target_align = kArmAlign4;
330*a03ca8b9SKrzysztof Kosiński     }
331*a03ca8b9SKrzysztof Kosiński     *disp = static_cast<int32_t>(t);
332*a03ca8b9SKrzysztof Kosiński     return target_align;
333*a03ca8b9SKrzysztof Kosiński   }
334*a03ca8b9SKrzysztof Kosiński   return kArmAlignFail;
335*a03ca8b9SKrzysztof Kosiński }
336*a03ca8b9SKrzysztof Kosiński 
337*a03ca8b9SKrzysztof Kosiński // static
EncodeT24(arm_disp_t disp,uint32_t * code32)338*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::EncodeT24(arm_disp_t disp, uint32_t* code32) {
339*a03ca8b9SKrzysztof Kosiński   uint32_t t = *code32;
340*a03ca8b9SKrzysztof Kosiński   uint32_t bits = t & 0xF800D000;
341*a03ca8b9SKrzysztof Kosiński   if (bits == 0xF0009000 || bits == 0xF000D000 || bits == 0xF000C000) {
342*a03ca8b9SKrzysztof Kosiński     if (disp % 2)  // Require 2-byte alignment.
343*a03ca8b9SKrzysztof Kosiński       return false;
344*a03ca8b9SKrzysztof Kosiński     // BLX encoding T2 requires H == 0, and that |disp| results in |target_rva|
345*a03ca8b9SKrzysztof Kosiński     // with a 4-byte aligned address.
346*a03ca8b9SKrzysztof Kosiński     if (bits == 0xF000C000) {
347*a03ca8b9SKrzysztof Kosiński       uint32_t H = GetBit<1>(disp);
348*a03ca8b9SKrzysztof Kosiński       if (H)
349*a03ca8b9SKrzysztof Kosiński         return false;  // Illegal |disp|: H must be 0.
350*a03ca8b9SKrzysztof Kosiński     }
351*a03ca8b9SKrzysztof Kosiński     if (!SignedFit<25>(disp))  // Detect overflow.
352*a03ca8b9SKrzysztof Kosiński       return false;
353*a03ca8b9SKrzysztof Kosiński     uint32_t imm11 = GetUnsignedBits<1, 11>(disp);   // jj...j.
354*a03ca8b9SKrzysztof Kosiński     uint32_t imm10 = GetUnsignedBits<12, 21>(disp);  // ii...i.
355*a03ca8b9SKrzysztof Kosiński     uint32_t I2 = GetBit<22>(disp);
356*a03ca8b9SKrzysztof Kosiński     uint32_t I1 = GetBit<23>(disp);
357*a03ca8b9SKrzysztof Kosiński     uint32_t S = GetBit<24>(disp);
358*a03ca8b9SKrzysztof Kosiński     t &= 0xF800D000;
359*a03ca8b9SKrzysztof Kosiński     t |= (S << 26) | (imm10 << 16) | ((I1 ^ S ^ 1) << 13) |
360*a03ca8b9SKrzysztof Kosiński          ((I2 ^ S ^ 1) << 11) | imm11;
361*a03ca8b9SKrzysztof Kosiński     *code32 = t;
362*a03ca8b9SKrzysztof Kosiński     return true;
363*a03ca8b9SKrzysztof Kosiński   }
364*a03ca8b9SKrzysztof Kosiński   return false;
365*a03ca8b9SKrzysztof Kosiński }
366*a03ca8b9SKrzysztof Kosiński 
367*a03ca8b9SKrzysztof Kosiński // static
ReadT24(rva_t instr_rva,uint32_t code32,rva_t * target_rva)368*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::ReadT24(rva_t instr_rva,
369*a03ca8b9SKrzysztof Kosiński                                      uint32_t code32,
370*a03ca8b9SKrzysztof Kosiński                                      rva_t* target_rva) {
371*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign2;
372*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
373*a03ca8b9SKrzysztof Kosiński     return false;
374*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp;
375*a03ca8b9SKrzysztof Kosiński   ArmAlign target_align = DecodeT24(code32, &disp);
376*a03ca8b9SKrzysztof Kosiński   if (target_align == kArmAlignFail)
377*a03ca8b9SKrzysztof Kosiński     return false;
378*a03ca8b9SKrzysztof Kosiński   *target_rva = GetThumb2TargetRvaFromDisp(instr_rva, disp, target_align);
379*a03ca8b9SKrzysztof Kosiński   return true;
380*a03ca8b9SKrzysztof Kosiński }
381*a03ca8b9SKrzysztof Kosiński 
382*a03ca8b9SKrzysztof Kosiński // static
WriteT24(rva_t instr_rva,rva_t target_rva,uint32_t * code32)383*a03ca8b9SKrzysztof Kosiński bool AArch32Rel32Translator::WriteT24(rva_t instr_rva,
384*a03ca8b9SKrzysztof Kosiński                                       rva_t target_rva,
385*a03ca8b9SKrzysztof Kosiński                                       uint32_t* code32) {
386*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign2;
387*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
388*a03ca8b9SKrzysztof Kosiński     return false;
389*a03ca8b9SKrzysztof Kosiński   // Dummy decode to get |target_align|.
390*a03ca8b9SKrzysztof Kosiński   arm_disp_t dummy_disp;
391*a03ca8b9SKrzysztof Kosiński   ArmAlign target_align = DecodeT24(*code32, &dummy_disp);
392*a03ca8b9SKrzysztof Kosiński   if (target_align == kArmAlignFail || IsMisaligned(target_rva, target_align))
393*a03ca8b9SKrzysztof Kosiński     return false;
394*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp =
395*a03ca8b9SKrzysztof Kosiński       GetThumb2DispFromTargetRva(instr_rva, target_rva, target_align);
396*a03ca8b9SKrzysztof Kosiński   return EncodeT24(disp, code32);
397*a03ca8b9SKrzysztof Kosiński }
398*a03ca8b9SKrzysztof Kosiński 
399*a03ca8b9SKrzysztof Kosiński /******** AArch64Rel32Translator ********/
400*a03ca8b9SKrzysztof Kosiński 
401*a03ca8b9SKrzysztof Kosiński AArch64Rel32Translator::AArch64Rel32Translator() = default;
402*a03ca8b9SKrzysztof Kosiński 
403*a03ca8b9SKrzysztof Kosiński // static
DecodeImmd14(uint32_t code32,arm_disp_t * disp)404*a03ca8b9SKrzysztof Kosiński ArmAlign AArch64Rel32Translator::DecodeImmd14(uint32_t code32,
405*a03ca8b9SKrzysztof Kosiński                                               arm_disp_t* disp) {
406*a03ca8b9SKrzysztof Kosiński   // TBZ:
407*a03ca8b9SKrzysztof Kosiński   //   Code:         b0110110 bbbbbSii iiiiiiii iiittttt
408*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSSSS SSSSSSSS Siiiiiii iiiiii00
409*a03ca8b9SKrzysztof Kosiński   // TBNZ:
410*a03ca8b9SKrzysztof Kosiński   //   Code:         b0110111 bbbbbSii iiiiiiii iiittttt
411*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSSSS SSSSSSSS Siiiiiii iiiiii00
412*a03ca8b9SKrzysztof Kosiński   uint32_t bits = code32 & 0x7F000000;
413*a03ca8b9SKrzysztof Kosiński   if (bits == 0x36000000 || bits == 0x37000000) {
414*a03ca8b9SKrzysztof Kosiński     *disp = GetSignedBits<5, 18>(code32) << 2;
415*a03ca8b9SKrzysztof Kosiński     return kArmAlign4;
416*a03ca8b9SKrzysztof Kosiński   }
417*a03ca8b9SKrzysztof Kosiński   return kArmAlignFail;
418*a03ca8b9SKrzysztof Kosiński }
419*a03ca8b9SKrzysztof Kosiński 
420*a03ca8b9SKrzysztof Kosiński // static
EncodeImmd14(arm_disp_t disp,uint32_t * code32)421*a03ca8b9SKrzysztof Kosiński bool AArch64Rel32Translator::EncodeImmd14(arm_disp_t disp, uint32_t* code32) {
422*a03ca8b9SKrzysztof Kosiński   uint32_t t = *code32;
423*a03ca8b9SKrzysztof Kosiński   uint32_t bits = t & 0x7F000000;
424*a03ca8b9SKrzysztof Kosiński   if (bits == 0x36000000 || bits == 0x37000000) {
425*a03ca8b9SKrzysztof Kosiński     if (disp % 4)  // Require 4-byte alignment.
426*a03ca8b9SKrzysztof Kosiński       return false;
427*a03ca8b9SKrzysztof Kosiński     if (!SignedFit<16>(disp))  // Detect overflow.
428*a03ca8b9SKrzysztof Kosiński       return false;
429*a03ca8b9SKrzysztof Kosiński     uint32_t imm14 = GetUnsignedBits<2, 15>(disp);  // ii...i.
430*a03ca8b9SKrzysztof Kosiński     t &= 0xFFF8001F;
431*a03ca8b9SKrzysztof Kosiński     t |= imm14 << 5;
432*a03ca8b9SKrzysztof Kosiński     *code32 = t;
433*a03ca8b9SKrzysztof Kosiński     return true;
434*a03ca8b9SKrzysztof Kosiński   }
435*a03ca8b9SKrzysztof Kosiński   return false;
436*a03ca8b9SKrzysztof Kosiński }
437*a03ca8b9SKrzysztof Kosiński 
438*a03ca8b9SKrzysztof Kosiński // static
ReadImmd14(rva_t instr_rva,uint32_t code32,rva_t * target_rva)439*a03ca8b9SKrzysztof Kosiński bool AArch64Rel32Translator::ReadImmd14(rva_t instr_rva,
440*a03ca8b9SKrzysztof Kosiński                                         uint32_t code32,
441*a03ca8b9SKrzysztof Kosiński                                         rva_t* target_rva) {
442*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign4;
443*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
444*a03ca8b9SKrzysztof Kosiński     return false;
445*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp;
446*a03ca8b9SKrzysztof Kosiński   if (DecodeImmd14(code32, &disp) == kArmAlignFail)
447*a03ca8b9SKrzysztof Kosiński     return false;
448*a03ca8b9SKrzysztof Kosiński   *target_rva = GetTargetRvaFromDisp(instr_rva, disp);
449*a03ca8b9SKrzysztof Kosiński   return true;
450*a03ca8b9SKrzysztof Kosiński }
451*a03ca8b9SKrzysztof Kosiński 
452*a03ca8b9SKrzysztof Kosiński // static
WriteImmd14(rva_t instr_rva,rva_t target_rva,uint32_t * code32)453*a03ca8b9SKrzysztof Kosiński bool AArch64Rel32Translator::WriteImmd14(rva_t instr_rva,
454*a03ca8b9SKrzysztof Kosiński                                          rva_t target_rva,
455*a03ca8b9SKrzysztof Kosiński                                          uint32_t* code32) {
456*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign4;
457*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kTargetAlign = kArmAlign4;
458*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign) ||
459*a03ca8b9SKrzysztof Kosiński       IsMisaligned(target_rva, kTargetAlign)) {
460*a03ca8b9SKrzysztof Kosiński     return false;
461*a03ca8b9SKrzysztof Kosiński   }
462*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp = GetDispFromTargetRva(instr_rva, target_rva);
463*a03ca8b9SKrzysztof Kosiński   return EncodeImmd14(disp, code32);
464*a03ca8b9SKrzysztof Kosiński }
465*a03ca8b9SKrzysztof Kosiński 
466*a03ca8b9SKrzysztof Kosiński // static
DecodeImmd19(uint32_t code32,arm_disp_t * disp)467*a03ca8b9SKrzysztof Kosiński ArmAlign AArch64Rel32Translator::DecodeImmd19(uint32_t code32,
468*a03ca8b9SKrzysztof Kosiński                                               arm_disp_t* disp) {
469*a03ca8b9SKrzysztof Kosiński   // B.cond:
470*a03ca8b9SKrzysztof Kosiński   //   Code:         01010100 Siiiiiii iiiiiiii iii0cccc
471*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSSSS SSSSiiii iiiiiiii iiiiii00
472*a03ca8b9SKrzysztof Kosiński   // CBZ:
473*a03ca8b9SKrzysztof Kosiński   //   Code:         z0110100 Siiiiiii iiiiiiii iiittttt
474*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSSSS SSSSiiii iiiiiiii iiiiii00
475*a03ca8b9SKrzysztof Kosiński   // CBNZ:
476*a03ca8b9SKrzysztof Kosiński   //   Code:         z0110101 Siiiiiii iiiiiiii iiittttt
477*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSSSS SSSSiiii iiiiiiii iiiiii00
478*a03ca8b9SKrzysztof Kosiński   uint32_t bits1 = code32 & 0xFF000010;
479*a03ca8b9SKrzysztof Kosiński   uint32_t bits2 = code32 & 0x7F000000;
480*a03ca8b9SKrzysztof Kosiński   if (bits1 == 0x54000000 || bits2 == 0x34000000 || bits2 == 0x35000000) {
481*a03ca8b9SKrzysztof Kosiński     *disp = GetSignedBits<5, 23>(code32) << 2;
482*a03ca8b9SKrzysztof Kosiński     return kArmAlign4;
483*a03ca8b9SKrzysztof Kosiński   }
484*a03ca8b9SKrzysztof Kosiński   return kArmAlignFail;
485*a03ca8b9SKrzysztof Kosiński }
486*a03ca8b9SKrzysztof Kosiński 
487*a03ca8b9SKrzysztof Kosiński // static
EncodeImmd19(arm_disp_t disp,uint32_t * code32)488*a03ca8b9SKrzysztof Kosiński bool AArch64Rel32Translator::EncodeImmd19(arm_disp_t disp, uint32_t* code32) {
489*a03ca8b9SKrzysztof Kosiński   uint32_t t = *code32;
490*a03ca8b9SKrzysztof Kosiński   uint32_t bits1 = t & 0xFF000010;
491*a03ca8b9SKrzysztof Kosiński   uint32_t bits2 = t & 0x7F000000;
492*a03ca8b9SKrzysztof Kosiński   if (bits1 == 0x54000000 || bits2 == 0x34000000 || bits2 == 0x35000000) {
493*a03ca8b9SKrzysztof Kosiński     if (disp % 4)  // Require 4-byte alignment.
494*a03ca8b9SKrzysztof Kosiński       return false;
495*a03ca8b9SKrzysztof Kosiński     if (!SignedFit<21>(disp))  // Detect overflow.
496*a03ca8b9SKrzysztof Kosiński       return false;
497*a03ca8b9SKrzysztof Kosiński     uint32_t imm19 = GetUnsignedBits<2, 20>(disp);  // ii...i.
498*a03ca8b9SKrzysztof Kosiński     t &= 0xFF00001F;
499*a03ca8b9SKrzysztof Kosiński     t |= imm19 << 5;
500*a03ca8b9SKrzysztof Kosiński     *code32 = t;
501*a03ca8b9SKrzysztof Kosiński     return true;
502*a03ca8b9SKrzysztof Kosiński   }
503*a03ca8b9SKrzysztof Kosiński   return false;
504*a03ca8b9SKrzysztof Kosiński }
505*a03ca8b9SKrzysztof Kosiński 
506*a03ca8b9SKrzysztof Kosiński // static
ReadImmd19(rva_t instr_rva,uint32_t code32,rva_t * target_rva)507*a03ca8b9SKrzysztof Kosiński bool AArch64Rel32Translator::ReadImmd19(rva_t instr_rva,
508*a03ca8b9SKrzysztof Kosiński                                         uint32_t code32,
509*a03ca8b9SKrzysztof Kosiński                                         rva_t* target_rva) {
510*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign4;
511*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
512*a03ca8b9SKrzysztof Kosiński     return false;
513*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp;
514*a03ca8b9SKrzysztof Kosiński   if (DecodeImmd19(code32, &disp) == kArmAlignFail)
515*a03ca8b9SKrzysztof Kosiński     return false;
516*a03ca8b9SKrzysztof Kosiński   *target_rva = GetTargetRvaFromDisp(instr_rva, disp);
517*a03ca8b9SKrzysztof Kosiński   return true;
518*a03ca8b9SKrzysztof Kosiński }
519*a03ca8b9SKrzysztof Kosiński 
520*a03ca8b9SKrzysztof Kosiński // static
WriteImmd19(rva_t instr_rva,rva_t target_rva,uint32_t * code32)521*a03ca8b9SKrzysztof Kosiński bool AArch64Rel32Translator::WriteImmd19(rva_t instr_rva,
522*a03ca8b9SKrzysztof Kosiński                                          rva_t target_rva,
523*a03ca8b9SKrzysztof Kosiński                                          uint32_t* code32) {
524*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign4;
525*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kTargetAlign = kArmAlign4;
526*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign) ||
527*a03ca8b9SKrzysztof Kosiński       IsMisaligned(target_rva, kTargetAlign)) {
528*a03ca8b9SKrzysztof Kosiński     return false;
529*a03ca8b9SKrzysztof Kosiński   }
530*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp = GetDispFromTargetRva(instr_rva, target_rva);
531*a03ca8b9SKrzysztof Kosiński   return EncodeImmd19(disp, code32);
532*a03ca8b9SKrzysztof Kosiński }
533*a03ca8b9SKrzysztof Kosiński 
534*a03ca8b9SKrzysztof Kosiński // static
DecodeImmd26(uint32_t code32,arm_disp_t * disp)535*a03ca8b9SKrzysztof Kosiński ArmAlign AArch64Rel32Translator::DecodeImmd26(uint32_t code32,
536*a03ca8b9SKrzysztof Kosiński                                               arm_disp_t* disp) {
537*a03ca8b9SKrzysztof Kosiński   // B:
538*a03ca8b9SKrzysztof Kosiński   //   Code:         000101Si iiiiiiii iiiiiiii iiiiiiii
539*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSiii iiiiiiii iiiiiiii iiiiii00
540*a03ca8b9SKrzysztof Kosiński   // BL:
541*a03ca8b9SKrzysztof Kosiński   //   Code:         100101Si iiiiiiii iiiiiiii iiiiiiii
542*a03ca8b9SKrzysztof Kosiński   //   Displacement: SSSSSiii iiiiiiii iiiiiiii iiiiii00
543*a03ca8b9SKrzysztof Kosiński   uint32_t bits = code32 & 0xFC000000;
544*a03ca8b9SKrzysztof Kosiński   if (bits == 0x14000000 || bits == 0x94000000) {
545*a03ca8b9SKrzysztof Kosiński     *disp = GetSignedBits<0, 25>(code32) << 2;
546*a03ca8b9SKrzysztof Kosiński     return kArmAlign4;
547*a03ca8b9SKrzysztof Kosiński   }
548*a03ca8b9SKrzysztof Kosiński   return kArmAlignFail;
549*a03ca8b9SKrzysztof Kosiński }
550*a03ca8b9SKrzysztof Kosiński 
551*a03ca8b9SKrzysztof Kosiński // static
EncodeImmd26(arm_disp_t disp,uint32_t * code32)552*a03ca8b9SKrzysztof Kosiński bool AArch64Rel32Translator::EncodeImmd26(arm_disp_t disp, uint32_t* code32) {
553*a03ca8b9SKrzysztof Kosiński   uint32_t t = *code32;
554*a03ca8b9SKrzysztof Kosiński   uint32_t bits = t & 0xFC000000;
555*a03ca8b9SKrzysztof Kosiński   if (bits == 0x14000000 || bits == 0x94000000) {
556*a03ca8b9SKrzysztof Kosiński     if (disp % 4)  // Require 4-byte alignment.
557*a03ca8b9SKrzysztof Kosiński       return false;
558*a03ca8b9SKrzysztof Kosiński     if (!SignedFit<28>(disp))  // Detect overflow.
559*a03ca8b9SKrzysztof Kosiński       return false;
560*a03ca8b9SKrzysztof Kosiński     uint32_t imm26 = GetUnsignedBits<2, 27>(disp);  // ii...i.
561*a03ca8b9SKrzysztof Kosiński     t &= 0xFC000000;
562*a03ca8b9SKrzysztof Kosiński     t |= imm26;
563*a03ca8b9SKrzysztof Kosiński     *code32 = t;
564*a03ca8b9SKrzysztof Kosiński     return true;
565*a03ca8b9SKrzysztof Kosiński   }
566*a03ca8b9SKrzysztof Kosiński   return false;
567*a03ca8b9SKrzysztof Kosiński }
568*a03ca8b9SKrzysztof Kosiński 
569*a03ca8b9SKrzysztof Kosiński // static
ReadImmd26(rva_t instr_rva,uint32_t code32,rva_t * target_rva)570*a03ca8b9SKrzysztof Kosiński bool AArch64Rel32Translator::ReadImmd26(rva_t instr_rva,
571*a03ca8b9SKrzysztof Kosiński                                         uint32_t code32,
572*a03ca8b9SKrzysztof Kosiński                                         rva_t* target_rva) {
573*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign4;
574*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign))
575*a03ca8b9SKrzysztof Kosiński     return false;
576*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp;
577*a03ca8b9SKrzysztof Kosiński   if (DecodeImmd26(code32, &disp) == kArmAlignFail)
578*a03ca8b9SKrzysztof Kosiński     return false;
579*a03ca8b9SKrzysztof Kosiński   *target_rva = GetTargetRvaFromDisp(instr_rva, disp);
580*a03ca8b9SKrzysztof Kosiński   return true;
581*a03ca8b9SKrzysztof Kosiński }
582*a03ca8b9SKrzysztof Kosiński 
583*a03ca8b9SKrzysztof Kosiński // static
WriteImmd26(rva_t instr_rva,rva_t target_rva,uint32_t * code32)584*a03ca8b9SKrzysztof Kosiński bool AArch64Rel32Translator::WriteImmd26(rva_t instr_rva,
585*a03ca8b9SKrzysztof Kosiński                                          rva_t target_rva,
586*a03ca8b9SKrzysztof Kosiński                                          uint32_t* code32) {
587*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kInstrAlign = kArmAlign4;
588*a03ca8b9SKrzysztof Kosiński   constexpr ArmAlign kTargetAlign = kArmAlign4;
589*a03ca8b9SKrzysztof Kosiński   if (IsMisaligned(instr_rva, kInstrAlign) ||
590*a03ca8b9SKrzysztof Kosiński       IsMisaligned(target_rva, kTargetAlign)) {
591*a03ca8b9SKrzysztof Kosiński     return false;
592*a03ca8b9SKrzysztof Kosiński   }
593*a03ca8b9SKrzysztof Kosiński   arm_disp_t disp = GetDispFromTargetRva(instr_rva, target_rva);
594*a03ca8b9SKrzysztof Kosiński   return EncodeImmd26(disp, code32);
595*a03ca8b9SKrzysztof Kosiński }
596*a03ca8b9SKrzysztof Kosiński 
597*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
598