1 // Copyright 2017 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/rel32_utils.h"
6
7 #include <stdint.h>
8
9 #include <deque>
10 #include <memory>
11 #include <optional>
12 #include <utility>
13 #include <vector>
14
15 #include "base/test/gtest_util.h"
16 #include "components/zucchini/address_translator.h"
17 #include "components/zucchini/arm_utils.h"
18 #include "components/zucchini/image_utils.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace zucchini {
22
23 namespace {
24
25 // A trivial AddressTranslator that applies constant shift.
26 class TestAddressTranslator : public AddressTranslator {
27 public:
TestAddressTranslator(offset_t image_size,rva_t rva_begin)28 TestAddressTranslator(offset_t image_size, rva_t rva_begin) {
29 DCHECK_GE(rva_begin, 0U);
30 CHECK_EQ(AddressTranslator::kSuccess,
31 Initialize({{0, image_size, rva_begin, image_size}}));
32 }
33 };
34
35 // Checks that |reader| emits and only emits |expected_refs|, in order.
CheckReader(const std::vector<Reference> & expected_refs,std::unique_ptr<ReferenceReader> reader)36 void CheckReader(const std::vector<Reference>& expected_refs,
37 std::unique_ptr<ReferenceReader> reader) {
38 for (Reference expected_ref : expected_refs) {
39 auto ref = reader->GetNext();
40 EXPECT_TRUE(ref.has_value());
41 EXPECT_EQ(expected_ref, ref.value());
42 }
43 EXPECT_EQ(std::nullopt, reader->GetNext()); // Nothing should be left.
44 }
45
46 // Copies displacements from |bytes1| to |bytes2| and checks results against
47 // |bytes_exp_1_to_2|. Then repeats for |*bytes2| , |*byte1|, and
48 // |bytes_exp_2_to_1|. Empty expected bytes mean failure is expected. The copy
49 // function is specified by |copier|.
CheckCopy(const std::vector<uint8_t> & bytes_exp_1_to_2,const std::vector<uint8_t> & bytes_exp_2_to_1,const std::vector<uint8_t> & bytes1,const std::vector<uint8_t> & bytes2,ArmCopyDispFun copier)50 void CheckCopy(const std::vector<uint8_t>& bytes_exp_1_to_2,
51 const std::vector<uint8_t>& bytes_exp_2_to_1,
52 const std::vector<uint8_t>& bytes1,
53 const std::vector<uint8_t>& bytes2,
54 ArmCopyDispFun copier) {
55 auto run_test = [&copier](const std::vector<uint8_t>& bytes_exp,
56 const std::vector<uint8_t>& bytes_in,
57 std::vector<uint8_t> bytes_out) {
58 ConstBufferView buffer_in(&bytes_in[0], bytes_in.size());
59 MutableBufferView buffer_out(&bytes_out[0], bytes_out.size());
60 if (bytes_exp.empty()) {
61 EXPECT_FALSE(copier(buffer_in, 0U, buffer_out, 0U));
62 } else {
63 EXPECT_TRUE(copier(buffer_in, 0U, buffer_out, 0U));
64 EXPECT_EQ(bytes_exp, bytes_out);
65 }
66 };
67 run_test(bytes_exp_1_to_2, bytes1, bytes2);
68 run_test(bytes_exp_2_to_1, bytes2, bytes1);
69 }
70
71 } // namespace
72
TEST(Rel32UtilsTest,Rel32ReaderX86)73 TEST(Rel32UtilsTest, Rel32ReaderX86) {
74 constexpr offset_t kTestImageSize = 0x00100000U;
75 constexpr rva_t kRvaBegin = 0x00030000U;
76 TestAddressTranslator translator(kTestImageSize, kRvaBegin);
77
78 // For simplicity, test data is not real X86 machine code. We are only
79 // including rel32 targets, without the full instructions.
80 std::vector<uint8_t> bytes = {
81 0xFF, 0xFF, 0xFF, 0xFF, // 00030000: (Filler)
82 0xFF, 0xFF, 0xFF, 0xFF, // 0003000C: (Filler)
83 0x04, 0x00, 0x00, 0x00, // 00030008: 00030010
84 0xFF, 0xFF, 0xFF, 0xFF, // 0003000C: (Filler)
85 0x00, 0x00, 0x00, 0x00, // 00030010: 00030014
86 0xFF, 0xFF, 0xFF, 0xFF, // 00030014: (Filler)
87 0xF4, 0xFF, 0xFF, 0xFF, // 00030018: 00030010
88 0xE4, 0xFF, 0xFF, 0xFF, // 0003001C: 00030004
89 };
90 ConstBufferView buffer(bytes.data(), bytes.size());
91 // Specify rel32 locations directly, instead of parsing.
92 std::deque<offset_t> rel32_locations = {0x0008U, 0x0010U, 0x0018U, 0x001CU};
93
94 // Generate everything.
95 auto reader1 = std::make_unique<Rel32ReaderX86>(buffer, 0x0000U, 0x0020U,
96 &rel32_locations, translator);
97 CheckReader({{0x0008U, 0x0010U},
98 {0x0010U, 0x0014U},
99 {0x0018U, 0x0010U},
100 {0x001CU, 0x0004U}},
101 std::move(reader1));
102
103 // Exclude last.
104 auto reader2 = std::make_unique<Rel32ReaderX86>(buffer, 0x0000U, 0x001CU,
105 &rel32_locations, translator);
106 CheckReader({{0x0008U, 0x0010U}, {0x0010U, 0x0014U}, {0x0018U, 0x0010U}},
107 std::move(reader2));
108
109 // Only find one.
110 auto reader3 = std::make_unique<Rel32ReaderX86>(buffer, 0x000CU, 0x0018U,
111 &rel32_locations, translator);
112 CheckReader({{0x0010U, 0x0014U}}, std::move(reader3));
113 }
114
TEST(Rel32UtilsTest,Rel32WriterX86)115 TEST(Rel32UtilsTest, Rel32WriterX86) {
116 constexpr offset_t kTestImageSize = 0x00100000U;
117 constexpr rva_t kRvaBegin = 0x00030000U;
118 TestAddressTranslator translator(kTestImageSize, kRvaBegin);
119
120 std::vector<uint8_t> bytes(32, 0xFF);
121 MutableBufferView buffer(bytes.data(), bytes.size());
122
123 Rel32WriterX86 writer(buffer, translator);
124 writer.PutNext({0x0008U, 0x0010U});
125 EXPECT_EQ(0x00000004U, buffer.read<uint32_t>(0x08)); // 00030008: 00030010
126
127 writer.PutNext({0x0010U, 0x0014U});
128 EXPECT_EQ(0x00000000U, buffer.read<uint32_t>(0x10)); // 00030010: 00030014
129
130 writer.PutNext({0x0018U, 0x0010U});
131 EXPECT_EQ(0xFFFFFFF4U, buffer.read<uint32_t>(0x18)); // 00030018: 00030010
132
133 writer.PutNext({0x001CU, 0x0004U});
134 EXPECT_EQ(0xFFFFFFE4U, buffer.read<uint32_t>(0x1C)); // 0003001C: 00030004
135
136 EXPECT_EQ(std::vector<uint8_t>({
137 0xFF, 0xFF, 0xFF, 0xFF, // 00030000: (Filler)
138 0xFF, 0xFF, 0xFF, 0xFF, // 00030004: (Filler)
139 0x04, 0x00, 0x00, 0x00, // 00030008: 00030010
140 0xFF, 0xFF, 0xFF, 0xFF, // 0003000C: (Filler)
141 0x00, 0x00, 0x00, 0x00, // 00030010: 00030014
142 0xFF, 0xFF, 0xFF, 0xFF, // 00030014: (Filler)
143 0xF4, 0xFF, 0xFF, 0xFF, // 00030018: 00030010
144 0xE4, 0xFF, 0xFF, 0xFF, // 0003001C: 00030004
145 }),
146 bytes);
147 }
148
TEST(Rel32UtilsTest,Rel32ReaderArm_AArch32)149 TEST(Rel32UtilsTest, Rel32ReaderArm_AArch32) {
150 constexpr offset_t kTestImageSize = 0x00100000U;
151 constexpr rva_t kRvaBegin = 0x00030000U;
152 TestAddressTranslator translator(kTestImageSize, kRvaBegin);
153
154 // A24.
155 std::vector<uint8_t> bytes = {
156 0xFF, 0xFF, 0xFF, 0xFF, // 00030000: (Filler)
157 0xFF, 0xFF, 0xFF, 0xFF, // 00030004: (Filler)
158 0x00, 0x00, 0x00, 0xEA, // 00030008: B 00030010 ; A24
159 0xFF, 0xFF, 0xFF, 0xFF, // 0003000C: (Filler)
160 0xFF, 0xFF, 0xFF, 0xEB, // 00030010: BL 00030014 ; A24
161 0xFF, 0xFF, 0xFF, 0xFF, // 00030014: (Filler)
162 0xFC, 0xFF, 0xFF, 0xEB, // 00030018: BL 00030010 ; A24
163 0xF8, 0xFF, 0xFF, 0xEA, // 0003001C: B 00030004 ; A24
164 };
165 ConstBufferView region(&bytes[0], bytes.size());
166 // Specify rel32 locations directly, instead of parsing.
167 std::deque<offset_t> rel32_locations_A24 = {0x0008U, 0x0010U, 0x0018U,
168 0x001CU};
169
170 // Generate everything.
171 auto reader1 =
172 std::make_unique<Rel32ReaderArm<AArch32Rel32Translator::AddrTraits_A24>>(
173 translator, region, rel32_locations_A24, 0x0000U, 0x0020U);
174 CheckReader({{0x0008U, 0x0010U},
175 {0x0010U, 0x0014U},
176 {0x0018U, 0x0010U},
177 {0x001CU, 0x0004U}},
178 std::move(reader1));
179
180 // Exclude last.
181 auto reader2 =
182 std::make_unique<Rel32ReaderArm<AArch32Rel32Translator::AddrTraits_A24>>(
183 translator, region, rel32_locations_A24, 0x0000U, 0x001CU);
184 CheckReader({{0x0008U, 0x0010U}, {0x0010U, 0x0014U}, {0x0018U, 0x0010U}},
185 std::move(reader2));
186
187 // Only find one.
188 auto reader3 =
189 std::make_unique<Rel32ReaderArm<AArch32Rel32Translator::AddrTraits_A24>>(
190 translator, region, rel32_locations_A24, 0x000CU, 0x0018U);
191 CheckReader({{0x0010U, 0x0014U}}, std::move(reader3));
192 }
193
TEST(Rel32UtilsTest,Rel32WriterArm_AArch32_Easy)194 TEST(Rel32UtilsTest, Rel32WriterArm_AArch32_Easy) {
195 constexpr offset_t kTestImageSize = 0x00100000U;
196 constexpr rva_t kRvaBegin = 0x00030000U;
197 TestAddressTranslator translator(kTestImageSize, kRvaBegin);
198
199 std::vector<uint8_t> bytes = {
200 0xFF, 0xFF, // 00030000: (Filler)
201 0x01, 0xDE, // 00030002: B 00030008 ; T8
202 0xFF, 0xFF, 0xFF, 0xFF, // 00030004: (Filler)
203 0x01, 0xE0, // 00030008: B 0003000E ; T11
204 0xFF, 0xFF, // 0003000A: (Filler)
205 0x80, 0xF3, 0x00, 0x80, // 0003000C: B 00030010 ; T20
206 };
207 MutableBufferView region(&bytes[0], bytes.size());
208
209 auto writer1 =
210 std::make_unique<Rel32WriterArm<AArch32Rel32Translator::AddrTraits_T8>>(
211 translator, region);
212 writer1->PutNext({0x0002U, 0x0004U});
213 EXPECT_EQ(0xFF, bytes[0x02]); // 00030002: B 00030004 ; T8
214 EXPECT_EQ(0xDE, bytes[0x03]);
215
216 writer1->PutNext({0x0002U, 0x000AU});
217 EXPECT_EQ(0x02, bytes[0x02]); // 00030002: B 0003000A ; T8
218 EXPECT_EQ(0xDE, bytes[0x03]);
219
220 auto writer2 =
221 std::make_unique<Rel32WriterArm<AArch32Rel32Translator::AddrTraits_T11>>(
222 translator, region);
223 writer2->PutNext({0x0008U, 0x0008U});
224 EXPECT_EQ(0xFE, bytes[0x08]); // 00030008: B 00030008 ; T11
225 EXPECT_EQ(0xE7, bytes[0x09]);
226 writer2->PutNext({0x0008U, 0x0010U});
227 EXPECT_EQ(0x02, bytes[0x08]); // 00030008: B 00030010 ; T11
228 EXPECT_EQ(0xE0, bytes[0x09]);
229
230 auto writer3 =
231 std::make_unique<Rel32WriterArm<AArch32Rel32Translator::AddrTraits_T20>>(
232 translator, region);
233 writer3->PutNext({0x000CU, 0x000AU});
234 EXPECT_EQ(0xBF, bytes[0x0C]); // 0003000C: B 0003000A ; T20
235 EXPECT_EQ(0xF7, bytes[0x0D]);
236 EXPECT_EQ(0xFD, bytes[0x0E]);
237 EXPECT_EQ(0xAF, bytes[0x0F]);
238 writer3->PutNext({0x000CU, 0x0010U});
239 EXPECT_EQ(0x80, bytes[0x0C]); // 0003000C: B 00030010 ; T20
240 EXPECT_EQ(0xF3, bytes[0x0D]);
241 EXPECT_EQ(0x00, bytes[0x0E]);
242 EXPECT_EQ(0x80, bytes[0x0F]);
243 }
244
TEST(Rel32UtilsTest,Rel32WriterArm_AArch32_Hard)245 TEST(Rel32UtilsTest, Rel32WriterArm_AArch32_Hard) {
246 constexpr offset_t kTestImageSize = 0x10000000U;
247 constexpr rva_t kRvaBegin = 0x0C030000U;
248 TestAddressTranslator translator(kTestImageSize, kRvaBegin);
249
250 std::vector<uint8_t> bytes = {
251 0xFF, 0xFF, // 0C030000: (Filler)
252 0x00, 0xF0, 0x00, 0xB8, // 0C030002: B 0C030006 ; T24
253 0xFF, 0xFF, 0xFF, 0xFF, // 0C030006: (Filler)
254 0x00, 0xF0, 0x7A, 0xE8, // 0C03000A: BLX 0C030100 ; T24
255 0xFF, 0xFF, // 0C03000E: (Filler)
256 0x00, 0xF0, 0x7A, 0xE8, // 0C030010: BLX 0C030108 ; T24
257 };
258 MutableBufferView region(&bytes[0], bytes.size());
259
260 auto writer =
261 std::make_unique<Rel32WriterArm<AArch32Rel32Translator::AddrTraits_T24>>(
262 translator, region);
263 writer->PutNext({0x0002U, 0x0000U});
264 EXPECT_EQ(0xFF, bytes[0x02]); // 0C030002: B 0C030000 ; T24
265 EXPECT_EQ(0xF7, bytes[0x03]);
266 EXPECT_EQ(0xFD, bytes[0x04]);
267 EXPECT_EQ(0xBF, bytes[0x05]);
268 writer->PutNext({0x0002U, 0x0008U});
269 EXPECT_EQ(0x00, bytes[0x02]); // 0C030002: B 0C030008 ; T24
270 EXPECT_EQ(0xF0, bytes[0x03]);
271 EXPECT_EQ(0x01, bytes[0x04]);
272 EXPECT_EQ(0xB8, bytes[0x05]);
273
274 // BLX complication, with location that's not 4-byte aligned.
275 writer->PutNext({0x000AU, 0x0010U});
276 EXPECT_EQ(0x00, bytes[0x0A]); // 0C03000A: BLX 0C030010 ; T24
277 EXPECT_EQ(0xF0, bytes[0x0B]);
278 EXPECT_EQ(0x02, bytes[0x0C]);
279 EXPECT_EQ(0xE8, bytes[0x0D]);
280 writer->PutNext({0x000AU, 0x0100U});
281 EXPECT_EQ(0x00, bytes[0x0A]); // 0C03000A: BLX 0C030100 ; T24
282 EXPECT_EQ(0xF0, bytes[0x0B]);
283 EXPECT_EQ(0x7A, bytes[0x0C]);
284 EXPECT_EQ(0xE8, bytes[0x0D]);
285 writer->PutNext({0x000AU, 0x0000U});
286 EXPECT_EQ(0xFF, bytes[0x0A]); // 0C03000A: BLX 0C030000 ; T24
287 EXPECT_EQ(0xF7, bytes[0x0B]);
288 EXPECT_EQ(0xFA, bytes[0x0C]);
289 EXPECT_EQ(0xEF, bytes[0x0D]);
290
291 // BLX complication, with location that's 4-byte aligned.
292 writer->PutNext({0x0010U, 0x0010U});
293 EXPECT_EQ(0xFF, bytes[0x10]); // 0C030010: BLX 0C030010 ; T24
294 EXPECT_EQ(0xF7, bytes[0x11]);
295 EXPECT_EQ(0xFE, bytes[0x12]);
296 EXPECT_EQ(0xEF, bytes[0x13]);
297 writer->PutNext({0x0010U, 0x0108U});
298 EXPECT_EQ(0x00, bytes[0x10]); // 0C030010: BLX 0C030108 ; T24
299 EXPECT_EQ(0xF0, bytes[0x11]);
300 EXPECT_EQ(0x7A, bytes[0x12]);
301 EXPECT_EQ(0xE8, bytes[0x13]);
302 }
303
304 // Test BLX encoding A2, which is an ARM instruction that switches to THUMB2,
305 // and therefore should have 2-byte alignment.
TEST(Rel32UtilsTest,AArch32SwitchToThumb2)306 TEST(Rel32UtilsTest, AArch32SwitchToThumb2) {
307 constexpr offset_t kTestImageSize = 0x10000000U;
308 constexpr rva_t kRvaBegin = 0x08030000U;
309 TestAddressTranslator translator(kTestImageSize, kRvaBegin);
310
311 std::vector<uint8_t> bytes = {
312 0xFF, 0xFF, 0x00, 0x00, // 08030000: (Filler)
313 0x00, 0x00, 0x00, 0xFA, // 08030004: BLX 0803000C ; A24
314 };
315 MutableBufferView region(&bytes[0], bytes.size());
316
317 auto writer =
318 std::make_unique<Rel32WriterArm<AArch32Rel32Translator::AddrTraits_A24>>(
319 translator, region);
320
321 // To location that's 4-byte aligned.
322 writer->PutNext({0x0004U, 0x0100U});
323 EXPECT_EQ(0x3D, bytes[0x04]); // 08030004: BLX 08030100 ; A24
324 EXPECT_EQ(0x00, bytes[0x05]);
325 EXPECT_EQ(0x00, bytes[0x06]);
326 EXPECT_EQ(0xFA, bytes[0x07]);
327
328 // To location that's 2-byte aligned but not 4-byte aligned.
329 writer->PutNext({0x0004U, 0x0052U});
330 EXPECT_EQ(0x11, bytes[0x04]); // 08030004: BLX 08030052 ; A24
331 EXPECT_EQ(0x00, bytes[0x05]);
332 EXPECT_EQ(0x00, bytes[0x06]);
333 EXPECT_EQ(0xFB, bytes[0x07]);
334
335 // Clean slate code.
336 writer->PutNext({0x0004U, 0x000CU});
337 EXPECT_EQ(0x00, bytes[0x04]); // 08030004: BLX 0803000C ; A24
338 EXPECT_EQ(0x00, bytes[0x05]);
339 EXPECT_EQ(0x00, bytes[0x06]);
340 EXPECT_EQ(0xFA, bytes[0x07]);
341 }
342
TEST(Rel32UtilsTest,ArmCopyDisp_AArch32)343 TEST(Rel32UtilsTest, ArmCopyDisp_AArch32) {
344 std::vector<uint8_t> expect_fail;
345
346 // Successful A24.
347 ArmCopyDispFun copier_A24 =
348 ArmCopyDisp<AArch32Rel32Translator::AddrTraits_A24>;
349 CheckCopy({0x12, 0x34, 0x56, 0xEB}, // 00000100: BL 0158D150
350 {0xA0, 0xC0, 0x0E, 0x2A}, // 00000100: BCS 003B0388
351 {0x12, 0x34, 0x56, 0x2A}, // 00000100: BCS 0158D150
352 {0xA0, 0xC0, 0x0E, 0xEB}, // 00000100: BL 003B0388
353 copier_A24);
354
355 // Successful T8.
356 ArmCopyDispFun copier_T8 = ArmCopyDisp<AArch32Rel32Translator::AddrTraits_T8>;
357 CheckCopy({0x12, 0xD5}, // 00000100: BPL 00000128
358 {0xAB, 0xD8}, // 00000100: BHI 0000005A
359 {0x12, 0xD8}, // 00000100: BHI 00000128
360 {0xAB, 0xD5}, // 00000100: BPL 0000005A
361 copier_T8);
362
363 // Successful T11.
364 ArmCopyDispFun copier_T11 =
365 ArmCopyDisp<AArch32Rel32Translator::AddrTraits_T11>;
366 CheckCopy({0xF5, 0xE0}, // 00000100: B 000002EE
367 {0x12, 0xE7}, // 00000100: B FFFFFF28
368 {0xF5, 0xE0}, // 00000100: B 000002EE
369 {0x12, 0xE7}, // 00000100: B FFFFFF28
370 copier_T11);
371
372 // Failure if wrong copier is used.
373 CheckCopy(expect_fail, expect_fail, {0xF5, 0xE0}, {0x12, 0xE7}, copier_T8);
374
375 // Successful T20.
376 ArmCopyDispFun copier_T20 =
377 ArmCopyDisp<AArch32Rel32Translator::AddrTraits_T20>;
378 CheckCopy({0x41, 0xF2, 0xA5, 0x88}, // 00000100: BLS.W 0008124E
379 {0x04, 0xF3, 0x3C, 0xA2}, // 00000100: BGT.W 0004457C
380 {0x01, 0xF3, 0xA5, 0x88}, // 00000100: BGT.W 0008124E
381 {0x44, 0xF2, 0x3C, 0xA2}, // 00000100: BLS.W 0004457C
382 copier_T20);
383 CheckCopy({0x7F, 0xF6, 0xFF, 0xAF}, // 00000100: BLS.W 00000102
384 {0x00, 0xF3, 0x00, 0x80}, // 00000100: BGT.W 00000104
385 {0x3F, 0xF7, 0xFF, 0xAF}, // 00000100: BGT.W 00000102
386 {0x40, 0xF2, 0x00, 0x80}, // 00000100: BLS.W 00000104
387 copier_T20);
388
389 // Failure if wrong copier is used.
390 CheckCopy(expect_fail, expect_fail, {0x41, 0xF2, 0xA5, 0x88},
391 {0x84, 0xF3, 0x3C, 0xA2}, copier_A24);
392
393 // T24: Mix B encoding T4 and BL encoding T1.
394 ArmCopyDispFun copier_T24 =
395 ArmCopyDisp<AArch32Rel32Translator::AddrTraits_T24>;
396 CheckCopy({0xFF, 0xF7, 0xFF, 0xFF}, // 00000100: BL 00000102
397 {0x00, 0xF0, 0x00, 0x90}, // 00000100: B.W 00C00104
398 {0xFF, 0xF7, 0xFF, 0xBF}, // 00000100: B.W 00000102
399 {0x00, 0xF0, 0x00, 0xD0}, // 00000100: BL 00C00104
400 copier_T24);
401
402 // Mix B encoding T4 and BLX encoding T2. Note that the forward direction
403 // fails because B's target is invalid for BLX! It's possible to do "best
404 // effort" copying to reduce diff -- but right now we're not doing this.
405 CheckCopy(expect_fail, {0x00, 0xF0, 0x00, 0x90}, // 00000100: B.W 00C00104
406 {0xFF, 0xF7, 0xFF, 0xBF}, // 00000100: B.W 00000102
407 {0x00, 0xF0, 0x00, 0xC0}, // 00000100: BLX 00C00104
408 copier_T24);
409 // Success if ow B's target is valid for BLX.
410 CheckCopy({0xFF, 0xF7, 0xFE, 0xEF}, // 00000100: BLX 00000100
411 {0x00, 0xF0, 0x00, 0x90}, // 00000100: B.W 00C00104
412 {0xFF, 0xF7, 0xFE, 0xBF}, // 00000100: B.W 00000100
413 {0x00, 0xF0, 0x00, 0xC0}, // 00000100: BLX 00C00104
414 copier_T24);
415 }
416
TEST(Rel32UtilsTest,Rel32ReaderArm_AArch64)417 TEST(Rel32UtilsTest, Rel32ReaderArm_AArch64) {
418 constexpr offset_t kTestImageSize = 0x00100000U;
419 constexpr rva_t kRvaBegin = 0x00030000U;
420 TestAddressTranslator translator(kTestImageSize, kRvaBegin);
421
422 std::vector<uint8_t> bytes = {
423 0xFF, 0xFF, 0xFF, 0xFF, // 00030000: (Filler)
424 0xFF, 0xFF, 0xFF, 0xFF, // 00030004: (Filler)
425 0x02, 0x00, 0x00, 0x14, // 00030008: B 00030010 ; Immd26
426 0xFF, 0xFF, 0xFF, 0xFF, // 0003000C: (Filler)
427 0x25, 0x00, 0x00, 0x35, // 00030010: CBNZ R5,00030014 ; Immd19
428 0xFF, 0xFF, 0xFF, 0xFF, // 00030014: (Filler)
429 0xCA, 0xFF, 0xFF, 0x54, // 00030018: BGE 00030010 ; Immd19
430 0x4C, 0xFF, 0x8F, 0x36, // 0003001C: TBZ X12,#17,00030004 ; Immd14
431 };
432 MutableBufferView region(&bytes[0], bytes.size());
433
434 // Generate Immd26. We specify rel32 locations directly.
435 std::deque<offset_t> rel32_locations_Immd26 = {0x0008U};
436 auto reader1 = std::make_unique<
437 Rel32ReaderArm<AArch64Rel32Translator::AddrTraits_Immd26>>(
438 translator, region, rel32_locations_Immd26, 0x0000U, 0x0020U);
439 CheckReader({{0x0008U, 0x0010U}}, std::move(reader1));
440
441 // Generate Immd19.
442 std::deque<offset_t> rel32_locations_Immd19 = {0x0010U, 0x0018U};
443 auto reader2 = std::make_unique<
444 Rel32ReaderArm<AArch64Rel32Translator::AddrTraits_Immd19>>(
445 translator, region, rel32_locations_Immd19, 0x0000U, 0x0020U);
446 CheckReader({{0x0010U, 0x0014U}, {0x0018U, 0x0010U}}, std::move(reader2));
447
448 // Generate Immd14.
449 std::deque<offset_t> rel32_locations_Immd14 = {0x001CU};
450 auto reader3 = std::make_unique<
451 Rel32ReaderArm<AArch64Rel32Translator::AddrTraits_Immd14>>(
452 translator, region, rel32_locations_Immd14, 0x0000U, 0x0020U);
453 CheckReader({{0x001CU, 0x0004U}}, std::move(reader3));
454 }
455
TEST(Rel32UtilsTest,Rel32WriterArm_AArch64)456 TEST(Rel32UtilsTest, Rel32WriterArm_AArch64) {
457 constexpr offset_t kTestImageSize = 0x00100000U;
458 constexpr rva_t kRvaBegin = 0x00030000U;
459 TestAddressTranslator translator(kTestImageSize, kRvaBegin);
460
461 std::vector<uint8_t> bytes = {
462 0xFF, 0xFF, 0xFF, 0xFF, // 00030000: (Filler)
463 0xFF, 0xFF, 0xFF, 0xFF, // 00030004: (Filler)
464 0x02, 0x00, 0x00, 0x14, // 00030008: B 00030010 ; Immd26
465 0xFF, 0xFF, 0xFF, 0xFF, // 0003000C: (Filler)
466 0x25, 0x00, 0x00, 0x35, // 00030010: CBNZ R5,00030014 ; Immd19
467 0xFF, 0xFF, 0xFF, 0xFF, // 00030014: (Filler)
468 0xCA, 0xFF, 0xFF, 0x54, // 00030018: BGE 00030010 ; Immd19
469 0x4C, 0xFF, 0x8F, 0x36, // 0003001C: TBZ X12,#17,00030004 ; Immd14
470 };
471 MutableBufferView region(&bytes[0], bytes.size());
472
473 auto writer1 = std::make_unique<
474 Rel32WriterArm<AArch64Rel32Translator::AddrTraits_Immd26>>(translator,
475 region);
476 writer1->PutNext({0x0008U, 0x0000U});
477 EXPECT_EQ(0xFE, bytes[0x08]); // 00030008: B 00030000 ; Immd26
478 EXPECT_EQ(0xFF, bytes[0x09]);
479 EXPECT_EQ(0xFF, bytes[0x0A]);
480 EXPECT_EQ(0x17, bytes[0x0B]);
481
482 auto writer2 = std::make_unique<
483 Rel32WriterArm<AArch64Rel32Translator::AddrTraits_Immd19>>(translator,
484 region);
485 writer2->PutNext({0x0010U, 0x0000U});
486 EXPECT_EQ(0x85, bytes[0x10]); // 00030010: CBNZ R5,00030000 ; Immd19
487 EXPECT_EQ(0xFF, bytes[0x11]);
488 EXPECT_EQ(0xFF, bytes[0x12]);
489 EXPECT_EQ(0x35, bytes[0x13]);
490 writer2->PutNext({0x0018U, 0x001CU});
491 EXPECT_EQ(0x2A, bytes[0x18]); // 00030018: BGE 0003001C ; Immd19
492 EXPECT_EQ(0x00, bytes[0x19]);
493 EXPECT_EQ(0x00, bytes[0x1A]);
494 EXPECT_EQ(0x54, bytes[0x1B]);
495
496 auto writer3 = std::make_unique<
497 Rel32WriterArm<AArch64Rel32Translator::AddrTraits_Immd14>>(translator,
498 region);
499 writer3->PutNext({0x001CU, 0x0010U});
500 EXPECT_EQ(0xAC, bytes[0x1C]); // 0003001C: TBZ X12,#17,00030010 ; Immd14
501 EXPECT_EQ(0xFF, bytes[0x1D]);
502 EXPECT_EQ(0x8F, bytes[0x1E]);
503 EXPECT_EQ(0x36, bytes[0x1F]);
504 }
505
TEST(Rel32UtilsTest,ArmCopyDisp_AArch64)506 TEST(Rel32UtilsTest, ArmCopyDisp_AArch64) {
507 std::vector<uint8_t> expect_fail;
508
509 // Successful Imm26.
510 ArmCopyDispFun copier_Immd26 =
511 ArmCopyDisp<AArch64Rel32Translator::AddrTraits_Immd26>;
512 CheckCopy({0x12, 0x34, 0x56, 0x94}, // 00000100: BL 0158D148
513 {0xA1, 0xC0, 0x0E, 0x17}, // 00000100: B FC3B0384
514 {0x12, 0x34, 0x56, 0x14}, // 00000100: B 0158D148
515 {0xA1, 0xC0, 0x0E, 0x97}, // 00000100: BL FC3B0384
516 copier_Immd26);
517
518 // Successful Imm19.
519 ArmCopyDispFun copier_Immd19 =
520 ArmCopyDisp<AArch64Rel32Translator::AddrTraits_Immd19>;
521 CheckCopy({0x24, 0x12, 0x34, 0x54}, // 00000100: BMI 00068344
522 {0xD7, 0xA5, 0xFC, 0xB4}, // 00000100: CBZ X23,FFFF95B8
523 {0x37, 0x12, 0x34, 0xB4}, // 00000100: CBZ X23,00068344
524 {0xC4, 0xA5, 0xFC, 0x54}, // 00000100: BMI FFFF95B8
525 copier_Immd19);
526
527 // Successful Imm14.
528 ArmCopyDispFun copier_Immd14 =
529 ArmCopyDisp<AArch64Rel32Translator::AddrTraits_Immd14>;
530 CheckCopy({0x00, 0x00, 0x00, 0x36}, // 00000100: TBZ X0,#0,00000100
531 {0xFF, 0xFF, 0xFF, 0xB7}, // 00000100: TBNZ ZR,#63,000000FC
532 {0x1F, 0x00, 0xF8, 0xB7}, // 00000100: TBNZ ZR,#63,00000100
533 {0xE0, 0xFF, 0x07, 0x36}, // 00000100: TBZ X0,#0,000000FC
534 copier_Immd14);
535
536 // Failure if wrong copier is used.
537 CheckCopy(expect_fail, expect_fail, {0x1F, 0x00, 0xF8, 0xB7},
538 {0xE0, 0xFF, 0x07, 0x36}, copier_Immd26);
539 }
540
541 } // namespace zucchini
542