1 : // Copyright 2011 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #ifndef SYZYGY_CORE_ADDRESS_H_
16 : #define SYZYGY_CORE_ADDRESS_H_
17 :
18 : #include <iosfwd>
19 : #include "base/basictypes.h"
20 : #include "base/logging.h"
21 : #include "syzygy/core/serialization.h"
22 :
23 : namespace core {
24 :
25 : enum AddressType {
26 : kRelativeAddressType,
27 : kAbsoluteAddressType,
28 : kFileOffsetAddressType,
29 : };
30 :
31 : // This class implements an address in a PE image file.
32 : // Addresses are of three varieties:
33 : // - Relative addresses are relative to the base of the image, and thus do not
34 : // change when the image is relocated. Bulk of the addresses in the PE image
35 : // format itself are of this variety, and that's where relative addresses
36 : // crop up most frequently.
37 : // - Absolute addresses are as the name indicates absolute, and those change
38 : // when an image is relocated. Absolute addresses mostly occur in initialized
39 : // data, and for each absolute datum in an image file, there will be a
40 : // relocation entry calling out its location in the image.
41 : // - File offset addresses occur only in the debug data directory that I'm
42 : // aware of, where the debug data is referred to both by a relative address
43 : // and (presumably for convenience) by a file offset address.
44 : // This class is a lightweight wrapper for an integer, which can be freely
45 : // copied. The different address types are deliberately assignment
46 : // incompatible, which helps to avoid confusion when handling different
47 : // types of addresses in implementation.
48 : template <AddressType type> class AddressImpl {
49 : public:
50 E : AddressImpl() : value_(0) {
51 E : }
52 E : explicit AddressImpl(uint32 value) : value_(value) {
53 E : }
54 E : AddressImpl(const AddressImpl<type>& other) // NOLINT
55 : : value_(other.value_) {
56 E : }
57 :
58 E : bool operator<(const AddressImpl<type>& other) const {
59 E : return value_ < other.value_;
60 E : }
61 E : bool operator<=(const AddressImpl<type>& other) const {
62 E : return value_ <= other.value_;
63 E : }
64 E : bool operator>(const AddressImpl<type>& other) const {
65 E : return value_ > other.value_;
66 E : }
67 E : bool operator>=(const AddressImpl<type>& other) const {
68 E : return value_ >= other.value_;
69 E : }
70 :
71 E : bool operator==(const AddressImpl<type>& other) const {
72 E : return value_ == other.value_;
73 E : }
74 E : bool operator!=(const AddressImpl<type>& other) const {
75 E : return value_ != other.value_;
76 E : }
77 :
78 E : void operator=(const AddressImpl<type>& other) {
79 E : value_ = other.value_;
80 E : }
81 E : void operator+=(int32 offset) {
82 E : value_ += offset;
83 E : }
84 E : void operator-=(int32 offset) {
85 E : value_ -= offset;
86 E : }
87 :
88 E : AddressImpl<type> operator+(size_t offset) const {
89 E : return AddressImpl<type>(value() + offset);
90 E : }
91 :
92 E : AddressImpl<type> operator-(size_t offset) const {
93 E : return AddressImpl<type>(value() - offset);
94 E : }
95 :
96 E : int32 operator-(const AddressImpl<type>& other) const {
97 E : return value_ - other.value_;
98 E : }
99 :
100 E : uint32 value() const { return value_; }
101 E : void set_value(uint32 value) {
102 E : value_ = value;
103 E : }
104 :
105 E : AddressImpl<type> AlignUp(size_t alignment) const {
106 E : DCHECK(alignment > 0);
107 : // Round up to nearest multiple of alignment.
108 E : uint32 value = ((value_ + alignment - 1) / alignment) * alignment;
109 E : return AddressImpl<type>(value);
110 E : }
111 :
112 E : bool IsAligned(size_t alignment) const {
113 E : DCHECK(alignment > 0);
114 E : return (value_ % alignment) == 0;
115 E : }
116 :
117 : // Determines the address alignment by counting the trailing zeros. If the
118 : // value of the address is 0 then we return the maximum alignment for a 32-bit
119 : // address (0x80000000).
120 E : uint32 GetAlignment() const {
121 E : uint32 value_copy = value_;
122 E : uint8 trailing_zeros = 0;
123 :
124 : // Sets the trailing zeros to one and set the other bits to zero.
125 : // This is inspired from the code on this page:
126 : // http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear
127 E : value_copy = (value_copy ^ (value_copy - 1)) >> 1;
128 :
129 E : for (; value_copy > 0; trailing_zeros++)
130 E : value_copy >>= 1;
131 :
132 E : return (1 << trailing_zeros);
133 E : }
134 :
135 : // For serialization.
136 E : bool Save(OutArchive *out_archive) const {
137 E : return out_archive->Save(value_);
138 E : }
139 E : bool Load(InArchive *in_archive) {
140 E : return in_archive->Load(&value_);
141 E : }
142 :
143 : private:
144 : uint32 value_;
145 : };
146 :
147 : // These types represent the different addressing formats used in PE images.
148 :
149 : // A virtual address relative to the image base, often termed
150 : // RVA in documentation and in data structure comments.
151 : typedef AddressImpl<kRelativeAddressType> RelativeAddress;
152 : // An absolute address.
153 : typedef AddressImpl<kAbsoluteAddressType> AbsoluteAddress;
154 : // A file offset within an image file.
155 : typedef AddressImpl<kFileOffsetAddressType> FileOffsetAddress;
156 :
157 : std::ostream& operator<<(std::ostream& str, RelativeAddress addr);
158 : std::ostream& operator<<(std::ostream& str, AbsoluteAddress addr);
159 : std::ostream& operator<<(std::ostream& str, FileOffsetAddress addr);
160 :
161 : } // namespace core
162 :
163 : #endif // SYZYGY_CORE_ADDRESS_H_
|