| // 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 <stddef.h> |
| #include <stdint.h> |
| |
| #include <vector> |
| |
| #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<offset_t>* reloc_block_offsets); |
| |
| // |reloc_block_offsets| should be precomputed from FindRelBlocks(). |
| RelocRvaReaderWin32(ConstBufferView image, |
| BufferRegion reloc_region, |
| const std::vector<offset_t>& 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<RelocUnitWin32> 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<Reference> 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<offset_t>& 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<offset_t>& reloc_block_offsets_; |
| AddressTranslator::OffsetToRvaCache target_offset_to_rva_; |
| }; |
| |
| } // namespace zucchini |
| |
| #endif // COMPONENTS_ZUCCHINI_RELOC_WIN32_H_ |