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