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 : // This file declares implementation classes to generate assembly code.
16 : // The API to the assembler is intentionally very close to the API exposed
17 : // by the V8 assembler (see src/ia32/assembler-ia32.* in V8 repository).
18 :
19 : #ifndef SYZYGY_CORE_ASSEMBLER_H_
20 : #define SYZYGY_CORE_ASSEMBLER_H_
21 :
22 : #include "syzygy/core/register.h"
23 :
24 : namespace core {
25 :
26 : // The condition codes by which conditional branches are determined. This enum
27 : // is taken from the V8 project, and has the property that the conditions are
28 : // defined to be bit-wise ORed into the base conditional branch opcode, and
29 : // they can be easily negated/inverted.
30 : //
31 : // See:
32 : // http://code.google.com/p/v8/source/browse/trunk/src/ia32/assembler-ia32.h
33 : enum ConditionCode {
34 : // Any value < 0 is considered no_condition
35 : kNoCondition = -1,
36 :
37 : kOverflow = 0,
38 : kNoOverflow = 1,
39 : kBelow = 2,
40 : kAboveEqual = 3,
41 : kEqual = 4,
42 : kNotEqual = 5,
43 : kBelowEqual = 6,
44 : kAbove = 7,
45 : kNegative = 8,
46 : kPositive = 9,
47 : kParityEven = 10,
48 : kParityOdd = 11,
49 : kLess = 12,
50 : kGreaterEqual = 13,
51 : kLessEqual = 14,
52 : kGreater = 15,
53 :
54 : // Aliases.
55 : kCarry = kBelow,
56 : kNotCarry = kAboveEqual,
57 : kZero = kEqual,
58 : kNotZero = kNotEqual,
59 : kSign = kNegative,
60 : kNotSign = kPositive,
61 :
62 : // Extents.
63 : kMinConditionCode = 0,
64 : kMaxConditionCode = 15
65 : };
66 :
67 : // The conditions on which a loop instruction should branch. These are modeled
68 : // in the same manner as ConditionCode (above).
69 : enum LoopCode {
70 : kLoopOnCounterAndNotZeroFlag = 0, // LOOPNE and LOOPNZ
71 : kLoopOnCounterAndZeroFlag = 1, // LOOPE and NOOPZ.
72 : kLoopOnCounter = 2, // LOOP.
73 : };
74 :
75 E : inline ConditionCode NegateConditionCode(ConditionCode cc) {
76 E : DCHECK_GT(16, cc);
77 E : return static_cast<ConditionCode>(cc ^ 1);
78 E : }
79 :
80 : // Selects a scale for the Operand addressing modes.
81 : // The values match the encoding in the x86 SIB bytes.
82 : enum ScaleFactor {
83 : kTimes1 = 0,
84 : kTimes2 = 1,
85 : kTimes4 = 2,
86 : kTimes8 = 3,
87 : };
88 :
89 : // We use the same enum for value sizes.
90 : typedef RegisterSize ValueSize;
91 :
92 : // An instance of this class is an explicit value, which is either
93 : // an immediate or a displacement.
94 : class ValueImpl {
95 : public:
96 : ValueImpl();
97 : ValueImpl(uint32 value, ValueSize size);
98 : ValueImpl(uint32 value, ValueSize size, const void* imm_ref);
99 :
100 : // @name Accessors.
101 : // @{
102 E : uint32 value() const { return value_; }
103 E : const void* reference() const { return reference_; }
104 E : ValueSize size() const { return size_; }
105 : // @}
106 :
107 : // Comparison operator.
108 : bool operator==(const ValueImpl& rhs) const;
109 :
110 : private:
111 : uint32 value_;
112 : const void* reference_;
113 : ValueSize size_;
114 : };
115 :
116 : // Displacements and immediates behave near-identically, but are semantically
117 : // slightly different.
118 : typedef ValueImpl ImmediateImpl;
119 : typedef ValueImpl DisplacementImpl;
120 :
121 : // An operand implies indirection to memory through one of the myriad
122 : // modes supported by IA32.
123 : class OperandImpl {
124 : public:
125 : // A register-indirect mode.
126 : explicit OperandImpl(const Register32& base);
127 :
128 : // A register-indirect with displacement mode.
129 : OperandImpl(const Register32& base, const DisplacementImpl& displ);
130 :
131 : // A displacement-only mode.
132 : explicit OperandImpl(const DisplacementImpl& displ);
133 :
134 : // The full [base + index * scale + displ32] mode.
135 : // @note esp cannot be used as an index register.
136 : OperandImpl(const Register32& base,
137 : const Register32& index,
138 : ScaleFactor scale,
139 : const DisplacementImpl& displ);
140 :
141 : // The [base + index * scale] mode.
142 : // @note esp cannot be used as an index register.
143 : OperandImpl(const Register32& base,
144 : const Register32& index,
145 : ScaleFactor scale);
146 :
147 : // The [index * scale + displ32] mode - e.g. no base.
148 : // @note esp cannot be used as an index register.
149 : OperandImpl(const Register32& index,
150 : ScaleFactor scale,
151 : const DisplacementImpl& displ);
152 :
153 : // Low-level constructor, none of the parameters are checked.
154 : OperandImpl(RegisterId base,
155 : RegisterId index,
156 : ScaleFactor scale,
157 : const DisplacementImpl& displacement);
158 :
159 : // @name Accessors.
160 : // @{
161 E : RegisterId base() const { return base_; }
162 E : RegisterId index() const { return index_; }
163 E : ScaleFactor scale() const { return scale_; }
164 E : const DisplacementImpl& displacement() const { return displacement_; }
165 : // @}
166 :
167 : private:
168 : // The base register involved, or none.
169 : RegisterId base_;
170 : // The index register involved, or none.
171 : RegisterId index_;
172 : // The scaling factor, must be kTimes1 if no index register.
173 : ScaleFactor scale_;
174 : // The displacement, if any.
175 : DisplacementImpl displacement_;
176 : };
177 :
178 : // The assembler takes care of maintaining an output location (address), and
179 : // generating a stream of bytes and references as instructions are assembled.
180 : class AssemblerImpl {
181 : public:
182 : // The assembler pushes instructions and references to
183 : // one of these for serialization.
184 : class InstructionSerializer {
185 : public:
186 : virtual void AppendInstruction(uint32 location,
187 : const uint8* bytes,
188 : size_t num_bytes,
189 : const size_t *ref_locations,
190 : const void* const* refs,
191 : size_t num_refs) = 0;
192 : };
193 :
194 : // Constructs an assembler that assembles to @p delegate
195 : // starting at @p location.
196 : AssemblerImpl(uint32 location, InstructionSerializer* serializer);
197 :
198 : // @name Accessors.
199 : // @{
200 E : uint32 location() const { return location_; }
201 E : void set_location(uint32 location) { location_ = location; }
202 : // @}
203 :
204 : // Emits one or more NOP instructions, their total length being @p size
205 : // bytes.
206 : // @param size The number of bytes of NOPs to generate.
207 : // @note For a generated NOP sequence of optimal performance it is best to
208 : // call nop once rather than successively (ie: the NOP sequence generated
209 : // by nop(x) nop(y) may perform worse than that generated by nop(x + y).
210 : void nop(size_t size);
211 :
212 : // @name Call instructions.
213 : // @{
214 : void call(const ImmediateImpl& dst);
215 : void call(const OperandImpl& dst);
216 : // @}
217 :
218 : // @name Control flow instructions.
219 : // @{
220 : void j(ConditionCode cc, const ImmediateImpl& dst);
221 : void jecxz(const ImmediateImpl& dst);
222 : void jmp(const ImmediateImpl& dst);
223 : void jmp(const OperandImpl& dst);
224 : void l(LoopCode lc, const ImmediateImpl& dst);
225 : void ret();
226 : void ret(uint16 n);
227 : // @}
228 :
229 : // @name Set flags.
230 : // @{
231 : void set(ConditionCode cc, const Register32& src);
232 : // @}
233 :
234 : // @name Byte mov varieties.
235 : // @{
236 : void mov_b(const OperandImpl& dst, const ImmediateImpl& src);
237 : void movzx_b(const Register32& dst, const OperandImpl& src);
238 : // @}
239 :
240 : // @name Double-word mov varieties.
241 : // @{
242 : void mov(const Register32& dst, const Register32& src);
243 : void mov(const Register32& dst, const OperandImpl& src);
244 : void mov(const OperandImpl& dst, const Register32& src);
245 : void mov(const Register32& dst, const ImmediateImpl& src);
246 : void mov(const OperandImpl& dst, const ImmediateImpl& src);
247 : void mov_fs(const Register32& dst, const OperandImpl& src);
248 : void mov_fs(const OperandImpl& dst, const Register32& src);
249 : // @}
250 :
251 : // @name Load effective address.
252 : void lea(const Register32& dst, const OperandImpl& src);
253 :
254 : // @name Stack manipulation.
255 : // @{
256 : void push(const Register32& src);
257 : void push(const ImmediateImpl& src);
258 : void push(const OperandImpl& src);
259 :
260 : void pop(const Register32& dst);
261 : void pop(const OperandImpl& dst);
262 : // @}
263 :
264 : // @name Manipulation of flags.
265 : // @{
266 : void pushfd();
267 : void popfd();
268 : void lahf();
269 : void sahf();
270 : // @}
271 :
272 : // @name Arithmetic operations.
273 : // @{
274 : void test(const Register8& dst, const Register8& src);
275 : void test(const Register8& dst, const ImmediateImpl& src);
276 :
277 : void test(const Register32& dst, const Register32& src);
278 : void test(const Register32& dst, const OperandImpl& src);
279 : void test(const OperandImpl& dst, const Register32& src);
280 : void test(const Register32& dst, const ImmediateImpl& src);
281 : void test(const OperandImpl& dst, const ImmediateImpl& src);
282 :
283 : void cmp(const Register8& dst, const Register8& src);
284 : void cmp(const Register8& dst, const ImmediateImpl& src);
285 :
286 : void cmp(const Register32& dst, const Register32& src);
287 : void cmp(const Register32& dst, const OperandImpl& src);
288 : void cmp(const OperandImpl& dst, const Register32& src);
289 : void cmp(const Register32& dst, const ImmediateImpl& src);
290 : void cmp(const OperandImpl& dst, const ImmediateImpl& src);
291 :
292 : void add(const Register8& dst, const Register8& src);
293 : void add(const Register8& dst, const ImmediateImpl& src);
294 :
295 : void add(const Register32& dst, const Register32& src);
296 : void add(const Register32& dst, const OperandImpl& src);
297 : void add(const OperandImpl& dst, const Register32& src);
298 : void add(const Register32& dst, const ImmediateImpl& src);
299 : void add(const OperandImpl& dst, const ImmediateImpl& src);
300 :
301 : void sub(const Register8& dst, const Register8& src);
302 : void sub(const Register8& dst, const ImmediateImpl& src);
303 :
304 : void sub(const Register32& dst, const Register32& src);
305 : void sub(const Register32& dst, const OperandImpl& src);
306 : void sub(const OperandImpl& dst, const Register32& src);
307 : void sub(const Register32& dst, const ImmediateImpl& src);
308 : void sub(const OperandImpl& dst, const ImmediateImpl& src);
309 : // @}
310 :
311 : // @name Shifting operations.
312 : // @{
313 : void shl(const Register32& dst, const ImmediateImpl& src);
314 : void shr(const Register32& dst, const ImmediateImpl& src);
315 : // @}
316 :
317 : // Exchange contents of two registers.
318 : // @param dst The destination register.
319 : // @param src The source register.
320 : // @note Exchanges involving eax generate shorter byte code.
321 : // @note This instruction can be used as a primitive for writing
322 : // synchronization mechanisms as there is an implicit lock taken
323 : // during execution.
324 : void xchg(const Register32& dst, const Register32& src);
325 : void xchg(const Register16& dst, const Register16& src);
326 : void xchg(const Register8& dst, const Register8& src);
327 :
328 : // @name Aliases
329 : // @{
330 E : void loop(const ImmediateImpl& dst) { l(kLoopOnCounter, dst); }
331 E : void loope(const ImmediateImpl& dst) { l(kLoopOnCounterAndZeroFlag, dst); }
332 E : void loopne(const ImmediateImpl& dst) {
333 E : l(kLoopOnCounterAndNotZeroFlag, dst);
334 E : }
335 : // @}
336 :
337 : // Size of an 8 bit reach branch opcode.
338 : static const size_t kShortBranchOpcodeSize;
339 : // Size of an 8 bit reach branch.
340 : static const size_t kShortBranchSize;
341 :
342 : // Size of a 32 bit reach branch op code.
343 : static const size_t kLongBranchOpcodeSize;
344 : // Size of an 8bit reach branch.
345 : static const size_t kLongBranchSize;
346 :
347 : // Size of an 8 bit reach jump opcode.
348 : static const size_t kShortJumpOpcodeSize;
349 : // Size of an 8 bit reach jump.
350 : static const size_t kShortJumpSize;
351 :
352 : // Size of a 32 bit reach jump op code.
353 : static const size_t kLongJumpOpcodeSize;
354 : // Size of an 8bit reach jump.
355 : static const size_t kLongJumpSize;
356 :
357 : // The maximum length a single instruction will assemble to.
358 : // No instruction on x86 can exceed 15 bytes, per specs.
359 : static const size_t kMaxInstructionLength = 15;
360 :
361 : private:
362 : class InstructionBuffer;
363 :
364 : // @name Nop instruction helpers.
365 : // @{
366 : // Each of these corresponds to a basic suggested NOP sequence. They
367 : // can each be extended by prefixing with 1 or more operand size (0x66)
368 : // prefixes. These are not exposed directly as the user should simply
369 : // call 'nop' instead.
370 : // @param prefix_count The number of operand size prefix bytes to apply.
371 : void nop1(size_t prefix_count);
372 : void nop4(size_t prefix_count);
373 : void nop5(size_t prefix_count);
374 : void nop7(size_t prefix_count);
375 : void nop8(size_t prefix_count);
376 : // @}
377 :
378 : // Output the instruction data in @p instr to our delegate.
379 : void Output(const InstructionBuffer& instr);
380 :
381 : // Stores the current location of assembly.
382 : uint32 location_;
383 :
384 : // The delegate we push instructions at.
385 : InstructionSerializer* serializer_;
386 : };
387 :
388 : } // namespace core
389 :
390 : #endif // SYZYGY_CORE_ASSEMBLER_H_
|