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 E : : 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 E : : 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 E : : 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 E : : 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 E : : 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 E : return basic_block_ == other.basic_block_ &&
99 : block_ == other.block_ &&
100 : offset_ == other.offset_ &&
101 : 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_t 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 : void jmp(const Register32& dst);
165 : // @}
166 :
167 : // @name Conditional branch instruction.
168 : // @{
169 : void j(ConditionCode code, const Immediate& dst);
170 : // @}
171 :
172 : private:
173 : typedef BlockGraph::ReferenceType ReferenceType;
174 :
175 : class BasicBlockSerializer
176 : : public assm::AssemblerBase<UntypedReference>::InstructionSerializer {
177 : public:
178 : BasicBlockSerializer(const Instructions::iterator& where,
179 : Instructions* list);
180 :
181 : void AppendInstruction(uint32_t location,
182 : const uint8_t* bytes,
183 : uint32_t num_bytes,
184 : const ReferenceInfo* refs,
185 : size_t num_refs) override;
186 : bool FinalizeLabel(uint32_t location,
187 : const uint8_t* bytes,
188 : size_t num_bytes) override;
189 :
190 E : SourceRange source_range() const { return source_range_; }
191 E : void set_source_range(const SourceRange& source_range) {
192 E : source_range_ = source_range;
193 E : }
194 :
195 : // Pushes back a reference type to be associated with a untyped reference.
196 : // @param type The type of the reference.
197 : // @param size The size of the reference, as a ValueSize.
198 : void PushReferenceInfo(ReferenceType type, assm::ValueSize size);
199 :
200 : private:
201 : Instructions::iterator where_;
202 : Instructions* list_;
203 :
204 : // Source range set to instructions appended by this serializer.
205 : SourceRange source_range_;
206 : };
207 :
208 : BasicBlockSerializer serializer_;
209 : };
210 :
211 : // @name Immediate factory functions.
212 : // @{
213 :
214 : // Default construction.
215 : BasicBlockAssembler::Immediate Immediate();
216 :
217 : // Constructs an 8- or 32-bit Immediate, depending on the minimum number of
218 : // bits required to represent the Immediate. If the Immediate can be encoded
219 : // using 8-bits to have the same representation under sign extension, then an
220 : // 8-bit Immediate will be created; otherwise, a 32-bit absolute Immediate will
221 : // be created.
222 : // @param value The value to be stored.
223 : BasicBlockAssembler::Immediate Immediate(uint32_t value);
224 :
225 : // Constructs an absolute Immediate having a specific bit width.
226 : // @param value The value to be stored.
227 : // @param size The size of the value.
228 : BasicBlockAssembler::Immediate Immediate(uint32_t value, assm::ValueSize size);
229 :
230 : // Constructs a 32-bit direct reference to the basic block @p bb.
231 : // @param bb The basic block to be referred to.
232 : // @note This is fine even for jmps (which may be encoded using 8-bit
233 : // references) as the BB layout algorithm will use the shortest jmp
234 : // possible.
235 : BasicBlockAssembler::Immediate Immediate(BasicBlock* bb);
236 :
237 : // Constructs a 32-bit direct reference to @p block at the given @p offset.
238 : // @param block The block to be referred to.
239 : // @param offset The offset to be referred to, both semantically and
240 : // literally. The base and offset of the reference will be set to this.
241 : // @note This is fine even for jmps (which may be encoded using 8-bit
242 : // references) as the BB layout algorithm will use the shortest jmp
243 : // possible.
244 : BasicBlockAssembler::Immediate Immediate(
245 : BlockGraph::Block* block, BlockGraph::Offset offset);
246 :
247 : // Constructs a 32-bit reference to @p block at the given @p offset and
248 : // @p base.
249 : // @param block The block to be referred to.
250 : // @param offset The offset to be literally referred to.
251 : // @param base The offset to be semantically referred to. This must be
252 : // within the data of @p block.
253 : BasicBlockAssembler::Immediate Immediate(
254 : BlockGraph::Block* block, BlockGraph::Offset offset,
255 : BlockGraph::Offset base);
256 :
257 : // Full constructor.
258 : // @param value The value to be stored.
259 : // @param size The size of the Immediate.
260 : // @param ref The untyped reference backing this Immediate. The reference must
261 : // be valid.
262 : BasicBlockAssembler::Immediate Immediate(uint32_t value,
263 : ValueSize size,
264 : const UntypedReference& ref);
265 :
266 : // @}
267 :
268 : // @name Displacement factory functions.
269 : // @{
270 :
271 : // Default construction.
272 : BasicBlockAssembler::Displacement Displacement();
273 :
274 : // Constructs an 8- or 32-bit Displacement, depending on the minimum number of
275 : // bits required to represent the Displacement. If the Displacement can be
276 : // encoded using 8-bits to have the same representation under sign extension,
277 : // then an 8-bit Displacement will be created; otherwise, a 32-bit absolute
278 : // Displacement will be created.
279 : // @param value The value to be stored.
280 : BasicBlockAssembler::Displacement Displacement(uint32_t value);
281 :
282 : // Constructs an absolute Displacement having a specific bit width.
283 : // @param value The value to be stored.
284 : // @param size The size of the Displacement.
285 : BasicBlockAssembler::Displacement Displacement(uint32_t value, ValueSize size);
286 :
287 : // Constructs a 32-bit direct reference to the basic block @p bb.
288 : // @param bb The basic block to be referred to.
289 : // @note This is fine even for jmps (which may be encoded using 8-bit
290 : // references) as the BB layout algorithm will use the shortest jmp
291 : // possible.
292 : BasicBlockAssembler::Displacement Displacement(BasicBlock* bb);
293 :
294 : // Constructs a 32-bit direct reference to @p block at the given @p offset.
295 : // @param block The block to be referred to.
296 : // @param offset The offset to be referred to, both semantically and
297 : // literally. The base and offset of the reference will be set to this.
298 : // @note This is fine even for jmps (which may be encoded using 8-bit
299 : // references) as the BB layout algorithm will use the shortest jmp
300 : // possible.
301 : BasicBlockAssembler::Displacement Displacement(
302 : BlockGraph::Block* block, BlockGraph::Offset offset);
303 :
304 : // Constructs a 32-bit reference to @p block at the given @p offset and
305 : // @p base.
306 : // @param block The block to be referred to.
307 : // @param offset The offset to be literally referred to.
308 : // @param base The offset to be semantically referred to. This must be
309 : // within the data of @p block.
310 : BasicBlockAssembler::Displacement Displacement(BlockGraph::Block* block,
311 : BlockGraph::Offset offset,
312 : BlockGraph::Offset base);
313 :
314 : // Full constructor.
315 : // @param value The value to be stored.
316 : // @param size The size of the Displacement.
317 : // @param ref The untyped reference backing this Displacement. The reference
318 : // must be valid.
319 : BasicBlockAssembler::Displacement Displacement(uint32_t value,
320 : ValueSize size,
321 : const UntypedReference& ref);
322 :
323 : // @}
324 :
325 : // @name Operand factory functions.
326 : // @{
327 :
328 : // A register-indirect mode.
329 : BasicBlockAssembler::Operand Operand(const assm::Register32& base);
330 :
331 : // A register-indirect with displacement mode.
332 : BasicBlockAssembler::Operand Operand(
333 : const assm::Register32& base,
334 : const BasicBlockAssembler::Displacement& displ);
335 :
336 : // A displacement-only mode.
337 : BasicBlockAssembler::Operand Operand(
338 : const BasicBlockAssembler::Displacement& displ);
339 :
340 : // The full [base + index * scale + displ32] mode.
341 : // @note esp cannot be used as an index register.
342 : BasicBlockAssembler::Operand Operand(
343 : const assm::Register32& base, const assm::Register32& index,
344 : assm::ScaleFactor scale, const BasicBlockAssembler::Displacement& displ);
345 :
346 : // The full [base + index * scale] mode.
347 : // @note esp cannot be used as an index register.
348 : BasicBlockAssembler::Operand Operand(const assm::Register32& base,
349 : const assm::Register32& index,
350 : assm::ScaleFactor scale);
351 :
352 : // The [index * scale + displ32] mode.
353 : // @note esp cannot be used as an index register.
354 : BasicBlockAssembler::Operand Operand(
355 : const assm::Register32& index, assm::ScaleFactor scale,
356 : const BasicBlockAssembler::Displacement& displ);
357 :
358 : // @}
359 :
360 : } // namespace block_graph
361 :
362 : #endif // SYZYGY_BLOCK_GRAPH_BASIC_BLOCK_ASSEMBLER_H_
|