1 : // Copyright 2012 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 : // Provides an assembler that assembles to basic block instruction lists.
16 :
17 : #ifndef SYZYGY_BLOCK_GRAPH_BASIC_BLOCK_ASSEMBLER_H_
18 : #define SYZYGY_BLOCK_GRAPH_BASIC_BLOCK_ASSEMBLER_H_
19 :
20 : #include "syzygy/assm/assembler_base.h"
21 : #include "syzygy/block_graph/basic_block.h"
22 : #include "syzygy/block_graph/block_graph.h"
23 :
24 : namespace block_graph {
25 :
26 : using assm::ValueSize;
27 :
28 : // Declares a BasicBlockReference-like class that has no type or size
29 : // information. The size information is stored in the Operand or Value housing
30 : // the untyped reference, and the type is inferred from the instruction being
31 : // assembled.
32 : class UntypedReference {
33 : public:
34 : typedef BlockGraph::Block Block;
35 : typedef BlockGraph::Offset Offset;
36 :
37 : // Default constructor.
38 E : UntypedReference()
39 : : basic_block_(NULL), block_(NULL), offset_(0), base_(0) {
40 E : }
41 :
42 : // Copy constructor.
43 : // @param other The reference to be copied.
44 : UntypedReference(const UntypedReference& other)
45 : : basic_block_(other.basic_block_), block_(other.block_),
46 E : offset_(other.offset_), base_(other.base_) {
47 E : }
48 :
49 : // Constructor from a basic block reference.
50 : // @param bb_ref The basic block reference to be copied.
51 : explicit UntypedReference(const BasicBlockReference& bb_ref)
52 : : basic_block_(bb_ref.basic_block()), block_(bb_ref.block()),
53 E : offset_(bb_ref.offset()), base_(bb_ref.base()) {
54 E : DCHECK(block_ != NULL || basic_block_ != NULL);
55 E : }
56 :
57 : // Constructs a reference to a basic block.
58 : // @param basic_block The basic block to be referred to.
59 E : explicit UntypedReference(BasicBlock* basic_block)
60 : : basic_block_(basic_block), block_(NULL), offset_(0), base_(0) {
61 E : DCHECK(basic_block != NULL);
62 E : }
63 :
64 : // Constructs a reference to a block.
65 : // @param block The block to be referred to.
66 : // @param offset The offset from the start of the block actually being
67 : // pointed to.
68 : // @param base The offset from the start of the block semantically being
69 : // referred to.
70 E : UntypedReference(Block* block, Offset offset, Offset base)
71 : : basic_block_(NULL), block_(block), offset_(offset), base_(base) {
72 E : DCHECK(block != NULL);
73 E : }
74 :
75 : // @name Accessors.
76 : // @{
77 E : BasicBlock* basic_block() const { return basic_block_; }
78 E : Block* block() const { return block_; }
79 E : Offset offset() const { return offset_; }
80 E : Offset base() const { return base_; }
81 : // @}
82 :
83 : // @returns true if this reference is valid.
84 E : bool IsValid() const { return block_ != NULL || basic_block_ != NULL; }
85 :
86 : // Returns the type of the object being referred to.
87 E : BasicBlockReference::ReferredType referred_type() const {
88 E : if (block_ != NULL)
89 E : return BasicBlockReference::REFERRED_TYPE_BLOCK;
90 E : if (basic_block_ != NULL)
91 E : return BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK;
92 E : return BasicBlockReference::REFERRED_TYPE_UNKNOWN;
93 E : }
94 :
95 : // Comparison operator.
96 : // @returns true if this reference is the same as the @p other.
97 E : bool operator==(const UntypedReference& other) const {
98 : return basic_block_ == other.basic_block_ &&
99 : block_ == other.block_ &&
100 : offset_ == other.offset_ &&
101 E : base_ == other.base_;
102 E : }
103 :
104 : // Assignment operator.
105 E : const UntypedReference& operator=(const UntypedReference& other) {
106 E : basic_block_ = other.basic_block_;
107 E : block_ = other.block_;
108 E : offset_ = other.offset_;
109 E : base_ = other.base_;
110 :
111 E : return *this;
112 E : }
113 :
114 : private:
115 : BasicBlock* basic_block_;
116 : Block* block_;
117 : Offset offset_;
118 : Offset base_;
119 : };
120 :
121 : class BasicBlockAssembler : public assm::AssemblerBase<UntypedReference> {
122 : public:
123 : typedef assm::AssemblerBase<UntypedReference> Super;
124 :
125 : typedef BlockGraph::Block::SourceRange SourceRange;
126 : typedef BasicBlock::Instructions Instructions;
127 : typedef assm::Register8 Register8;
128 : typedef assm::Register16 Register16;
129 : typedef assm::Register32 Register32;
130 : typedef assm::ConditionCode ConditionCode;
131 :
132 : // Constructs a basic block assembler that inserts new instructions
133 : // into @p *list at @p where.
134 : BasicBlockAssembler(const Instructions::iterator& where,
135 : Instructions *list);
136 :
137 : // Constructs a basic block assembler that inserts new instructions into
138 : // @p *list at @p where, assuming a starting address of @p location.
139 : BasicBlockAssembler(uint32 location,
140 : const Instructions::iterator& where,
141 : Instructions *list);
142 :
143 : // @returns The source range injected into created instructions.
144 E : SourceRange source_range() const { return serializer_.source_range(); }
145 :
146 : // Set the SourceRange injected repeatedly into each instruction created via
147 : // the assembler. This should be used with care because it causes the OMAP
148 : // information to no longer be 1:1 mapping, and may confuse some debuggers.
149 : // @param source_range The source range set to each created instructions.
150 E : void set_source_range(const SourceRange& source_range) {
151 E : serializer_.set_source_range(source_range);
152 E : }
153 :
154 : // @name Call instructions.
155 : // @{
156 : void call(const Immediate& dst);
157 : void call(const Operand& dst);
158 : // @}
159 :
160 : // @name Jmp instructions.
161 : // @{
162 : void jmp(const Immediate& dst);
163 : void jmp(const Operand& dst);
164 : // @}
165 :
166 : // @name Conditional branch instruction.
167 : // @{
168 : void j(ConditionCode code, const Immediate& dst);
169 : // @}
170 :
171 : private:
172 : typedef BlockGraph::ReferenceType ReferenceType;
173 :
174 : class BasicBlockSerializer
175 : : public assm::AssemblerBase<UntypedReference>::InstructionSerializer {
176 : public:
177 : BasicBlockSerializer(const Instructions::iterator& where,
178 : Instructions* list);
179 :
180 : void AppendInstruction(uint32 location,
181 : const uint8* bytes,
182 : size_t num_bytes,
183 : const ReferenceInfo* refs,
184 : size_t num_refs) override;
185 : bool FinalizeLabel(uint32 location,
186 : const uint8* bytes,
187 : size_t num_bytes) override;
188 :
189 E : SourceRange source_range() const { return source_range_; }
190 E : void set_source_range(const SourceRange& source_range) {
191 E : source_range_ = source_range;
192 E : }
193 :
194 : // Pushes back a reference type to be associated with a untyped reference.
195 : // @param type The type of the reference.
196 : // @param size The size of the reference, as a ValueSize.
197 : void PushReferenceInfo(ReferenceType type, assm::ValueSize size);
198 :
199 : private:
200 : Instructions::iterator where_;
201 : Instructions* list_;
202 :
203 : // Source range set to instructions appended by this serializer.
204 : SourceRange source_range_;
205 : };
206 :
207 : BasicBlockSerializer serializer_;
208 : };
209 :
210 : // @name Immediate factory functions.
211 : // @{
212 :
213 : // Default construction.
214 : BasicBlockAssembler::Immediate Immediate();
215 :
216 : // Constructs an 8- or 32-bit Immediate, depending on the minimum number of
217 : // bits required to represent the Immediate. If the Immediate can be encoded
218 : // using 8-bits to have the same representation under sign extension, then an
219 : // 8-bit Immediate will be created; otherwise, a 32-bit absolute Immediate will
220 : // be created.
221 : // @param value The value to be stored.
222 : BasicBlockAssembler::Immediate Immediate(uint32 value);
223 :
224 : // Constructs an absolute Immediate having a specific bit width.
225 : // @param value The value to be stored.
226 : // @param size The size of the value.
227 : BasicBlockAssembler::Immediate Immediate(uint32 value, assm::ValueSize size);
228 :
229 : // Constructs a 32-bit direct reference to the basic block @p bb.
230 : // @param bb The basic block to be referred to.
231 : // @note This is fine even for jmps (which may be encoded using 8-bit
232 : // references) as the BB layout algorithm will use the shortest jmp
233 : // possible.
234 : BasicBlockAssembler::Immediate Immediate(BasicBlock* bb);
235 :
236 : // Constructs a 32-bit direct reference to @p block at the given @p offset.
237 : // @param block The block to be referred to.
238 : // @param offset The offset to be referred to, both semantically and
239 : // literally. The base and offset of the reference will be set to this.
240 : // @note This is fine even for jmps (which may be encoded using 8-bit
241 : // references) as the BB layout algorithm will use the shortest jmp
242 : // possible.
243 : BasicBlockAssembler::Immediate Immediate(
244 : BlockGraph::Block* block, BlockGraph::Offset offset);
245 :
246 : // Constructs a 32-bit reference to @p block at the given @p offset and
247 : // @p base.
248 : // @param block The block to be referred to.
249 : // @param offset The offset to be literally referred to.
250 : // @param base The offset to be semantically referred to. This must be
251 : // within the data of @p block.
252 : BasicBlockAssembler::Immediate Immediate(
253 : BlockGraph::Block* block, BlockGraph::Offset offset,
254 : BlockGraph::Offset base);
255 :
256 : // Full constructor.
257 : // @param value The value to be stored.
258 : // @param size The size of the Immediate.
259 : // @param ref The untyped reference backing this Immediate. The reference must
260 : // be valid.
261 : BasicBlockAssembler::Immediate Immediate(
262 : uint32 value, ValueSize size, const UntypedReference& ref);
263 :
264 : // @}
265 :
266 : // @name Displacement factory functions.
267 : // @{
268 :
269 : // Default construction.
270 : BasicBlockAssembler::Displacement Displacement();
271 :
272 : // Constructs an 8- or 32-bit Displacement, depending on the minimum number of
273 : // bits required to represent the Displacement. If the Displacement can be
274 : // encoded using 8-bits to have the same representation under sign extension,
275 : // then an 8-bit Displacement will be created; otherwise, a 32-bit absolute
276 : // Displacement will be created.
277 : // @param value The value to be stored.
278 : BasicBlockAssembler::Displacement Displacement(uint32 value);
279 :
280 : // Constructs an absolute Displacement having a specific bit width.
281 : // @param value The value to be stored.
282 : // @param size The size of the Displacement.
283 : BasicBlockAssembler::Displacement Displacement(uint32 value, ValueSize size);
284 :
285 : // Constructs a 32-bit direct reference to the basic block @p bb.
286 : // @param bb The basic block to be referred to.
287 : // @note This is fine even for jmps (which may be encoded using 8-bit
288 : // references) as the BB layout algorithm will use the shortest jmp
289 : // possible.
290 : BasicBlockAssembler::Displacement Displacement(BasicBlock* bb);
291 :
292 : // Constructs a 32-bit direct reference to @p block at the given @p offset.
293 : // @param block The block to be referred to.
294 : // @param offset The offset to be referred to, both semantically and
295 : // literally. The base and offset of the reference will be set to this.
296 : // @note This is fine even for jmps (which may be encoded using 8-bit
297 : // references) as the BB layout algorithm will use the shortest jmp
298 : // possible.
299 : BasicBlockAssembler::Displacement Displacement(
300 : BlockGraph::Block* block, BlockGraph::Offset offset);
301 :
302 : // Constructs a 32-bit reference to @p block at the given @p offset and
303 : // @p base.
304 : // @param block The block to be referred to.
305 : // @param offset The offset to be literally referred to.
306 : // @param base The offset to be semantically referred to. This must be
307 : // within the data of @p block.
308 : BasicBlockAssembler::Displacement Displacement(BlockGraph::Block* block,
309 : BlockGraph::Offset offset,
310 : BlockGraph::Offset base);
311 :
312 : // Full constructor.
313 : // @param value The value to be stored.
314 : // @param size The size of the Displacement.
315 : // @param ref The untyped reference backing this Displacement. The reference
316 : // must be valid.
317 : BasicBlockAssembler::Displacement Displacement(
318 : uint32 value, ValueSize size, const UntypedReference& ref);
319 :
320 : // @}
321 :
322 : // @name Operand factory functions.
323 : // @{
324 :
325 : // A register-indirect mode.
326 : BasicBlockAssembler::Operand Operand(const assm::Register32& base);
327 :
328 : // A register-indirect with displacement mode.
329 : BasicBlockAssembler::Operand Operand(
330 : const assm::Register32& base,
331 : const BasicBlockAssembler::Displacement& displ);
332 :
333 : // A displacement-only mode.
334 : BasicBlockAssembler::Operand Operand(
335 : const BasicBlockAssembler::Displacement& displ);
336 :
337 : // The full [base + index * scale + displ32] mode.
338 : // @note esp cannot be used as an index register.
339 : BasicBlockAssembler::Operand Operand(
340 : const assm::Register32& base, const assm::Register32& index,
341 : assm::ScaleFactor scale, const BasicBlockAssembler::Displacement& displ);
342 :
343 : // The full [base + index * scale] mode.
344 : // @note esp cannot be used as an index register.
345 : BasicBlockAssembler::Operand Operand(const assm::Register32& base,
346 : const assm::Register32& index,
347 : assm::ScaleFactor scale);
348 :
349 : // The [index * scale + displ32] mode.
350 : // @note esp cannot be used as an index register.
351 : BasicBlockAssembler::Operand Operand(
352 : const assm::Register32& index, assm::ScaleFactor scale,
353 : const BasicBlockAssembler::Displacement& displ);
354 :
355 : // @}
356 :
357 : } // namespace block_graph
358 :
359 : #endif // SYZYGY_BLOCK_GRAPH_BASIC_BLOCK_ASSEMBLER_H_
|