blob: 6393702f6cddf456ace7b5522cb385530408c140 [file] [log] [blame]
Samuel Huang06f1ae92018-03-13 18:19:34 +00001// 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
Etienne Pierre-dorayae27d8e2018-07-24 15:42:33 +00005#ifndef COMPONENTS_ZUCCHINI_RELOC_WIN32_H_
6#define COMPONENTS_ZUCCHINI_RELOC_WIN32_H_
Samuel Huang06f1ae92018-03-13 18:19:34 +00007
8#include <stddef.h>
9#include <stdint.h>
10
11#include <vector>
12
Samuel Huang06f1ae92018-03-13 18:19:34 +000013#include "components/zucchini/address_translator.h"
14#include "components/zucchini/buffer_source.h"
15#include "components/zucchini/buffer_view.h"
16#include "components/zucchini/image_utils.h"
Anton Bikineev1a965512021-05-15 22:35:36 +000017#include "third_party/abseil-cpp/absl/types/optional.h"
Samuel Huang06f1ae92018-03-13 18:19:34 +000018
19namespace 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.
35struct 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)|.
47class 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
Anton Bikineev1a965512021-05-15 22:35:36 +000068 // Successively visits and returns data for each reloc unit, or absl::nullopt
Samuel Huang06f1ae92018-03-13 18:19:34 +000069 // when all reloc units are found. Encapsulates block transition details.
Anton Bikineev1a965512021-05-15 22:35:36 +000070 absl::optional<RelocUnitWin32> GetNext();
Samuel Huang06f1ae92018-03-13 18:19:34 +000071
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.
93class 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:
Anton Bikineev1a965512021-05-15 22:35:36 +0000105 absl::optional<Reference> GetNext() override;
Samuel Huang06f1ae92018-03-13 18:19:34 +0000106
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.
118class 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
Etienne Pierre-dorayae27d8e2018-07-24 15:42:33 +0000140#endif // COMPONENTS_ZUCCHINI_RELOC_WIN32_H_