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