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