1 : // Copyright 2014 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_ASSM_ASSEMBLER_BASE_H_
20 : #define SYZYGY_ASSM_ASSEMBLER_BASE_H_
21 :
22 : #include "syzygy/assm/cond.h"
23 : #include "syzygy/assm/label_base.h"
24 : #include "syzygy/assm/operand_base.h"
25 : #include "syzygy/assm/register.h"
26 : #include "syzygy/assm/value_base.h"
27 :
28 : namespace assm {
29 :
30 : // The reference sizes the assembler supports coincides with register sizes.
31 : typedef RegisterSize ReferenceSize;
32 :
33 : // The assembler takes care of maintaining an output location (address), and
34 : // generating a stream of bytes and references as instructions are assembled.
35 : template <class ReferenceType>
36 : class AssemblerBase {
37 : public:
38 : typedef DisplacementBase<ReferenceType> Displacement;
39 : typedef ImmediateBase<ReferenceType> Immediate;
40 : typedef OperandBase<ReferenceType> Operand;
41 : typedef LabelBase<ReferenceType> Label;
42 :
43 : // Tracks a single embedded reference in the instruction.
44 : struct ReferenceInfo {
45 : size_t offset;
46 : ReferenceType reference;
47 : ReferenceSize size;
48 : bool pc_relative;
49 : };
50 :
51 : // The assembler pushes instructions and references to
52 : // one of these for serialization.
53 : class InstructionSerializer {
54 : public:
55 : virtual void AppendInstruction(uint32 location,
56 : const uint8* bytes,
57 : size_t num_bytes,
58 : const ReferenceInfo* refs,
59 : size_t num_refs) = 0;
60 : virtual bool FinalizeLabel(uint32 location,
61 : const uint8* bytes,
62 : size_t num_bytes) = 0;
63 : };
64 :
65 : // Constructs an assembler that assembles to @p delegate
66 : // starting at @p location.
67 : AssemblerBase(uint32 location, InstructionSerializer* serializer);
68 :
69 : // @name Accessors.
70 : // @{
71 E : uint32 location() const { return location_; }
72 E : void set_location(uint32 location) { location_ = location; }
73 : // @}
74 :
75 : // Emits one or more NOP instructions, their total length being @p size
76 : // bytes.
77 : // @param size The number of bytes of NOPs to generate.
78 : // @note For a generated NOP sequence of optimal performance it is best to
79 : // call nop once rather than successively (ie: the NOP sequence generated
80 : // by nop(x) nop(y) may perform worse than that generated by nop(x + y).
81 : void nop(size_t size);
82 :
83 : // @name Call instructions.
84 : // @{
85 : void call(const Immediate& dst);
86 : void call(const Operand& dst);
87 : // @}
88 :
89 : protected:
90 : // @name Control flow instructions.
91 : // These instructions are protected, as they're not appropriate to expose
92 : // for all assembler subclasses.
93 : // @{
94 : void j(ConditionCode cc, const Immediate& dst);
95 :
96 : // @param cc the condition code to generate.
97 : // @param dst the label to jump to.
98 : // @param size the requested size/reach of the instruction. Will generate the
99 : // optimal reach if kSizeNone and the label is bound. Will generate long
100 : // reach if kSizeNone and the label is unbound.
101 : // @returns true if successful, false if the requested reach is
102 : // inappropriate.
103 : bool j(ConditionCode cc, Label* dst, RegisterSize size);
104 : bool j(ConditionCode cc, Label* dst);
105 : void jecxz(const Immediate& dst);
106 : void jmp(const Immediate& dst);
107 : void jmp(const Operand& dst);
108 : void jmp(const Register32& dst);
109 : void l(LoopCode lc, const Immediate& dst);
110 :
111 : public:
112 : void ret();
113 : void ret(uint16 n);
114 : // @}
115 :
116 : // @name Set flags.
117 : // @{
118 : void set(ConditionCode cc, const Register32& src);
119 : // @}
120 :
121 : // @name Byte mov varieties.
122 : // @{
123 : void mov_b(const Operand& dst, const Immediate& src);
124 : void movzx_b(const Register32& dst, const Operand& src);
125 : // @}
126 :
127 : // @name Double-word mov varieties.
128 : // @{
129 : void mov(const Register32& dst, const Register32& src);
130 : void mov(const Register32& dst, const Operand& src);
131 : void mov(const Operand& dst, const Register32& src);
132 : void mov(const Register32& dst, const Immediate& src);
133 : void mov(const Operand& dst, const Immediate& src);
134 : void mov_fs(const Register32& dst, const Operand& src);
135 : void mov_fs(const Operand& dst, const Register32& src);
136 : // @}
137 :
138 : // @name Load effective address.
139 : void lea(const Register32& dst, const Operand& src);
140 :
141 : // @name Stack manipulation.
142 : // @{
143 : void push(const Register32& src);
144 : void push(const Immediate& src);
145 : void push(const Operand& src);
146 : void pushad();
147 :
148 : void pop(const Register32& dst);
149 : void pop(const Operand& dst);
150 : void popad();
151 : // @}
152 :
153 : // @name Flag manipulation.
154 : // @{
155 : void pushfd();
156 : void popfd();
157 : void lahf();
158 : void sahf();
159 : // @}
160 :
161 : // @name Arithmetic operations.
162 : // @{
163 : void test(const Register8& dst, const Register8& src);
164 : void test(const Register8& dst, const Immediate& src);
165 :
166 : void test(const Register32& dst, const Register32& src);
167 : void test(const Register32& dst, const Operand& src);
168 : void test(const Operand& dst, const Register32& src);
169 : void test(const Register32& dst, const Immediate& src);
170 : void test(const Operand& dst, const Immediate& src);
171 :
172 : void cmp(const Register8& dst, const Register8& src);
173 : void cmp(const Register8& dst, const Immediate& src);
174 :
175 : void cmp(const Register32& dst, const Register32& src);
176 : void cmp(const Register32& dst, const Operand& src);
177 : void cmp(const Operand& dst, const Register32& src);
178 : void cmp(const Register32& dst, const Immediate& src);
179 : void cmp(const Operand& dst, const Immediate& src);
180 :
181 : void add(const Register8& dst, const Register8& src);
182 : void add(const Register8& dst, const Immediate& src);
183 :
184 : void add(const Register32& dst, const Register32& src);
185 : void add(const Register32& dst, const Operand& src);
186 : void add(const Operand& dst, const Register32& src);
187 : void add(const Register32& dst, const Immediate& src);
188 : void add(const Operand& dst, const Immediate& src);
189 :
190 : void sub(const Register8& dst, const Register8& src);
191 : void sub(const Register8& dst, const Immediate& src);
192 :
193 : void sub(const Register32& dst, const Register32& src);
194 : void sub(const Register32& dst, const Operand& src);
195 : void sub(const Operand& dst, const Register32& src);
196 : void sub(const Register32& dst, const Immediate& src);
197 : void sub(const Operand& dst, const Immediate& src);
198 : // @}
199 :
200 : // @name Logical operations.
201 : // @{
202 : void and(const Register8& dst, const Register8& src);
203 : void and(const Register8& dst, const Immediate& src);
204 :
205 : void and(const Register32& dst, const Register32& src);
206 : void and(const Register32& dst, const Operand& src);
207 : void and(const Operand& dst, const Register32& src);
208 : void and(const Register32& dst, const Immediate& src);
209 : void and(const Operand& dst, const Immediate& src);
210 :
211 : void xor(const Register8& dst, const Register8& src);
212 : void xor(const Register8& dst, const Immediate& src);
213 :
214 : void xor(const Register32& dst, const Register32& src);
215 : void xor(const Register32& dst, const Operand& src);
216 : void xor(const Operand& dst, const Register32& src);
217 : void xor(const Register32& dst, const Immediate& src);
218 : void xor(const Operand& dst, const Immediate& src);
219 : // @}
220 :
221 : // @name Shifting operations.
222 : // @{
223 : void shl(const Register32& dst, const Immediate& src);
224 : void shr(const Register32& dst, const Immediate& src);
225 : // @}
226 :
227 : // Exchange contents of two registers.
228 : // @param dst The destination register.
229 : // @param src The source register.
230 : // @note Exchanges involving eax generate shorter byte code.
231 : void xchg(const Register32& dst, const Register32& src);
232 : void xchg(const Register16& dst, const Register16& src);
233 : void xchg(const Register8& dst, const Register8& src);
234 :
235 : // Exchange contents of a register and memory.
236 : // @param dst The destination register.
237 : // @param src The source memory location.
238 : // @note This instruction can be used as a primitive for writing
239 : // synchronization mechanisms as there is an implicit lock taken
240 : // on @p src during execution.
241 : void xchg(const Register32& dst, const Operand& src);
242 :
243 : // @name Aliases
244 : // @{
245 E : void loop(const Immediate& dst) { l(kLoopOnCounter, dst); }
246 E : void loope(const Immediate& dst) { l(kLoopOnCounterAndZeroFlag, dst); }
247 E : void loopne(const Immediate& dst) {
248 E : l(kLoopOnCounterAndNotZeroFlag, dst);
249 E : }
250 : // @}
251 :
252 : private:
253 : friend class Label;
254 : class InstructionBuffer;
255 :
256 : // @name Nop instruction helpers.
257 : // @{
258 : // Each of these corresponds to a basic suggested NOP sequence. They
259 : // can each be extended by prefixing with 1 or more operand size (0x66)
260 : // prefixes. These are not exposed directly as the user should simply
261 : // call 'nop' instead.
262 : // @param prefix_count The number of operand size prefix bytes to apply.
263 : void nop1(size_t prefix_count);
264 : void nop4(size_t prefix_count);
265 : void nop5(size_t prefix_count);
266 : void nop7(size_t prefix_count);
267 : void nop8(size_t prefix_count);
268 : // @}
269 :
270 : // Output the instruction data in @p instr to our delegate.
271 : void Output(const InstructionBuffer& instr);
272 :
273 : // Finalizes the use of an unbound label.
274 : bool FinalizeLabel(uint32 location, uint32 destination, RegisterSize size);
275 :
276 : // Stores the current location of assembly.
277 : uint32 location_;
278 :
279 : // The delegate we push instructions at.
280 : InstructionSerializer* serializer_;
281 : };
282 :
283 : } // namespace assm
284 :
285 : #include "syzygy/assm/assembler_base_impl.h"
286 :
287 : #endif // SYZYGY_ASSM_ASSEMBLER_BASE_H_
|