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