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