xref: /aosp_15_r20/external/zucchini/reloc_win32_unittest.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
1*a03ca8b9SKrzysztof Kosiński // Copyright 2017 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/reloc_win32.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include <stdint.h>
8*a03ca8b9SKrzysztof Kosiński 
9*a03ca8b9SKrzysztof Kosiński #include <algorithm>
10*a03ca8b9SKrzysztof Kosiński #include <memory>
11*a03ca8b9SKrzysztof Kosiński #include <string>
12*a03ca8b9SKrzysztof Kosiński #include <utility>
13*a03ca8b9SKrzysztof Kosiński #include <vector>
14*a03ca8b9SKrzysztof Kosiński 
15*a03ca8b9SKrzysztof Kosiński #include "base/numerics/safe_conversions.h"
16*a03ca8b9SKrzysztof Kosiński #include "base/test/gtest_util.h"
17*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/address_translator.h"
18*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/algorithm.h"
19*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/image_utils.h"
20*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/test_utils.h"
21*a03ca8b9SKrzysztof Kosiński #include "testing/gtest/include/gtest/gtest.h"
22*a03ca8b9SKrzysztof Kosiński 
23*a03ca8b9SKrzysztof Kosiński namespace zucchini {
24*a03ca8b9SKrzysztof Kosiński 
25*a03ca8b9SKrzysztof Kosiński class RelocUtilsWin32Test : public testing::Test {
26*a03ca8b9SKrzysztof Kosiński  protected:
27*a03ca8b9SKrzysztof Kosiński   using Units = std::vector<RelocUnitWin32>;
28*a03ca8b9SKrzysztof Kosiński 
RelocUtilsWin32Test()29*a03ca8b9SKrzysztof Kosiński   RelocUtilsWin32Test() {}
30*a03ca8b9SKrzysztof Kosiński 
31*a03ca8b9SKrzysztof Kosiński   // Resets all tester data, calls RelocRvaReaderWin32::FindRelocBlocks(), and
32*a03ca8b9SKrzysztof Kosiński   // returns its results.
Initialize(const std::vector<uint8_t> & image_raw,BufferRegion reloc_region)33*a03ca8b9SKrzysztof Kosiński   bool Initialize(const std::vector<uint8_t>& image_raw,
34*a03ca8b9SKrzysztof Kosiński                   BufferRegion reloc_region) {
35*a03ca8b9SKrzysztof Kosiński     image_ = BufferSource(image_raw.data(), image_raw.size());
36*a03ca8b9SKrzysztof Kosiński     reloc_region_ = reloc_region;
37*a03ca8b9SKrzysztof Kosiński     return RelocRvaReaderWin32::FindRelocBlocks(image_, reloc_region_,
38*a03ca8b9SKrzysztof Kosiński                                                 &reloc_block_offsets_);
39*a03ca8b9SKrzysztof Kosiński   }
40*a03ca8b9SKrzysztof Kosiński 
41*a03ca8b9SKrzysztof Kosiński   // Uses RelocRvaReaderWin32 to get all relocs, returned as Units.
EmitAll(offset_t lo,offset_t hi)42*a03ca8b9SKrzysztof Kosiński   Units EmitAll(offset_t lo, offset_t hi) {
43*a03ca8b9SKrzysztof Kosiński     RelocRvaReaderWin32 reader(image_, reloc_region_, reloc_block_offsets_, lo,
44*a03ca8b9SKrzysztof Kosiński                                hi);
45*a03ca8b9SKrzysztof Kosiński     Units units;
46*a03ca8b9SKrzysztof Kosiński     for (auto unit = reader.GetNext(); unit.has_value();
47*a03ca8b9SKrzysztof Kosiński          unit = reader.GetNext()) {
48*a03ca8b9SKrzysztof Kosiński       units.push_back(unit.value());
49*a03ca8b9SKrzysztof Kosiński     }
50*a03ca8b9SKrzysztof Kosiński     return units;
51*a03ca8b9SKrzysztof Kosiński   }
52*a03ca8b9SKrzysztof Kosiński 
53*a03ca8b9SKrzysztof Kosiński   ConstBufferView image_;
54*a03ca8b9SKrzysztof Kosiński   BufferRegion reloc_region_;
55*a03ca8b9SKrzysztof Kosiński   std::vector<uint32_t> reloc_block_offsets_;
56*a03ca8b9SKrzysztof Kosiński };
57*a03ca8b9SKrzysztof Kosiński 
TEST_F(RelocUtilsWin32Test,RvaReaderEmpty)58*a03ca8b9SKrzysztof Kosiński TEST_F(RelocUtilsWin32Test, RvaReaderEmpty) {
59*a03ca8b9SKrzysztof Kosiński   {
60*a03ca8b9SKrzysztof Kosiński     std::vector<uint8_t> image_raw = ParseHexString("");
61*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(Initialize(image_raw, {0U, 0U}));
62*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(std::vector<uint32_t>(), reloc_block_offsets_);  // Nothing.
63*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(Units(), EmitAll(0U, 0U));
64*a03ca8b9SKrzysztof Kosiński   }
65*a03ca8b9SKrzysztof Kosiński   {
66*a03ca8b9SKrzysztof Kosiński     std::vector<uint8_t> image_raw = ParseHexString("AA BB CC DD EE FF");
67*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(Initialize(image_raw, {2U, 0U}));
68*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(std::vector<uint32_t>(), reloc_block_offsets_);  // Nothing.
69*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(Units(), EmitAll(2U, 2U));
70*a03ca8b9SKrzysztof Kosiński   }
71*a03ca8b9SKrzysztof Kosiński   {
72*a03ca8b9SKrzysztof Kosiński     std::vector<uint8_t> image_raw = ParseHexString("00 C0 00 00 08 00 00 00");
73*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(Initialize(image_raw, {0U, image_raw.size()}));
74*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(std::vector<uint32_t>({0U}),
75*a03ca8b9SKrzysztof Kosiński               reloc_block_offsets_);  // Empty block.
76*a03ca8b9SKrzysztof Kosiński     EXPECT_EQ(Units(), EmitAll(0U, 8U));
77*a03ca8b9SKrzysztof Kosiński   }
78*a03ca8b9SKrzysztof Kosiński }
79*a03ca8b9SKrzysztof Kosiński 
TEST_F(RelocUtilsWin32Test,RvaReaderBad)80*a03ca8b9SKrzysztof Kosiński TEST_F(RelocUtilsWin32Test, RvaReaderBad) {
81*a03ca8b9SKrzysztof Kosiński   std::string test_cases[] = {
82*a03ca8b9SKrzysztof Kosiński       "00 C0 00 00 07 00 00",           // Header too small.
83*a03ca8b9SKrzysztof Kosiński       "00 C0 00 00 08 00 00",           // Header too small, lies about size.
84*a03ca8b9SKrzysztof Kosiński       "00 C0 00 00 0A 00 00 00 66 31",  // Odd number of units.
85*a03ca8b9SKrzysztof Kosiński       "00 C0 00 00 0C 00 00 00 66 31 88 31 FF",  // Trailing data.
86*a03ca8b9SKrzysztof Kosiński   };
87*a03ca8b9SKrzysztof Kosiński   for (const std::string& test_case : test_cases) {
88*a03ca8b9SKrzysztof Kosiński     std::vector<uint8_t> image_raw = ParseHexString(test_case);
89*a03ca8b9SKrzysztof Kosiński     EXPECT_FALSE(Initialize(image_raw, {0U, image_raw.size()}));
90*a03ca8b9SKrzysztof Kosiński   }
91*a03ca8b9SKrzysztof Kosiński }
92*a03ca8b9SKrzysztof Kosiński 
TEST_F(RelocUtilsWin32Test,RvaReaderSingle)93*a03ca8b9SKrzysztof Kosiński TEST_F(RelocUtilsWin32Test, RvaReaderSingle) {
94*a03ca8b9SKrzysztof Kosiński   // Block 0: All type 0x3: {0xC166, 0xC288, 0xC342, (padding) 0xCFFF}.
95*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> image_raw = ParseHexString(
96*a03ca8b9SKrzysztof Kosiński       "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF "
97*a03ca8b9SKrzysztof Kosiński       "00 C0 00 00 10 00 00 00 66 31 88 32 42 33 FF 0F "
98*a03ca8b9SKrzysztof Kosiński       "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
99*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kBlock0 = 16U;
100*a03ca8b9SKrzysztof Kosiński   Units exp0 = {{3, kBlock0 + 8U, 0xC166U},
101*a03ca8b9SKrzysztof Kosiński                 {3, kBlock0 + 10U, 0xC288U},
102*a03ca8b9SKrzysztof Kosiński                 {3, kBlock0 + 12U, 0xC342U},
103*a03ca8b9SKrzysztof Kosiński                 {0, kBlock0 + 14U, 0xCFFFU}};
104*a03ca8b9SKrzysztof Kosiński 
105*a03ca8b9SKrzysztof Kosiński   EXPECT_TRUE(Initialize(image_raw, {16U, 16U}));
106*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp0, EmitAll(kBlock0, kBlock0 + 16U));
107*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0));
108*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0 + 8U));
109*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0 + 9U));
110*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp0, 0, 1), EmitAll(kBlock0, kBlock0 + 10U));
111*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp0, 0, 1), EmitAll(kBlock0 + 8U, kBlock0 + 10U));
112*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlock0 + 9U, kBlock0 + 10U));
113*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp0, 0, 3), EmitAll(kBlock0, kBlock0 + 15U));
114*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp0, 2, 3), EmitAll(kBlock0 + 11U, kBlock0 + 15U));
115*a03ca8b9SKrzysztof Kosiński }
116*a03ca8b9SKrzysztof Kosiński 
TEST_F(RelocUtilsWin32Test,RvaReaderMulti)117*a03ca8b9SKrzysztof Kosiński TEST_F(RelocUtilsWin32Test, RvaReaderMulti) {
118*a03ca8b9SKrzysztof Kosiński   // The sample image encodes 3 reloc blocks:
119*a03ca8b9SKrzysztof Kosiński   // Block 0: All type 0x3: {0xC166, 0xC288, 0xC344, (padding) 0xCFFF}.
120*a03ca8b9SKrzysztof Kosiński   // Block 1: All type 0x3: {0x12166, 0x12288}.
121*a03ca8b9SKrzysztof Kosiński   // Block 2: All type 0xA: {0x24000, 0x24010, 0x24020, 0x24028, 0x24A3C,
122*a03ca8b9SKrzysztof Kosiński   //                         0x24170}.
123*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> image_raw = ParseHexString(
124*a03ca8b9SKrzysztof Kosiński       "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF "
125*a03ca8b9SKrzysztof Kosiński       "00 C0 00 00 10 00 00 00 66 31 88 32 42 33 FF 0F "
126*a03ca8b9SKrzysztof Kosiński       "00 20 01 00 0C 00 00 00 66 31 88 32 "
127*a03ca8b9SKrzysztof Kosiński       "00 40 02 00 14 00 00 00 00 A0 10 A0 20 A0 28 A0 3C A0 70 A1 "
128*a03ca8b9SKrzysztof Kosiński       "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
129*a03ca8b9SKrzysztof Kosiński   offset_t image_size = base::checked_cast<offset_t>(image_raw.size());
130*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kBlock0 = 16U;
131*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kBlock1 = kBlock0 + 16U;
132*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kBlock2 = kBlock1 + 12U;
133*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kBlockEnd = kBlock2 + 20U;
134*a03ca8b9SKrzysztof Kosiński   Units exp0 = {{3, kBlock0 + 8U, 0xC166U},
135*a03ca8b9SKrzysztof Kosiński                 {3, kBlock0 + 10U, 0xC288U},
136*a03ca8b9SKrzysztof Kosiński                 {3, kBlock0 + 12U, 0xC342U},
137*a03ca8b9SKrzysztof Kosiński                 {0, kBlock0 + 14U, 0xCFFFU}};
138*a03ca8b9SKrzysztof Kosiński   Units exp1 = {{3, kBlock0 + 24U, 0x12166U}, {3, kBlock0 + 26U, 0x12288U}};
139*a03ca8b9SKrzysztof Kosiński   Units exp2 = {{10, kBlock0 + 36U, 0x24000U}, {10, kBlock0 + 38U, 0x24010U},
140*a03ca8b9SKrzysztof Kosiński                 {10, kBlock0 + 40U, 0x24020U}, {10, kBlock0 + 42U, 0x24028U},
141*a03ca8b9SKrzysztof Kosiński                 {10, kBlock0 + 44U, 0x2403CU}, {10, kBlock0 + 46U, 0x24170U}};
142*a03ca8b9SKrzysztof Kosiński 
143*a03ca8b9SKrzysztof Kosiński   EXPECT_TRUE(Initialize(image_raw, {kBlock0, kBlockEnd - kBlock0}));
144*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(std::vector<uint32_t>({kBlock0, kBlock1, kBlock2}),
145*a03ca8b9SKrzysztof Kosiński             reloc_block_offsets_);
146*a03ca8b9SKrzysztof Kosiński 
147*a03ca8b9SKrzysztof Kosiński   // Everything.
148*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Cat(Cat(exp0, exp1), exp2), EmitAll(kBlock0, kBlockEnd));
149*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Cat(Cat(exp0, exp1), exp2), EmitAll(0, image_size));
150*a03ca8b9SKrzysztof Kosiński   // Entire blocks.
151*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp0, EmitAll(kBlock0, kBlock1));
152*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp1, EmitAll(kBlock1, kBlock2));
153*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp2, EmitAll(kBlock2, kBlockEnd));
154*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(0, kBlock0));
155*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlockEnd, image_size));
156*a03ca8b9SKrzysztof Kosiński   // Within blocks, clipped at boundaries.
157*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp0, EmitAll(kBlock0 + 5U, kBlock1));
158*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp0, EmitAll(kBlock0 + 8U, kBlock1));
159*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp0, 1, 4), EmitAll(kBlock0 + 9U, kBlock1));
160*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp0, 0, 3), EmitAll(kBlock0, kBlock0 + 15U));
161*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp0, 0, 3), EmitAll(kBlock0, kBlock0 + 14U));
162*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp0, 0, 1), EmitAll(kBlock0 + 8U, kBlock0 + 10U));
163*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp1, 1, 2), EmitAll(kBlock1 + 10U, kBlock1 + 12U));
164*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp2, 2, 4), EmitAll(kBlock2 + 12U, kBlock2 + 16U));
165*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0));
166*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0 + 8U));
167*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlock2 + 10U, kBlock2 + 11U));
168*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlock2 + 11U, kBlock2 + 12U));
169*a03ca8b9SKrzysztof Kosiński   // Across blocks.
170*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Cat(Cat(exp0, exp1), exp2), EmitAll(kBlock0 - 5U, kBlockEnd));
171*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Cat(Cat(exp0, exp1), exp2), EmitAll(kBlock0 + 6U, kBlockEnd));
172*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Cat(Cat(exp0, exp1), Sub(exp2, 0, 5)),
173*a03ca8b9SKrzysztof Kosiński             EmitAll(kBlock0 + 6U, kBlock2 + 18U));
174*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Cat(Sub(exp0, 2, 4), Sub(exp1, 0, 1)),
175*a03ca8b9SKrzysztof Kosiński             EmitAll(kBlock0 + 12U, kBlock1 + 10U));
176*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Cat(Sub(exp0, 2, 4), Sub(exp1, 0, 1)),
177*a03ca8b9SKrzysztof Kosiński             EmitAll(kBlock0 + 11U, kBlock1 + 10U));
178*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Cat(Sub(exp0, 2, 4), Sub(exp1, 0, 1)),
179*a03ca8b9SKrzysztof Kosiński             EmitAll(kBlock0 + 12U, kBlock1 + 11U));
180*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Sub(exp1, 1, 2), EmitAll(kBlock1 + 10U, kBlock2 + 5U));
181*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Cat(Sub(exp1, 1, 2), exp2), EmitAll(kBlock1 + 10U, kBlockEnd + 5));
182*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(Units(), EmitAll(kBlock0 + 15, kBlock1 + 9));
183*a03ca8b9SKrzysztof Kosiński }
184*a03ca8b9SKrzysztof Kosiński 
TEST_F(RelocUtilsWin32Test,ReadWrite)185*a03ca8b9SKrzysztof Kosiński TEST_F(RelocUtilsWin32Test, ReadWrite) {
186*a03ca8b9SKrzysztof Kosiński   // Set up mock image: Size = 0x3000, .reloc at 0x600. RVA is 0x40000 + offset.
187*a03ca8b9SKrzysztof Kosiński   constexpr rva_t kBaseRva = 0x40000;
188*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> image_data(0x3000, 0xFF);
189*a03ca8b9SKrzysztof Kosiński   // 4 x86 relocs (xx 3x), 3 x64 relocs (xx Ax), 1 padding (xx 0X).
190*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> reloc_data = ParseHexString(
191*a03ca8b9SKrzysztof Kosiński       "00 10 04 00 10 00 00 00 C0 32 18 A3 F8 A7 FF 0F "
192*a03ca8b9SKrzysztof Kosiński       "00 20 04 00 10 00 00 00 80 A0 65 31 F8 37 BC 3A");
193*a03ca8b9SKrzysztof Kosiński   reloc_region_ = {0x600, reloc_data.size()};
194*a03ca8b9SKrzysztof Kosiński   std::copy(reloc_data.begin(), reloc_data.end(),
195*a03ca8b9SKrzysztof Kosiński             image_data.begin() + reloc_region_.lo());
196*a03ca8b9SKrzysztof Kosiński   image_ = {image_data.data(), image_data.size()};
197*a03ca8b9SKrzysztof Kosiński   offset_t image_size = base::checked_cast<offset_t>(image_.size());
198*a03ca8b9SKrzysztof Kosiński 
199*a03ca8b9SKrzysztof Kosiński   AddressTranslator translator;
200*a03ca8b9SKrzysztof Kosiński   translator.Initialize({{0, image_size, kBaseRva, image_size}});
201*a03ca8b9SKrzysztof Kosiński 
202*a03ca8b9SKrzysztof Kosiński   // Precompute |reloc_block_offsets_|.
203*a03ca8b9SKrzysztof Kosiński   EXPECT_TRUE(RelocRvaReaderWin32::FindRelocBlocks(image_, reloc_region_,
204*a03ca8b9SKrzysztof Kosiński                                                    &reloc_block_offsets_));
205*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(std::vector<uint32_t>({0x600U, 0x610U}), reloc_block_offsets_);
206*a03ca8b9SKrzysztof Kosiński 
207*a03ca8b9SKrzysztof Kosiński   // Focus on x86.
208*a03ca8b9SKrzysztof Kosiński   constexpr uint16_t kRelocTypeX86 = 3;
209*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kVAWidthX86 = 4;
210*a03ca8b9SKrzysztof Kosiński 
211*a03ca8b9SKrzysztof Kosiński   // Make RelocRvaReaderWin32.
212*a03ca8b9SKrzysztof Kosiński   RelocRvaReaderWin32 reloc_rva_reader(image_, reloc_region_,
213*a03ca8b9SKrzysztof Kosiński                                        reloc_block_offsets_, 0, image_size);
214*a03ca8b9SKrzysztof Kosiński   offset_t offset_bound = image_size - kVAWidthX86 + 1;
215*a03ca8b9SKrzysztof Kosiński 
216*a03ca8b9SKrzysztof Kosiński   // Make RelocReaderWin32 that wraps |reloc_rva_reader|.
217*a03ca8b9SKrzysztof Kosiński   auto reader = std::make_unique<RelocReaderWin32>(
218*a03ca8b9SKrzysztof Kosiński       std::move(reloc_rva_reader), kRelocTypeX86, offset_bound, translator);
219*a03ca8b9SKrzysztof Kosiński 
220*a03ca8b9SKrzysztof Kosiński   // Read all references and check.
221*a03ca8b9SKrzysztof Kosiński   std::vector<Reference> refs;
222*a03ca8b9SKrzysztof Kosiński   for (std::optional<Reference> ref = reader->GetNext(); ref.has_value();
223*a03ca8b9SKrzysztof Kosiński        ref = reader->GetNext()) {
224*a03ca8b9SKrzysztof Kosiński     refs.push_back(ref.value());
225*a03ca8b9SKrzysztof Kosiński   }
226*a03ca8b9SKrzysztof Kosiński   std::vector<Reference> exp_refs{
227*a03ca8b9SKrzysztof Kosiński       {0x608, 0x12C0}, {0x61A, 0x2165}, {0x61C, 0x27F8}, {0x61E, 0x2ABC}};
228*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp_refs, refs);
229*a03ca8b9SKrzysztof Kosiński 
230*a03ca8b9SKrzysztof Kosiński   // Write reference, extract bytes and check.
231*a03ca8b9SKrzysztof Kosiński   MutableBufferView mutable_image(&image_data[0], image_data.size());
232*a03ca8b9SKrzysztof Kosiński   auto writer = std::make_unique<RelocWriterWin32>(
233*a03ca8b9SKrzysztof Kosiński       kRelocTypeX86, mutable_image, reloc_region_, reloc_block_offsets_,
234*a03ca8b9SKrzysztof Kosiński       translator);
235*a03ca8b9SKrzysztof Kosiński 
236*a03ca8b9SKrzysztof Kosiński   writer->PutNext({0x608, 0x1F83});
237*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> exp_reloc_data1 = ParseHexString(
238*a03ca8b9SKrzysztof Kosiński       "00 10 04 00 10 00 00 00 83 3F 18 A3 F8 A7 FF 0F "
239*a03ca8b9SKrzysztof Kosiński       "00 20 04 00 10 00 00 00 80 A0 65 31 F8 37 BC 3A");
240*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp_reloc_data1,
241*a03ca8b9SKrzysztof Kosiński             Sub(image_data, reloc_region_.lo(), reloc_region_.hi()));
242*a03ca8b9SKrzysztof Kosiński 
243*a03ca8b9SKrzysztof Kosiński   writer->PutNext({0x61C, 0x2950});
244*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> exp_reloc_data2 = ParseHexString(
245*a03ca8b9SKrzysztof Kosiński       "00 10 04 00 10 00 00 00 83 3F 18 A3 F8 A7 FF 0F "
246*a03ca8b9SKrzysztof Kosiński       "00 20 04 00 10 00 00 00 80 A0 65 31 50 39 BC 3A");
247*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp_reloc_data2,
248*a03ca8b9SKrzysztof Kosiński             Sub(image_data, reloc_region_.lo(), reloc_region_.hi()));
249*a03ca8b9SKrzysztof Kosiński }
250*a03ca8b9SKrzysztof Kosiński 
251*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
252