xref: /aosp_15_r20/external/zucchini/rel32_finder.h (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 #ifndef COMPONENTS_ZUCCHINI_REL32_FINDER_H_
6*a03ca8b9SKrzysztof Kosiński #define COMPONENTS_ZUCCHINI_REL32_FINDER_H_
7*a03ca8b9SKrzysztof Kosiński 
8*a03ca8b9SKrzysztof Kosiński #include <stddef.h>
9*a03ca8b9SKrzysztof Kosiński 
10*a03ca8b9SKrzysztof Kosiński #include <vector>
11*a03ca8b9SKrzysztof Kosiński 
12*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/address_translator.h"
13*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/arm_utils.h"
14*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_view.h"
15*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/image_utils.h"
16*a03ca8b9SKrzysztof Kosiński 
17*a03ca8b9SKrzysztof Kosiński namespace zucchini {
18*a03ca8b9SKrzysztof Kosiński 
19*a03ca8b9SKrzysztof Kosiński // See README.md for definitions on abs32 and rel32 references. The following
20*a03ca8b9SKrzysztof Kosiński // are assumed:
21*a03ca8b9SKrzysztof Kosiński // * Abs32 reference bodies have fixed widths.
22*a03ca8b9SKrzysztof Kosiński // * Rel32 locations can be identified by heuristically disassembling machine
23*a03ca8b9SKrzysztof Kosiński //   code, and errors are tolerated.
24*a03ca8b9SKrzysztof Kosiński // * The collection all abs32 and rel32 reference bodies do not overlap.
25*a03ca8b9SKrzysztof Kosiński 
26*a03ca8b9SKrzysztof Kosiński // A class to visit non-empty contiguous gaps in |region| that lie outside of
27*a03ca8b9SKrzysztof Kosiński // |abs32_locations| elements, each with a body that spans |abs32_width_| bytes.
28*a03ca8b9SKrzysztof Kosiński // For example, given:
29*a03ca8b9SKrzysztof Kosiński //   region = [base_ + 4, base_ + 26),
30*a03ca8b9SKrzysztof Kosiński //   abs32_locations = {2, 6, 15, 20, 27},
31*a03ca8b9SKrzysztof Kosiński //   abs32_width_ = 4,
32*a03ca8b9SKrzysztof Kosiński // the following is obtained:
33*a03ca8b9SKrzysztof Kosiński //             111111111122222222223   -> offsets
34*a03ca8b9SKrzysztof Kosiński //   0123456789012345678901234567890
35*a03ca8b9SKrzysztof Kosiński //   ....**********************.....   -> region = *
36*a03ca8b9SKrzysztof Kosiński //     ^   ^        ^    ^      ^      -> abs32 locations
37*a03ca8b9SKrzysztof Kosiński //     aaaaaaaa     aaaa aaaa   aaaa   -> abs32 bodies
38*a03ca8b9SKrzysztof Kosiński //   ....------*****----*----**.....   -> regions excluding abs32 -> 3 gaps
39*a03ca8b9SKrzysztof Kosiński // The resulting gaps (non-empty, so [6, 6) is excluded) are:
40*a03ca8b9SKrzysztof Kosiński //   [10, 15), [19, 20), [24, 26).
41*a03ca8b9SKrzysztof Kosiński // These gaps can then be passed to Rel32Finder (below) to find rel32 references
42*a03ca8b9SKrzysztof Kosiński // with bodies that are guaranteed to not overlap with any abs32 bodies.
43*a03ca8b9SKrzysztof Kosiński class Abs32GapFinder {
44*a03ca8b9SKrzysztof Kosiński  public:
45*a03ca8b9SKrzysztof Kosiński   // |abs32_locations| is a sorted list of non-overlapping abs32 locations in
46*a03ca8b9SKrzysztof Kosiński   // |image|, each spanning |abs32_width| bytes. Gaps are searched in |region|,
47*a03ca8b9SKrzysztof Kosiński   // which must be part of |image|.
48*a03ca8b9SKrzysztof Kosiński   Abs32GapFinder(ConstBufferView image,
49*a03ca8b9SKrzysztof Kosiński                  ConstBufferView region,
50*a03ca8b9SKrzysztof Kosiński                  const std::vector<offset_t>& abs32_locations,
51*a03ca8b9SKrzysztof Kosiński                  size_t abs32_width);
52*a03ca8b9SKrzysztof Kosiński   Abs32GapFinder(const Abs32GapFinder&) = delete;
53*a03ca8b9SKrzysztof Kosiński   const Abs32GapFinder& operator=(const Abs32GapFinder&) = delete;
54*a03ca8b9SKrzysztof Kosiński   ~Abs32GapFinder();
55*a03ca8b9SKrzysztof Kosiński 
56*a03ca8b9SKrzysztof Kosiński   // Searches for the next available gap, and returns successfulness.
57*a03ca8b9SKrzysztof Kosiński   bool FindNext();
58*a03ca8b9SKrzysztof Kosiński 
59*a03ca8b9SKrzysztof Kosiński   // Returns the cached result from the last successful FindNext().
GetGap()60*a03ca8b9SKrzysztof Kosiński   ConstBufferView GetGap() const { return gap_; }
61*a03ca8b9SKrzysztof Kosiński 
62*a03ca8b9SKrzysztof Kosiński  private:
63*a03ca8b9SKrzysztof Kosiński   const ConstBufferView::const_iterator base_;
64*a03ca8b9SKrzysztof Kosiński   const ConstBufferView::const_iterator region_end_;
65*a03ca8b9SKrzysztof Kosiński   ConstBufferView::const_iterator cur_lo_;
66*a03ca8b9SKrzysztof Kosiński   const std::vector<offset_t>::const_iterator abs32_end_;
67*a03ca8b9SKrzysztof Kosiński   std::vector<offset_t>::const_iterator abs32_cur_;
68*a03ca8b9SKrzysztof Kosiński   const size_t abs32_width_;
69*a03ca8b9SKrzysztof Kosiński   ConstBufferView gap_;
70*a03ca8b9SKrzysztof Kosiński };
71*a03ca8b9SKrzysztof Kosiński 
72*a03ca8b9SKrzysztof Kosiński // A class to scan regions within an image to find successive rel32 references.
73*a03ca8b9SKrzysztof Kosiński // Architecture-specific parsing and result extraction are delegated to
74*a03ca8b9SKrzysztof Kosiński // inherited classes (say, Rel32Finder_Impl). Sample extraction loop, combined
75*a03ca8b9SKrzysztof Kosiński // with Abs32GapFinder usage:
76*a03ca8b9SKrzysztof Kosiński //
77*a03ca8b9SKrzysztof Kosiński //   Abs32GapFinder gap_finder(...);
78*a03ca8b9SKrzysztof Kosiński //   Rel32Finder_Impl finder(...);
79*a03ca8b9SKrzysztof Kosiński //   while (gap_finder.FindNext()) {
80*a03ca8b9SKrzysztof Kosiński //     rel_finder.SetRegion(gap_finder.GetGap());
81*a03ca8b9SKrzysztof Kosiński //     while (rel_finder.FindNext()) {
82*a03ca8b9SKrzysztof Kosiński //       auto rel32 = rel_finder.GetRel32();  // In Rel32Finder_Impl.
83*a03ca8b9SKrzysztof Kosiński //       if (architecture_specific_validation(rel32)) {
84*a03ca8b9SKrzysztof Kosiński //         rel_finder.Accept();
85*a03ca8b9SKrzysztof Kosiński //         // Store rel32.
86*a03ca8b9SKrzysztof Kosiński //       }
87*a03ca8b9SKrzysztof Kosiński //     }
88*a03ca8b9SKrzysztof Kosiński //   }
89*a03ca8b9SKrzysztof Kosiński class Rel32Finder {
90*a03ca8b9SKrzysztof Kosiński  public:
91*a03ca8b9SKrzysztof Kosiński   Rel32Finder(ConstBufferView image, const AddressTranslator& translator);
92*a03ca8b9SKrzysztof Kosiński   Rel32Finder(const Rel32Finder&) = delete;
93*a03ca8b9SKrzysztof Kosiński   const Rel32Finder& operator=(const Rel32Finder&) = delete;
94*a03ca8b9SKrzysztof Kosiński   virtual ~Rel32Finder();
95*a03ca8b9SKrzysztof Kosiński 
96*a03ca8b9SKrzysztof Kosiński   // Assigns the scan |region| for rel32 references to enable FindNext() use.
97*a03ca8b9SKrzysztof Kosiński   void SetRegion(ConstBufferView region);
98*a03ca8b9SKrzysztof Kosiński 
99*a03ca8b9SKrzysztof Kosiński   // Scans for the next rel32 reference, and returns whether any is found, so a
100*a03ca8b9SKrzysztof Kosiński   // "while" loop can be used for iterative rel32 extraction. The results are
101*a03ca8b9SKrzysztof Kosiński   // cached in Rel32Finder_Impl and obtained by Rel32Finder_Impl::GetRel32().
102*a03ca8b9SKrzysztof Kosiński   bool FindNext();
103*a03ca8b9SKrzysztof Kosiński 
104*a03ca8b9SKrzysztof Kosiński   // When a rel32 reference is found, the caller needs to decide whether to keep
105*a03ca8b9SKrzysztof Kosiński   // the result (perhaps following more validation). If it decides to keep the
106*a03ca8b9SKrzysztof Kosiński   // result, then it must call Accept(), so the next call to FindNext() can skip
107*a03ca8b9SKrzysztof Kosiński   // the accepted rel32 reference.
108*a03ca8b9SKrzysztof Kosiński   void Accept();
109*a03ca8b9SKrzysztof Kosiński 
110*a03ca8b9SKrzysztof Kosiński   // Accessors for unittest.
accept_it()111*a03ca8b9SKrzysztof Kosiński   ConstBufferView::const_iterator accept_it() const { return accept_it_; }
region()112*a03ca8b9SKrzysztof Kosiński   ConstBufferView region() const { return region_; }
113*a03ca8b9SKrzysztof Kosiński 
114*a03ca8b9SKrzysztof Kosiński  protected:
115*a03ca8b9SKrzysztof Kosiński   // Alternatives for where to continue the next scan when a rel32 reference is
116*a03ca8b9SKrzysztof Kosiński   // found. nulls indicate that no rel32 references remain.
117*a03ca8b9SKrzysztof Kosiński   struct NextIterators {
118*a03ca8b9SKrzysztof Kosiński     // The next iterator if the caller does not call Accept().
119*a03ca8b9SKrzysztof Kosiński     ConstBufferView::const_iterator reject;
120*a03ca8b9SKrzysztof Kosiński 
121*a03ca8b9SKrzysztof Kosiński     // The next iterator if the caller calls Accept().
122*a03ca8b9SKrzysztof Kosiński     ConstBufferView::const_iterator accept;
123*a03ca8b9SKrzysztof Kosiński   };
124*a03ca8b9SKrzysztof Kosiński 
125*a03ca8b9SKrzysztof Kosiński   // Detects and extracts architecture-specific rel32 reference. For each one
126*a03ca8b9SKrzysztof Kosiński   // found, the implementation should cache the necessary data to be retrieved
127*a03ca8b9SKrzysztof Kosiński   // via accessors. Returns a NextIterators that stores alternatives for where
128*a03ca8b9SKrzysztof Kosiński   // to continue the scan. If no rel32 reference is found then the returned
129*a03ca8b9SKrzysztof Kosiński   // NextIterators are nulls.
130*a03ca8b9SKrzysztof Kosiński   virtual NextIterators Scan(ConstBufferView region) = 0;
131*a03ca8b9SKrzysztof Kosiński 
132*a03ca8b9SKrzysztof Kosiński   const ConstBufferView image_;
133*a03ca8b9SKrzysztof Kosiński   AddressTranslator::OffsetToRvaCache offset_to_rva_;
134*a03ca8b9SKrzysztof Kosiński 
135*a03ca8b9SKrzysztof Kosiński  private:
136*a03ca8b9SKrzysztof Kosiński   ConstBufferView region_;
137*a03ca8b9SKrzysztof Kosiński   ConstBufferView::const_iterator accept_it_ = nullptr;
138*a03ca8b9SKrzysztof Kosiński };
139*a03ca8b9SKrzysztof Kosiński 
140*a03ca8b9SKrzysztof Kosiński // Parsing for X86 or X64: we perform naive scan for opcodes that have rel32 as
141*a03ca8b9SKrzysztof Kosiński // an argument, and disregard instruction alignment.
142*a03ca8b9SKrzysztof Kosiński class Rel32FinderIntel : public Rel32Finder {
143*a03ca8b9SKrzysztof Kosiński  public:
144*a03ca8b9SKrzysztof Kosiński   Rel32FinderIntel(const Rel32FinderIntel&) = delete;
145*a03ca8b9SKrzysztof Kosiński   const Rel32FinderIntel& operator=(const Rel32FinderIntel&) = delete;
146*a03ca8b9SKrzysztof Kosiński 
147*a03ca8b9SKrzysztof Kosiński   // Struct to store GetRel32() results.
148*a03ca8b9SKrzysztof Kosiński   struct Result {
149*a03ca8b9SKrzysztof Kosiński     offset_t location;
150*a03ca8b9SKrzysztof Kosiński     rva_t target_rva;
151*a03ca8b9SKrzysztof Kosiński 
152*a03ca8b9SKrzysztof Kosiński     // Some references must have their target in the same section as location,
153*a03ca8b9SKrzysztof Kosiński     // which we use this to heuristically reject rel32 reference candidates.
154*a03ca8b9SKrzysztof Kosiński     // When true, this constraint is relaxed.
155*a03ca8b9SKrzysztof Kosiński     bool can_point_outside_section;
156*a03ca8b9SKrzysztof Kosiński   };
157*a03ca8b9SKrzysztof Kosiński 
158*a03ca8b9SKrzysztof Kosiński   using Rel32Finder::Rel32Finder;
159*a03ca8b9SKrzysztof Kosiński 
160*a03ca8b9SKrzysztof Kosiński   // Returns the cached result from the last successful FindNext().
GetRel32()161*a03ca8b9SKrzysztof Kosiński   const Result& GetRel32() { return rel32_; }
162*a03ca8b9SKrzysztof Kosiński 
163*a03ca8b9SKrzysztof Kosiński  protected:
164*a03ca8b9SKrzysztof Kosiński   // Helper for Scan() that also assigns |rel32_|.
165*a03ca8b9SKrzysztof Kosiński   Rel32Finder::NextIterators SetResult(ConstBufferView::const_iterator cursor,
166*a03ca8b9SKrzysztof Kosiński                                        uint32_t code_size,
167*a03ca8b9SKrzysztof Kosiński                                        bool can_point_outside_section);
168*a03ca8b9SKrzysztof Kosiński 
169*a03ca8b9SKrzysztof Kosiński   // Cached results.
170*a03ca8b9SKrzysztof Kosiński   Result rel32_;
171*a03ca8b9SKrzysztof Kosiński 
172*a03ca8b9SKrzysztof Kosiński   // Rel32Finder:
173*a03ca8b9SKrzysztof Kosiński   NextIterators Scan(ConstBufferView region) override = 0;
174*a03ca8b9SKrzysztof Kosiński };
175*a03ca8b9SKrzysztof Kosiński 
176*a03ca8b9SKrzysztof Kosiński // X86 instructions.
177*a03ca8b9SKrzysztof Kosiński class Rel32FinderX86 : public Rel32FinderIntel {
178*a03ca8b9SKrzysztof Kosiński  public:
179*a03ca8b9SKrzysztof Kosiński   using Rel32FinderIntel::Rel32FinderIntel;
180*a03ca8b9SKrzysztof Kosiński 
181*a03ca8b9SKrzysztof Kosiński   Rel32FinderX86(const Rel32FinderX86&) = delete;
182*a03ca8b9SKrzysztof Kosiński   const Rel32FinderX86& operator=(const Rel32FinderX86&) = delete;
183*a03ca8b9SKrzysztof Kosiński 
184*a03ca8b9SKrzysztof Kosiński  private:
185*a03ca8b9SKrzysztof Kosiński   // Rel32Finder:
186*a03ca8b9SKrzysztof Kosiński   NextIterators Scan(ConstBufferView region) override;
187*a03ca8b9SKrzysztof Kosiński };
188*a03ca8b9SKrzysztof Kosiński 
189*a03ca8b9SKrzysztof Kosiński // X64 instructions.
190*a03ca8b9SKrzysztof Kosiński class Rel32FinderX64 : public Rel32FinderIntel {
191*a03ca8b9SKrzysztof Kosiński  public:
192*a03ca8b9SKrzysztof Kosiński   using Rel32FinderIntel::Rel32FinderIntel;
193*a03ca8b9SKrzysztof Kosiński 
194*a03ca8b9SKrzysztof Kosiński   Rel32FinderX64(const Rel32FinderX64&) = delete;
195*a03ca8b9SKrzysztof Kosiński   const Rel32FinderX64& operator=(const Rel32FinderX64&) = delete;
196*a03ca8b9SKrzysztof Kosiński 
197*a03ca8b9SKrzysztof Kosiński  private:
198*a03ca8b9SKrzysztof Kosiński   // Rel32Finder:
199*a03ca8b9SKrzysztof Kosiński   NextIterators Scan(ConstBufferView region) override;
200*a03ca8b9SKrzysztof Kosiński };
201*a03ca8b9SKrzysztof Kosiński 
202*a03ca8b9SKrzysztof Kosiński // Base class for ARM (AArch32 and AArch64) instructions.
203*a03ca8b9SKrzysztof Kosiński template <typename ADDR_TYPE>
204*a03ca8b9SKrzysztof Kosiński class Rel32FinderArm : public Rel32Finder {
205*a03ca8b9SKrzysztof Kosiński  public:
206*a03ca8b9SKrzysztof Kosiński   struct Result {
207*a03ca8b9SKrzysztof Kosiński     offset_t location;
208*a03ca8b9SKrzysztof Kosiński     rva_t target_rva;
209*a03ca8b9SKrzysztof Kosiński     ADDR_TYPE type;
210*a03ca8b9SKrzysztof Kosiński 
211*a03ca8b9SKrzysztof Kosiński     // For testing.
212*a03ca8b9SKrzysztof Kosiński     bool operator==(const Result& other) const {
213*a03ca8b9SKrzysztof Kosiński       return location == other.location && target_rva == other.target_rva &&
214*a03ca8b9SKrzysztof Kosiński              type == other.type;
215*a03ca8b9SKrzysztof Kosiński     }
216*a03ca8b9SKrzysztof Kosiński   };
217*a03ca8b9SKrzysztof Kosiński 
218*a03ca8b9SKrzysztof Kosiński   Rel32FinderArm(ConstBufferView image, const AddressTranslator& translator);
219*a03ca8b9SKrzysztof Kosiński   Rel32FinderArm(const Rel32FinderArm&) = delete;
220*a03ca8b9SKrzysztof Kosiński   const Rel32FinderArm& operator=(const Rel32FinderArm&) = delete;
221*a03ca8b9SKrzysztof Kosiński   ~Rel32FinderArm() override;
222*a03ca8b9SKrzysztof Kosiński 
223*a03ca8b9SKrzysztof Kosiński   // Helper for Scan*() that also assigns |rel32_|.
224*a03ca8b9SKrzysztof Kosiński   NextIterators SetResult(Result&& result,
225*a03ca8b9SKrzysztof Kosiński                           ConstBufferView::const_iterator cursor,
226*a03ca8b9SKrzysztof Kosiński                           int instr_size);
227*a03ca8b9SKrzysztof Kosiński 
228*a03ca8b9SKrzysztof Kosiński   // SetResult() for end of scan.
229*a03ca8b9SKrzysztof Kosiński   NextIterators SetEmptyResult();
230*a03ca8b9SKrzysztof Kosiński 
231*a03ca8b9SKrzysztof Kosiński  protected:
232*a03ca8b9SKrzysztof Kosiński   // Cached results.
233*a03ca8b9SKrzysztof Kosiński   Result rel32_;
234*a03ca8b9SKrzysztof Kosiński };
235*a03ca8b9SKrzysztof Kosiński 
236*a03ca8b9SKrzysztof Kosiński // AArch32 instructions.
237*a03ca8b9SKrzysztof Kosiński class Rel32FinderAArch32
238*a03ca8b9SKrzysztof Kosiński     : public Rel32FinderArm<AArch32Rel32Translator::AddrType> {
239*a03ca8b9SKrzysztof Kosiński  public:
240*a03ca8b9SKrzysztof Kosiński   Rel32FinderAArch32(ConstBufferView image,
241*a03ca8b9SKrzysztof Kosiński                      const AddressTranslator& translator,
242*a03ca8b9SKrzysztof Kosiński                      bool is_thumb2);
243*a03ca8b9SKrzysztof Kosiński   Rel32FinderAArch32(const Rel32FinderAArch32&) = delete;
244*a03ca8b9SKrzysztof Kosiński   const Rel32FinderAArch32& operator=(const Rel32FinderAArch32&) = delete;
245*a03ca8b9SKrzysztof Kosiński   ~Rel32FinderAArch32() override;
246*a03ca8b9SKrzysztof Kosiński 
GetRel32()247*a03ca8b9SKrzysztof Kosiński   const Result& GetRel32() const { return rel32_; }
248*a03ca8b9SKrzysztof Kosiński 
249*a03ca8b9SKrzysztof Kosiński  private:
250*a03ca8b9SKrzysztof Kosiński   // Rel32 extraction, assuming segment is in ARM mode.
251*a03ca8b9SKrzysztof Kosiński   NextIterators ScanA32(ConstBufferView region);
252*a03ca8b9SKrzysztof Kosiński 
253*a03ca8b9SKrzysztof Kosiński   // Rel32 extraction, assuming segment is in THUMB2 mode.
254*a03ca8b9SKrzysztof Kosiński   NextIterators ScanT32(ConstBufferView region);
255*a03ca8b9SKrzysztof Kosiński 
256*a03ca8b9SKrzysztof Kosiński   // Rel32Finder:
257*a03ca8b9SKrzysztof Kosiński   NextIterators Scan(ConstBufferView region) override;
258*a03ca8b9SKrzysztof Kosiński 
259*a03ca8b9SKrzysztof Kosiński   // Indicates whether segment is in THUMB2 or ARM mod. In general this can
260*a03ca8b9SKrzysztof Kosiński   // change throughout a section. However, currently we assume that this is
261*a03ca8b9SKrzysztof Kosiński   // constant for an entire section.
262*a03ca8b9SKrzysztof Kosiński   const bool is_thumb2_;
263*a03ca8b9SKrzysztof Kosiński };
264*a03ca8b9SKrzysztof Kosiński 
265*a03ca8b9SKrzysztof Kosiński // AArch64 instructions.
266*a03ca8b9SKrzysztof Kosiński class Rel32FinderAArch64
267*a03ca8b9SKrzysztof Kosiński     : public Rel32FinderArm<AArch64Rel32Translator::AddrType> {
268*a03ca8b9SKrzysztof Kosiński  public:
269*a03ca8b9SKrzysztof Kosiński   Rel32FinderAArch64(ConstBufferView image,
270*a03ca8b9SKrzysztof Kosiński                      const AddressTranslator& translator);
271*a03ca8b9SKrzysztof Kosiński   Rel32FinderAArch64(const Rel32FinderAArch64&) = delete;
272*a03ca8b9SKrzysztof Kosiński   const Rel32FinderAArch64& operator=(const Rel32FinderAArch64&) = delete;
273*a03ca8b9SKrzysztof Kosiński   ~Rel32FinderAArch64() override;
274*a03ca8b9SKrzysztof Kosiński 
GetRel32()275*a03ca8b9SKrzysztof Kosiński   const Result& GetRel32() const { return rel32_; }
276*a03ca8b9SKrzysztof Kosiński 
277*a03ca8b9SKrzysztof Kosiński  private:
278*a03ca8b9SKrzysztof Kosiński   // Rel32Finder:
279*a03ca8b9SKrzysztof Kosiński   NextIterators Scan(ConstBufferView region) override;
280*a03ca8b9SKrzysztof Kosiński };
281*a03ca8b9SKrzysztof Kosiński 
282*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
283*a03ca8b9SKrzysztof Kosiński 
284*a03ca8b9SKrzysztof Kosiński #endif  // COMPONENTS_ZUCCHINI_REL32_FINDER_H_
285