xref: /aosp_15_r20/external/zucchini/reloc_win32.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_RELOC_WIN32_H_
6*a03ca8b9SKrzysztof Kosiński #define COMPONENTS_ZUCCHINI_RELOC_WIN32_H_
7*a03ca8b9SKrzysztof Kosiński 
8*a03ca8b9SKrzysztof Kosiński #include <stddef.h>
9*a03ca8b9SKrzysztof Kosiński #include <stdint.h>
10*a03ca8b9SKrzysztof Kosiński 
11*a03ca8b9SKrzysztof Kosiński #include <optional>
12*a03ca8b9SKrzysztof Kosiński #include <vector>
13*a03ca8b9SKrzysztof Kosiński 
14*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/address_translator.h"
15*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_source.h"
16*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_view.h"
17*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/image_utils.h"
18*a03ca8b9SKrzysztof Kosiński 
19*a03ca8b9SKrzysztof Kosiński namespace zucchini {
20*a03ca8b9SKrzysztof Kosiński 
21*a03ca8b9SKrzysztof Kosiński // Win32 PE relocation table stores a list of (type, RVA) pairs. The table is
22*a03ca8b9SKrzysztof Kosiński // organized into "blocks" for RVAs with common high-order bits (12-31). Each
23*a03ca8b9SKrzysztof Kosiński // block consists of a list (even length) of 2-byte "units". Each unit stores
24*a03ca8b9SKrzysztof Kosiński // type (in bits 12-15) and low-order bits (0-11) of an RVA (in bits 0-11). In
25*a03ca8b9SKrzysztof Kosiński // pseudo-struct:
26*a03ca8b9SKrzysztof Kosiński //   struct Block {
27*a03ca8b9SKrzysztof Kosiński //     uint32_t rva_hi;
28*a03ca8b9SKrzysztof Kosiński //     uint32_t block_size_in_bytes;  // 8 + multiple of 4.
29*a03ca8b9SKrzysztof Kosiński //     struct {
30*a03ca8b9SKrzysztof Kosiński //       uint16_t rva_lo:12, type:4;  // Little-endian.
31*a03ca8b9SKrzysztof Kosiński //     } units[(block_size_in_bytes - 8) / 2];  // Size must be even.
32*a03ca8b9SKrzysztof Kosiński //   } reloc_table[num_blocks];  // May have padding (type = 0).
33*a03ca8b9SKrzysztof Kosiński 
34*a03ca8b9SKrzysztof Kosiński // Extracted Win32 reloc Unit data.
35*a03ca8b9SKrzysztof Kosiński struct RelocUnitWin32 {
36*a03ca8b9SKrzysztof Kosiński   RelocUnitWin32();
37*a03ca8b9SKrzysztof Kosiński   RelocUnitWin32(uint8_t type_in, offset_t location_in, rva_t target_rva_in);
38*a03ca8b9SKrzysztof Kosiński   friend bool operator==(const RelocUnitWin32& a, const RelocUnitWin32& b);
39*a03ca8b9SKrzysztof Kosiński 
40*a03ca8b9SKrzysztof Kosiński   uint8_t type;
41*a03ca8b9SKrzysztof Kosiński   offset_t location;
42*a03ca8b9SKrzysztof Kosiński   rva_t target_rva;
43*a03ca8b9SKrzysztof Kosiński };
44*a03ca8b9SKrzysztof Kosiński 
45*a03ca8b9SKrzysztof Kosiński // A reader that parses Win32 PE relocation data and emits RelocUnitWin32 for
46*a03ca8b9SKrzysztof Kosiński // each reloc unit that lies strictly inside |[lo, hi)|.
47*a03ca8b9SKrzysztof Kosiński class RelocRvaReaderWin32 {
48*a03ca8b9SKrzysztof Kosiński  public:
49*a03ca8b9SKrzysztof Kosiński   enum : ptrdiff_t { kRelocUnitSize = sizeof(uint16_t) };
50*a03ca8b9SKrzysztof Kosiński 
51*a03ca8b9SKrzysztof Kosiński   // Parses |image| at |reloc_region| to find beginning offsets of each reloc
52*a03ca8b9SKrzysztof Kosiński   // block. On success, writes the result to |reloc_block_offsets| and returns
53*a03ca8b9SKrzysztof Kosiński   // true. Otherwise leaves |reloc_block_offsets| in an undetermined state, and
54*a03ca8b9SKrzysztof Kosiński   // returns false.
55*a03ca8b9SKrzysztof Kosiński   static bool FindRelocBlocks(ConstBufferView image,
56*a03ca8b9SKrzysztof Kosiński                               BufferRegion reloc_region,
57*a03ca8b9SKrzysztof Kosiński                               std::vector<offset_t>* reloc_block_offsets);
58*a03ca8b9SKrzysztof Kosiński 
59*a03ca8b9SKrzysztof Kosiński   // |reloc_block_offsets| should be precomputed from FindRelBlocks().
60*a03ca8b9SKrzysztof Kosiński   RelocRvaReaderWin32(ConstBufferView image,
61*a03ca8b9SKrzysztof Kosiński                       BufferRegion reloc_region,
62*a03ca8b9SKrzysztof Kosiński                       const std::vector<offset_t>& reloc_block_offsets,
63*a03ca8b9SKrzysztof Kosiński                       offset_t lo,
64*a03ca8b9SKrzysztof Kosiński                       offset_t hi);
65*a03ca8b9SKrzysztof Kosiński   RelocRvaReaderWin32(RelocRvaReaderWin32&&);
66*a03ca8b9SKrzysztof Kosiński   ~RelocRvaReaderWin32();
67*a03ca8b9SKrzysztof Kosiński 
68*a03ca8b9SKrzysztof Kosiński   // Successively visits and returns data for each reloc unit, or std::nullopt
69*a03ca8b9SKrzysztof Kosiński   // when all reloc units are found. Encapsulates block transition details.
70*a03ca8b9SKrzysztof Kosiński   std::optional<RelocUnitWin32> GetNext();
71*a03ca8b9SKrzysztof Kosiński 
72*a03ca8b9SKrzysztof Kosiński  private:
73*a03ca8b9SKrzysztof Kosiński   // Assuming that |block_begin| points to the beginning of a reloc block, loads
74*a03ca8b9SKrzysztof Kosiński   // |rva_hi_bits_| and assigns |cur_reloc_units_| as the region containing the
75*a03ca8b9SKrzysztof Kosiński   // associated units, potentially truncated by |end_it_|. Returns true if reloc
76*a03ca8b9SKrzysztof Kosiński   // data are available for read, and false otherwise.
77*a03ca8b9SKrzysztof Kosiński   bool LoadRelocBlock(ConstBufferView::const_iterator block_begin);
78*a03ca8b9SKrzysztof Kosiński 
79*a03ca8b9SKrzysztof Kosiński   const ConstBufferView image_;
80*a03ca8b9SKrzysztof Kosiński 
81*a03ca8b9SKrzysztof Kosiński   // End iterator.
82*a03ca8b9SKrzysztof Kosiński   ConstBufferView::const_iterator end_it_;
83*a03ca8b9SKrzysztof Kosiński 
84*a03ca8b9SKrzysztof Kosiński   // Unit data of the current reloc block.
85*a03ca8b9SKrzysztof Kosiński   BufferSource cur_reloc_units_;
86*a03ca8b9SKrzysztof Kosiński 
87*a03ca8b9SKrzysztof Kosiński   // High-order bits (12-31) for all relocs of the current reloc block.
88*a03ca8b9SKrzysztof Kosiński   rva_t rva_hi_bits_;
89*a03ca8b9SKrzysztof Kosiński };
90*a03ca8b9SKrzysztof Kosiński 
91*a03ca8b9SKrzysztof Kosiński // A reader for Win32 reloc References, implemented as a filtering and
92*a03ca8b9SKrzysztof Kosiński // translation adaptor of RelocRvaReaderWin32.
93*a03ca8b9SKrzysztof Kosiński class RelocReaderWin32 : public ReferenceReader {
94*a03ca8b9SKrzysztof Kosiński  public:
95*a03ca8b9SKrzysztof Kosiński   // Takes ownership of |reloc_rva_reader|. |offset_bound| specifies the
96*a03ca8b9SKrzysztof Kosiński   // exclusive upper bound of reloc target offsets, taking account of widths of
97*a03ca8b9SKrzysztof Kosiński   // targets (which are abs32 References).
98*a03ca8b9SKrzysztof Kosiński   RelocReaderWin32(RelocRvaReaderWin32&& reloc_rva_reader,
99*a03ca8b9SKrzysztof Kosiński                    uint16_t reloc_type,
100*a03ca8b9SKrzysztof Kosiński                    offset_t offset_bound,
101*a03ca8b9SKrzysztof Kosiński                    const AddressTranslator& translator);
102*a03ca8b9SKrzysztof Kosiński   ~RelocReaderWin32() override;
103*a03ca8b9SKrzysztof Kosiński 
104*a03ca8b9SKrzysztof Kosiński   // ReferenceReader:
105*a03ca8b9SKrzysztof Kosiński   std::optional<Reference> GetNext() override;
106*a03ca8b9SKrzysztof Kosiński 
107*a03ca8b9SKrzysztof Kosiński  private:
108*a03ca8b9SKrzysztof Kosiński   RelocRvaReaderWin32 reloc_rva_reader_;
109*a03ca8b9SKrzysztof Kosiński   const uint16_t reloc_type_;  // uint16_t to simplify shifting (<< 12).
110*a03ca8b9SKrzysztof Kosiński   const offset_t offset_bound_;
111*a03ca8b9SKrzysztof Kosiński   AddressTranslator::RvaToOffsetCache entry_rva_to_offset_;
112*a03ca8b9SKrzysztof Kosiński };
113*a03ca8b9SKrzysztof Kosiński 
114*a03ca8b9SKrzysztof Kosiński // A writer for Win32 reloc References. This is simpler than the reader since:
115*a03ca8b9SKrzysztof Kosiński // - No iteration is required.
116*a03ca8b9SKrzysztof Kosiński // - High-order bits of reloc target RVAs are assumed to be handled elsewhere,
117*a03ca8b9SKrzysztof Kosiński //   so only low-order bits need to be written.
118*a03ca8b9SKrzysztof Kosiński class RelocWriterWin32 : public ReferenceWriter {
119*a03ca8b9SKrzysztof Kosiński  public:
120*a03ca8b9SKrzysztof Kosiński   RelocWriterWin32(uint16_t reloc_type,
121*a03ca8b9SKrzysztof Kosiński                    MutableBufferView image,
122*a03ca8b9SKrzysztof Kosiński                    BufferRegion reloc_region,
123*a03ca8b9SKrzysztof Kosiński                    const std::vector<offset_t>& reloc_block_offsets,
124*a03ca8b9SKrzysztof Kosiński                    const AddressTranslator& translator);
125*a03ca8b9SKrzysztof Kosiński   ~RelocWriterWin32() override;
126*a03ca8b9SKrzysztof Kosiński 
127*a03ca8b9SKrzysztof Kosiński   // ReferenceWriter:
128*a03ca8b9SKrzysztof Kosiński   void PutNext(Reference ref) override;
129*a03ca8b9SKrzysztof Kosiński 
130*a03ca8b9SKrzysztof Kosiński  private:
131*a03ca8b9SKrzysztof Kosiński   const uint16_t reloc_type_;
132*a03ca8b9SKrzysztof Kosiński   MutableBufferView image_;
133*a03ca8b9SKrzysztof Kosiński   BufferRegion reloc_region_;
134*a03ca8b9SKrzysztof Kosiński   const std::vector<offset_t>& reloc_block_offsets_;
135*a03ca8b9SKrzysztof Kosiński   AddressTranslator::OffsetToRvaCache target_offset_to_rva_;
136*a03ca8b9SKrzysztof Kosiński };
137*a03ca8b9SKrzysztof Kosiński 
138*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
139*a03ca8b9SKrzysztof Kosiński 
140*a03ca8b9SKrzysztof Kosiński #endif  // COMPONENTS_ZUCCHINI_RELOC_WIN32_H_
141