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