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 l(LoopCode lc, const Immediate& dst);
109 :
110 : public:
111 : void ret();
112 : void ret(uint16 n);
113 : // @}
114 :
115 : // @name Set flags.
116 : // @{
117 : void set(ConditionCode cc, const Register32& src);
118 : // @}
119 :
120 : // @name Byte mov varieties.
121 : // @{
122 : void mov_b(const Operand& dst, const Immediate& src);
123 : void movzx_b(const Register32& dst, const Operand& src);
124 : // @}
125 :
126 : // @name Double-word mov varieties.
127 : // @{
128 : void mov(const Register32& dst, const Register32& src);
129 : void mov(const Register32& dst, const Operand& src);
130 : void mov(const Operand& dst, const Register32& src);
131 : void mov(const Register32& dst, const Immediate& src);
132 : void mov(const Operand& dst, const Immediate& src);
133 : void mov_fs(const Register32& dst, const Operand& src);
134 : void mov_fs(const Operand& dst, const Register32& src);
135 : // @}
136 :
137 : // @name Load effective address.
138 : void lea(const Register32& dst, const Operand& src);
139 :
140 : // @name Stack manipulation.
141 : // @{
142 : void push(const Register32& src);
143 : void push(const Immediate& src);
144 : void push(const Operand& src);
145 : void pushad();
146 :
147 : void pop(const Register32& dst);
148 : void pop(const Operand& dst);
149 : void popad();
150 : // @}
151 :
152 : // @name Flag manipulation.
153 : // @{
154 : void pushfd();
155 : void popfd();
156 : void lahf();
157 : void sahf();
158 : // @}
159 :
160 : // @name Arithmetic operations.
161 : // @{
162 : void test(const Register8& dst, const Register8& src);
163 : void test(const Register8& dst, const Immediate& src);
164 :
165 : void test(const Register32& dst, const Register32& src);
166 : void test(const Register32& dst, const Operand& src);
167 : void test(const Operand& dst, const Register32& src);
168 : void test(const Register32& dst, const Immediate& src);
169 : void test(const Operand& dst, const Immediate& src);
170 :
171 : void cmp(const Register8& dst, const Register8& src);
172 : void cmp(const Register8& dst, const Immediate& src);
173 :
174 : void cmp(const Register32& dst, const Register32& src);
175 : void cmp(const Register32& dst, const Operand& src);
176 : void cmp(const Operand& dst, const Register32& src);
177 : void cmp(const Register32& dst, const Immediate& src);
178 : void cmp(const Operand& dst, const Immediate& src);
179 :
180 : void add(const Register8& dst, const Register8& src);
181 : void add(const Register8& dst, const Immediate& src);
182 :
183 : void add(const Register32& dst, const Register32& src);
184 : void add(const Register32& dst, const Operand& src);
185 : void add(const Operand& dst, const Register32& src);
186 : void add(const Register32& dst, const Immediate& src);
187 : void add(const Operand& dst, const Immediate& src);
188 :
189 : void sub(const Register8& dst, const Register8& src);
190 : void sub(const Register8& dst, const Immediate& src);
191 :
192 : void sub(const Register32& dst, const Register32& src);
193 : void sub(const Register32& dst, const Operand& src);
194 : void sub(const Operand& dst, const Register32& src);
195 : void sub(const Register32& dst, const Immediate& src);
196 : void sub(const Operand& dst, const Immediate& src);
197 : // @}
198 :
199 : // @name Shifting operations.
200 : // @{
201 : void shl(const Register32& dst, const Immediate& src);
202 : void shr(const Register32& dst, const Immediate& src);
203 : // @}
204 :
205 : // Exchange contents of two registers.
206 : // @param dst The destination register.
207 : // @param src The source register.
208 : // @note Exchanges involving eax generate shorter byte code.
209 : void xchg(const Register32& dst, const Register32& src);
210 : void xchg(const Register16& dst, const Register16& src);
211 : void xchg(const Register8& dst, const Register8& src);
212 :
213 : // Exchange contents of a register and memory.
214 : // @param dst The destination register.
215 : // @param src The source memory location.
216 : // @note This instruction can be used as a primitive for writing
217 : // synchronization mechanisms as there is an implicit lock taken
218 : // on @p src during execution.
219 : void xchg(const Register32& dst, const Operand& src);
220 :
221 : // @name Aliases
222 : // @{
223 E : void loop(const Immediate& dst) { l(kLoopOnCounter, dst); }
224 E : void loope(const Immediate& dst) { l(kLoopOnCounterAndZeroFlag, dst); }
225 E : void loopne(const Immediate& dst) {
226 E : l(kLoopOnCounterAndNotZeroFlag, dst);
227 E : }
228 : // @}
229 :
230 : private:
231 : friend class Label;
232 : class InstructionBuffer;
233 :
234 : // @name Nop instruction helpers.
235 : // @{
236 : // Each of these corresponds to a basic suggested NOP sequence. They
237 : // can each be extended by prefixing with 1 or more operand size (0x66)
238 : // prefixes. These are not exposed directly as the user should simply
239 : // call 'nop' instead.
240 : // @param prefix_count The number of operand size prefix bytes to apply.
241 : void nop1(size_t prefix_count);
242 : void nop4(size_t prefix_count);
243 : void nop5(size_t prefix_count);
244 : void nop7(size_t prefix_count);
245 : void nop8(size_t prefix_count);
246 : // @}
247 :
248 : // Output the instruction data in @p instr to our delegate.
249 : void Output(const InstructionBuffer& instr);
250 :
251 : // Finalizes the use of an unbound label.
252 : bool FinalizeLabel(uint32 location, uint32 destination, RegisterSize size);
253 :
254 : // Stores the current location of assembly.
255 : uint32 location_;
256 :
257 : // The delegate we push instructions at.
258 : InstructionSerializer* serializer_;
259 : };
260 :
261 : } // namespace assm
262 :
263 : #include "syzygy/assm/assembler_base_impl.h"
264 :
265 : #endif // SYZYGY_ASSM_ASSEMBLER_BASE_H_
|