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