// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_ZUCCHINI_RELOC_WIN32_H_ #define COMPONENTS_ZUCCHINI_RELOC_WIN32_H_ #include #include #include #include "components/zucchini/address_translator.h" #include "components/zucchini/buffer_source.h" #include "components/zucchini/buffer_view.h" #include "components/zucchini/image_utils.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace zucchini { // Win32 PE relocation table stores a list of (type, RVA) pairs. The table is // organized into "blocks" for RVAs with common high-order bits (12-31). Each // block consists of a list (even length) of 2-byte "units". Each unit stores // type (in bits 12-15) and low-order bits (0-11) of an RVA (in bits 0-11). In // pseudo-struct: // struct Block { // uint32_t rva_hi; // uint32_t block_size_in_bytes; // 8 + multiple of 4. // struct { // uint16_t rva_lo:12, type:4; // Little-endian. // } units[(block_size_in_bytes - 8) / 2]; // Size must be even. // } reloc_table[num_blocks]; // May have padding (type = 0). // Extracted Win32 reloc Unit data. struct RelocUnitWin32 { RelocUnitWin32(); RelocUnitWin32(uint8_t type_in, offset_t location_in, rva_t target_rva_in); friend bool operator==(const RelocUnitWin32& a, const RelocUnitWin32& b); uint8_t type; offset_t location; rva_t target_rva; }; // A reader that parses Win32 PE relocation data and emits RelocUnitWin32 for // each reloc unit that lies strictly inside |[lo, hi)|. class RelocRvaReaderWin32 { public: enum : ptrdiff_t { kRelocUnitSize = sizeof(uint16_t) }; // Parses |image| at |reloc_region| to find beginning offsets of each reloc // block. On success, writes the result to |reloc_block_offsets| and returns // true. Otherwise leaves |reloc_block_offsets| in an undetermined state, and // returns false. static bool FindRelocBlocks(ConstBufferView image, BufferRegion reloc_region, std::vector* reloc_block_offsets); // |reloc_block_offsets| should be precomputed from FindRelBlocks(). RelocRvaReaderWin32(ConstBufferView image, BufferRegion reloc_region, const std::vector& reloc_block_offsets, offset_t lo, offset_t hi); RelocRvaReaderWin32(RelocRvaReaderWin32&&); ~RelocRvaReaderWin32(); // Successively visits and returns data for each reloc unit, or absl::nullopt // when all reloc units are found. Encapsulates block transition details. absl::optional GetNext(); private: // Assuming that |block_begin| points to the beginning of a reloc block, loads // |rva_hi_bits_| and assigns |cur_reloc_units_| as the region containing the // associated units, potentially truncated by |end_it_|. Returns true if reloc // data are available for read, and false otherwise. bool LoadRelocBlock(ConstBufferView::const_iterator block_begin); const ConstBufferView image_; // End iterator. ConstBufferView::const_iterator end_it_; // Unit data of the current reloc block. BufferSource cur_reloc_units_; // High-order bits (12-31) for all relocs of the current reloc block. rva_t rva_hi_bits_; }; // A reader for Win32 reloc References, implemented as a filtering and // translation adaptor of RelocRvaReaderWin32. class RelocReaderWin32 : public ReferenceReader { public: // Takes ownership of |reloc_rva_reader|. |offset_bound| specifies the // exclusive upper bound of reloc target offsets, taking account of widths of // targets (which are abs32 References). RelocReaderWin32(RelocRvaReaderWin32&& reloc_rva_reader, uint16_t reloc_type, offset_t offset_bound, const AddressTranslator& translator); ~RelocReaderWin32() override; // ReferenceReader: absl::optional GetNext() override; private: RelocRvaReaderWin32 reloc_rva_reader_; const uint16_t reloc_type_; // uint16_t to simplify shifting (<< 12). const offset_t offset_bound_; AddressTranslator::RvaToOffsetCache entry_rva_to_offset_; }; // A writer for Win32 reloc References. This is simpler than the reader since: // - No iteration is required. // - High-order bits of reloc target RVAs are assumed to be handled elsewhere, // so only low-order bits need to be written. class RelocWriterWin32 : public ReferenceWriter { public: RelocWriterWin32(uint16_t reloc_type, MutableBufferView image, BufferRegion reloc_region, const std::vector& reloc_block_offsets, const AddressTranslator& translator); ~RelocWriterWin32() override; // ReferenceWriter: void PutNext(Reference ref) override; private: const uint16_t reloc_type_; MutableBufferView image_; BufferRegion reloc_region_; const std::vector& reloc_block_offsets_; AddressTranslator::OffsetToRvaCache target_offset_to_rva_; }; } // namespace zucchini #endif // COMPONENTS_ZUCCHINI_RELOC_WIN32_H_