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 : #ifndef SYZYGY_ASSM_ASSEMBLER_BASE_IMPL_H_
16 : #define SYZYGY_ASSM_ASSEMBLER_BASE_IMPL_H_
17 :
18 : #ifndef SYZYGY_ASSM_ASSEMBLER_BASE_H_
19 : #error Do not include this file directly.
20 : #endif // SYZYGY_ASSM_ASSEMBLER_BASE_H_
21 :
22 : #include <stdint.h>
23 : #include <limits>
24 :
25 : #include "syzygy/assm/const.h"
26 :
27 : namespace assm {
28 :
29 : // This class is used to buffer a single instruction during its creation.
30 : // TODO(siggi): Add a small state machine in debug mode to ensure the
31 : // correct order of invocation to opcode/modrm etc.
32 : // @note @p ReferenceType must either be a pointer type, or else have
33 : // a method bool IsValid() const.
34 : template <class ReferenceType>
35 : class AssemblerBase<ReferenceType>::InstructionBuffer {
36 : public:
37 : explicit InstructionBuffer(AssemblerBase* assm);
38 : ~InstructionBuffer();
39 :
40 : // @name Accessors.
41 : // @{
42 E : size_t len() const { return len_; }
43 E : const uint8* buf() const { return buf_; }
44 E : size_t num_reference_infos() const { return num_reference_infos_; }
45 E : const ReferenceInfo* reference_infos() const { return reference_infos_; }
46 : // @}
47 :
48 : // Emits operand size prefix (0x66) bytes.
49 : // @param count The number of operand size prefix bytes to emit.
50 : void EmitOperandSizePrefix(size_t count);
51 : // Emit an opcode byte.
52 : void EmitOpCodeByte(uint8 opcode);
53 : // Emit a ModR/M byte with an opcode extension.
54 : void EmitModRMByte(Mod mod, uint8 op, RegisterId reg1);
55 : // Emit a ModR/M byte with a destination register.
56 : void EmitModRMByte(Mod mod, RegisterId reg2, RegisterId reg1);
57 : // Emit a SIB byte.
58 : void EmitScaleIndexBaseByte(ScaleFactor scale,
59 : RegisterId index,
60 : RegisterId base);
61 : // Emit an operand.
62 : void EmitOperand(uint8 reg_op, const Operand& op);
63 :
64 : // Emit an 8-bit displacement, with optional reference info.
65 : void Emit8BitDisplacement(const Displacement& disp);
66 : // Emit an 8-bit immediate, with optional reference info.
67 : void Emit8BitImmediate(const Immediate& disp);
68 :
69 : // Emit a 32-bit displacement with optional reference info.
70 : void Emit32BitDisplacement(const Displacement& disp);
71 :
72 : // Emit a 32-bit immediate with optional reference info.
73 : void Emit32BitImmediate(const Immediate& disp);
74 :
75 : // Emit an 8-bit PC-relative value.
76 : void Emit8BitPCRelative(uint32 location, const Immediate& imm);
77 :
78 : // Emit a 32-bit PC-relative value.
79 : void Emit32BitPCRelative(uint32 location, const Immediate& imm);
80 :
81 : // Emit a 16-bit immediate value.
82 : void Emit16BitValue(uint16 value);
83 :
84 : // Emit an arithmetic instruction with various encoding.
85 : void EmitArithmeticInstruction(
86 : uint8 op, const Register& dst, const Register& src);
87 : void EmitArithmeticInstruction(
88 : uint8 op, const Register& dst, const Operand& src);
89 : void EmitArithmeticInstruction(
90 : uint8 op, const Operand& dst, const Register32& src);
91 : void EmitArithmeticInstructionToRegister32(uint8 op_eax, uint8 op_8,
92 : uint8 op_32, uint8 sub_op, const Register32& dst,
93 : const Immediate& src);
94 : void EmitArithmeticInstructionToRegister8(uint8 op_eax, uint8 op_8,
95 : uint8 sub_op, const Register8& dst, const Immediate& src);
96 : void EmitArithmeticInstructionToOperand(uint8 op_8, uint8 op_32,
97 : uint8 sub_op, const Operand& dst, const Immediate& src);
98 :
99 : // Emit an XCHG instruction.
100 : void EmitXchg(ValueSize size, RegisterId dst, RegisterId src);
101 :
102 : // Add reference at current location.
103 : void AddReference(const ReferenceType& reference,
104 : RegisterSize size,
105 : bool pc_relative);
106 :
107 : protected:
108 : void EmitByte(uint8 byte);
109 :
110 : AssemblerBase* asm_;
111 : size_t num_reference_infos_;
112 : ReferenceInfo reference_infos_[2];
113 : size_t len_;
114 : uint8 buf_[kMaxInstructionLength];
115 : };
116 :
117 : namespace details {
118 :
119 : template <class ReferenceType>
120 E : bool IsValidReference(const ReferenceType* ref) {
121 E : return ref != NULL;
122 E : }
123 :
124 : template <class ReferenceType>
125 E : bool IsValidReference(const ReferenceType& ref) {
126 E : return ref.IsValid();
127 E : }
128 :
129 : } // namespace details
130 :
131 : // Returns true if @p operand is a displacement only - e.g.
132 : // specifies neither a base, nor an index register.
133 : template <class ReferenceType>
134 E : bool IsDisplacementOnly(const OperandBase<ReferenceType>& operand) {
135 : return operand.displacement().size() != kSizeNone &&
136 : operand.base() == kRegisterNone &&
137 E : operand.index() == kRegisterNone;
138 E : }
139 :
140 : template <class ReferenceType>
141 : AssemblerBase<ReferenceType>::InstructionBuffer::InstructionBuffer(
142 E : AssemblerBase* assm) : asm_(assm), len_(0), num_reference_infos_(0) {
143 E : DCHECK(assm != NULL);
144 : #ifndef NDEBUG
145 : // Initialize the buffer in debug mode for easier debugging.
146 E : ::memset(buf_, 0xCC, sizeof(buf_));
147 : #endif
148 E : }
149 :
150 : template <class ReferenceType>
151 E : AssemblerBase<ReferenceType>::InstructionBuffer::~InstructionBuffer() {
152 E : asm_->Output(*this);
153 E : }
154 :
155 : template <class ReferenceType>
156 : void AssemblerBase<ReferenceType>::InstructionBuffer::EmitOperandSizePrefix(
157 E : size_t count) {
158 E : for (size_t i = 0; i < count; ++i)
159 E : EmitByte(kOperandSizePrefix);
160 E : }
161 :
162 : template <class ReferenceType>
163 : void AssemblerBase<ReferenceType>::InstructionBuffer::EmitOpCodeByte(
164 E : uint8 opcode) {
165 E : EmitByte(opcode);
166 E : }
167 :
168 : template <class ReferenceType>
169 : void AssemblerBase<ReferenceType>::InstructionBuffer::EmitModRMByte(
170 E : Mod mod, uint8 reg_op, RegisterId reg1) {
171 E : DCHECK_LE(reg_op, 8);
172 E : DCHECK_NE(kRegisterNone, reg1);
173 E : EmitByte((mod << 6) | (reg_op << 3) | Register::Code(reg1));
174 E : }
175 :
176 : template <class ReferenceType>
177 : void AssemblerBase<ReferenceType>::InstructionBuffer::EmitModRMByte(
178 E : Mod mod, RegisterId reg2, RegisterId reg1) {
179 E : DCHECK_NE(kRegisterNone, reg2);
180 E : DCHECK_NE(kRegisterNone, reg1);
181 E : EmitModRMByte(mod, Register::Code(reg2), reg1);
182 E : }
183 :
184 : template <class ReferenceType>
185 : void AssemblerBase<ReferenceType>::InstructionBuffer::EmitScaleIndexBaseByte(
186 E : ScaleFactor scale, RegisterId index, RegisterId base) {
187 E : DCHECK_NE(kRegisterNone, index);
188 E : DCHECK_NE(kRegisterNone, base);
189 :
190 E : EmitByte((scale << 6) | (Register::Code(index) << 3) | Register::Code(base));
191 E : }
192 :
193 : template <class ReferenceType>
194 : void AssemblerBase<ReferenceType>::InstructionBuffer::EmitOperand(
195 E : uint8 reg_op, const Operand& op) {
196 E : DCHECK_GE(8, reg_op);
197 :
198 : // The op operand can encode any one of the following things:
199 : // An indirect register access [EAX].
200 : // An indirect 32-bit displacement only [0xDEADBEEF].
201 : // An indirect base register + 32/8-bit displacement [EAX+0xDEADBEEF].
202 : // An indirect base + index register*scale [EAX+ECX*4].
203 : // An indirect base + index register*scale + 32/8-bit displacement
204 : // [EAX+ECX*4+0xDEADBEEF].
205 : // To complicate things, there are certain combinations that can't be encoded
206 : // canonically. The mode [ESP] or [ESP+disp] can never be encoded in a
207 : // ModR/M byte alone, as ESP in the ModR/M byte for any of the indirect modes
208 : // is overloaded to select the SIB representation.
209 : // Likewise [EBP] is overloaded to encode the [disp32] case.
210 : // See e.g. http://ref.x86asm.net/geek32-abc.html#modrm_byte_32 for a nice
211 : // overview table of the ModR/M byte encoding.
212 :
213 : // ESP can never be used as an index register on X86.
214 E : DCHECK_NE(kRegisterEsp, op.index());
215 :
216 : // Is there an index register?
217 E : if (op.index() == kRegisterNone) {
218 E : DCHECK_EQ(kTimes1, op.scale());
219 :
220 : // No index register, is there a base register?
221 E : if (op.base() == kRegisterNone) {
222 : // No base register, this is a displacement only.
223 E : DCHECK_NE(kSizeNone, op.displacement().size());
224 E : DCHECK_EQ(kTimes1, op.scale());
225 :
226 : // The [disp32] mode is encoded by overloading [EBP].
227 E : EmitModRMByte(kReg1Ind, reg_op, kRegisterEbp);
228 E : Emit32BitDisplacement(op.displacement());
229 E : } else {
230 : // Base register only, is it ESP?
231 E : if (op.base() == kRegisterEsp) {
232 : // The [ESP] and [ESP+disp] cases cannot be encoded without a SIB byte.
233 E : if (op.displacement().size() == kSizeNone) {
234 E : EmitModRMByte(kReg1Ind, reg_op, kRegisterEsp);
235 E : EmitScaleIndexBaseByte(kTimes1, kRegisterEsp, kRegisterEsp);
236 E : } else if (op.displacement().size() == kSize8Bit) {
237 E : EmitModRMByte(kReg1ByteDisp, reg_op, kRegisterEsp);
238 E : EmitScaleIndexBaseByte(kTimes1, kRegisterEsp, kRegisterEsp);
239 E : Emit8BitDisplacement(op.displacement());
240 E : } else {
241 E : DCHECK_EQ(kSize32Bit, op.displacement().size());
242 E : EmitModRMByte(kReg1WordDisp, reg_op, kRegisterEsp);
243 E : EmitScaleIndexBaseByte(kTimes1, kRegisterEsp, kRegisterEsp);
244 E : Emit32BitDisplacement(op.displacement());
245 E : }
246 E : } else if (op.displacement().size() == kSizeNone) {
247 E : if (op.base() == kRegisterEbp) {
248 : // The [EBP] case cannot be encoded canonically, there always must
249 : // be a (zero) displacement.
250 E : EmitModRMByte(kReg1ByteDisp, reg_op, op.base());
251 : Emit8BitDisplacement(
252 E : Displacement(0, kSize8Bit, ReferenceType()));
253 E : } else {
254 E : EmitModRMByte(kReg1Ind, reg_op, op.base());
255 E : }
256 E : } else if (op.displacement().size() == kSize8Bit) {
257 : // It's [base+disp8], or possibly [EBP].
258 E : EmitModRMByte(kReg1ByteDisp, reg_op, op.base());
259 E : Emit8BitDisplacement(op.displacement());
260 E : } else {
261 E : DCHECK_EQ(kSize32Bit, op.displacement().size());
262 : // It's [base+disp32].
263 E : EmitModRMByte(kReg1WordDisp, reg_op, op.base());
264 E : Emit32BitDisplacement(op.displacement());
265 : }
266 E : }
267 E : } else if (op.base() == kRegisterNone) {
268 : // Index, no base.
269 E : DCHECK_NE(kRegisterNone, op.index());
270 E : DCHECK_EQ(kRegisterNone, op.base());
271 :
272 : // This mode always has a 32 bit displacement.
273 E : EmitModRMByte(kReg1Ind, reg_op, kRegisterEsp);
274 E : EmitScaleIndexBaseByte(op.scale(), op.index(), kRegisterEbp);
275 E : Emit32BitDisplacement(op.displacement());
276 E : } else {
277 : // Index and base case.
278 E : DCHECK_NE(kRegisterNone, op.index());
279 E : DCHECK_NE(kRegisterNone, op.base());
280 :
281 : // Is there a displacement?
282 E : if (op.displacement().size() == kSizeNone) {
283 E : EmitModRMByte(kReg1Ind, reg_op, kRegisterEsp);
284 E : EmitScaleIndexBaseByte(op.scale(), op.index(), op.base());
285 E : } else if (op.displacement().size() == kSize8Bit) {
286 E : EmitModRMByte(kReg1ByteDisp, reg_op, kRegisterEsp);
287 E : EmitScaleIndexBaseByte(op.scale(), op.index(), op.base());
288 E : Emit8BitDisplacement(op.displacement());
289 E : } else {
290 E : DCHECK_EQ(kSize32Bit, op.displacement().size());
291 E : EmitModRMByte(kReg1WordDisp, reg_op, kRegisterEsp);
292 E : EmitScaleIndexBaseByte(op.scale(), op.index(), op.base());
293 E : Emit32BitDisplacement(op.displacement());
294 : }
295 : }
296 E : }
297 :
298 : template <class ReferenceType>
299 : void AssemblerBase<ReferenceType>::InstructionBuffer::Emit8BitDisplacement(
300 E : const Displacement& disp) {
301 E : DCHECK(disp.size() == kSize8Bit);
302 :
303 E : AddReference(disp.reference(), kSize8Bit, false);
304 :
305 E : EmitByte(disp.value());
306 E : }
307 :
308 : template <class ReferenceType>
309 : void AssemblerBase<ReferenceType>::InstructionBuffer::Emit8BitImmediate(
310 E : const Immediate& imm) {
311 E : DCHECK(imm.size() == kSize8Bit);
312 :
313 E : AddReference(imm.reference(), kSize8Bit, false);
314 :
315 E : EmitByte(imm.value());
316 E : }
317 :
318 : template <class ReferenceType>
319 : void AssemblerBase<ReferenceType>::InstructionBuffer::Emit32BitDisplacement(
320 E : const Displacement& disp) {
321 E : AddReference(disp.reference(), kSize32Bit, false);
322 :
323 E : uint32 value = disp.value();
324 E : EmitByte(value);
325 E : EmitByte(value >> 8);
326 E : EmitByte(value >> 16);
327 E : EmitByte(value >> 24);
328 E : }
329 :
330 : template <class ReferenceType>
331 : void AssemblerBase<ReferenceType>::InstructionBuffer::Emit32BitImmediate(
332 E : const Immediate& imm) {
333 E : AddReference(imm.reference(), kSize32Bit, false);
334 :
335 E : uint32 value = imm.value();
336 E : EmitByte(value);
337 E : EmitByte(value >> 8);
338 E : EmitByte(value >> 16);
339 E : EmitByte(value >> 24);
340 E : }
341 :
342 : template <class ReferenceType>
343 : void AssemblerBase<ReferenceType>::InstructionBuffer::Emit8BitPCRelative(
344 E : uint32 location, const Immediate& imm) {
345 E : DCHECK_EQ(kSize8Bit, imm.size());
346 :
347 E : AddReference(imm.reference(), kSize8Bit, true);
348 :
349 : // Turn the absolute imm into a imm relative to the address of
350 : // the end of the emitted constant.
351 E : int32 relative_value = imm.value() - (location + len_ + 1);
352 E : DCHECK_LE(std::numeric_limits<int8>::min(), relative_value);
353 E : DCHECK_GE(std::numeric_limits<int8>::max(), relative_value);
354 E : EmitByte(relative_value);
355 E : }
356 :
357 : template <class ReferenceType>
358 : void AssemblerBase<ReferenceType>::InstructionBuffer::Emit32BitPCRelative(
359 E : uint32 location, const Immediate& imm) {
360 E : DCHECK_EQ(kSize32Bit, imm.size());
361 :
362 E : AddReference(imm.reference(), kSize32Bit, true);
363 :
364 : // Turn the absolute imm into a imm relative to the address of
365 : // the end of the emitted constant.
366 E : uint32 relative_value = imm.value() - (location + len_ + 4);
367 E : EmitByte(relative_value);
368 E : EmitByte(relative_value >> 8);
369 E : EmitByte(relative_value >> 16);
370 E : EmitByte(relative_value >> 24);
371 E : }
372 :
373 : template <class ReferenceType>
374 : void AssemblerBase<ReferenceType>::InstructionBuffer::Emit16BitValue(
375 E : uint16 value) {
376 E : EmitByte(value);
377 E : EmitByte(value >> 8);
378 E : }
379 :
380 : template <class ReferenceType>
381 : void AssemblerBase<ReferenceType>::InstructionBuffer::
382 : EmitArithmeticInstruction(
383 E : uint8 op, const Register& dst, const Register& src) {
384 E : DCHECK_EQ(dst.size(), src.size());
385 E : EmitOpCodeByte(op);
386 E : EmitModRMByte(kReg1, dst.id(), src.id());
387 E : }
388 :
389 : template <class ReferenceType>
390 : void AssemblerBase<ReferenceType>::InstructionBuffer::
391 : EmitArithmeticInstruction(
392 E : uint8 op, const Register& dst, const Operand& src) {
393 E : EmitOpCodeByte(op);
394 E : EmitOperand(dst.code(), src);
395 E : }
396 :
397 : template <class ReferenceType>
398 : void AssemblerBase<ReferenceType>::InstructionBuffer::
399 : EmitArithmeticInstruction(
400 E : uint8 op, const Operand& dst, const Register32& src) {
401 E : EmitOpCodeByte(op);
402 E : EmitOperand(src.code(), dst);
403 E : }
404 :
405 : template <class ReferenceType>
406 : void AssemblerBase<ReferenceType>::InstructionBuffer::
407 : EmitArithmeticInstructionToRegister32(
408 : uint8 op_eax, uint8 op_8, uint8 op_32, uint8 sub_op,
409 E : const Register32& dst, const Immediate& src) {
410 E : if (dst.id() == kRegisterEax && src.size() == kSize32Bit) {
411 : // Special encoding for EAX.
412 E : EmitOpCodeByte(op_eax);
413 E : Emit32BitImmediate(src);
414 E : } else if (src.size() == kSize8Bit) {
415 E : EmitOpCodeByte(op_8);
416 E : EmitModRMByte(kReg1, sub_op, dst.id());
417 E : Emit8BitImmediate(src);
418 E : } else {
419 E : EmitOpCodeByte(op_32);
420 E : EmitModRMByte(kReg1, sub_op, dst.id());
421 E : Emit32BitImmediate(src);
422 : }
423 E : }
424 :
425 : template <class ReferenceType>
426 : void AssemblerBase<ReferenceType>::InstructionBuffer::
427 : EmitArithmeticInstructionToRegister8(
428 : uint8 op_eax, uint8 op_8, uint8 sub_op,
429 E : const Register8& dst, const Immediate& src) {
430 E : DCHECK(src.size() == kSize8Bit);
431 E : if (dst.code() == kAccumulatorCode) {
432 : // Special encoding for AL/AX/EAX.
433 E : EmitOpCodeByte(op_eax);
434 E : } else {
435 E : EmitOpCodeByte(op_8);
436 E : EmitModRMByte(kReg1, sub_op, dst.id());
437 : }
438 E : Emit8BitImmediate(src);
439 E : }
440 :
441 : template <class ReferenceType>
442 : void AssemblerBase<ReferenceType>::InstructionBuffer::
443 : EmitArithmeticInstructionToOperand(
444 : uint8 op_8, uint8 op_32, uint8 sub_op,
445 E : const Operand& dst, const Immediate& src) {
446 E : if (src.size() == kSize8Bit) {
447 E : EmitOpCodeByte(op_8);
448 E : EmitOperand(sub_op, dst);
449 E : Emit8BitImmediate(src);
450 E : } else {
451 E : EmitOpCodeByte(op_32);
452 E : EmitOperand(sub_op, dst);
453 E : Emit32BitImmediate(src);
454 : }
455 E : }
456 :
457 : template <class ReferenceType>
458 : void AssemblerBase<ReferenceType>::InstructionBuffer::EmitXchg(
459 E : ValueSize size, RegisterId dst, RegisterId src) {
460 : // Encoding for 8-bit registers.
461 E : if (size == kSize8Bit) {
462 E : EmitOpCodeByte(0x86);
463 E : EmitModRMByte(kReg1, src, dst);
464 E : } else {
465 : // 16-bit encodings are identical to 32-bit encodings, simply with
466 : // a operand size override prefix.
467 E : if (size == kSize16Bit)
468 E : EmitOperandSizePrefix(1);
469 :
470 : // If either register is EAX/AX there's a 1-byte encoding.
471 E : RegisterCode dst_code = Register::Code(dst);
472 E : RegisterCode src_code = Register::Code(src);
473 E : if (src_code == kAccumulatorCode || dst_code == kAccumulatorCode) {
474 E : RegisterCode other_register = dst_code;
475 E : if (dst_code == kAccumulatorCode)
476 E : other_register = src_code;
477 E : EmitOpCodeByte(0x90 | other_register);
478 E : } else {
479 : // Otherwise we use a 2-byte encoding with a ModR/M byte.
480 E : EmitOpCodeByte(0x87);
481 E : EmitModRMByte(kReg1, src, dst);
482 : }
483 : }
484 E : }
485 :
486 : template <class ReferenceType>
487 : void AssemblerBase<ReferenceType>::InstructionBuffer::AddReference(
488 E : const ReferenceType& reference, RegisterSize size, bool pc_relative) {
489 E : if (!details::IsValidReference(reference))
490 E : return;
491 :
492 E : DCHECK_GT(arraysize(reference_infos_), num_reference_infos_);
493 E : ReferenceInfo& info = reference_infos_[num_reference_infos_];
494 E : info.offset = len();
495 E : info.reference = reference;
496 E : info.size = size;
497 E : info.pc_relative = pc_relative;
498 E : ++num_reference_infos_;
499 E : }
500 :
501 : template <class ReferenceType>
502 E : void AssemblerBase<ReferenceType>::InstructionBuffer::EmitByte(uint8 byte) {
503 E : DCHECK_GT(sizeof(buf_), len_);
504 E : buf_[len_++] = byte;
505 E : }
506 :
507 : template <class ReferenceType>
508 : AssemblerBase<ReferenceType>::AssemblerBase(
509 : uint32 location, InstructionSerializer* serializer) :
510 E : location_(location), serializer_(serializer) {
511 E : DCHECK(serializer != NULL);
512 E : }
513 :
514 : template <class ReferenceType>
515 E : void AssemblerBase<ReferenceType>::nop(size_t size) {
516 : // These are NOP sequences suggested by the Intel Architecture
517 : // Software Developer's manual, page 4-8.
518 : //
519 : // 1: 0x90
520 : // 2: 0x66 0x90
521 : // 3: 0x66 0x66 0x90
522 : // 4: 0x0F 0x1F 0x40 0x00
523 : // 5: 0x0F 0x1F 0x44 0x00 0x00
524 : // 6: 0x66 0x0F 0x1F 0x44 0x00 0x00
525 : // 7: 0x0F 0x1F 0x80 0x00 0x00 0x00 0x00
526 : // 8: 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
527 : // 9: 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
528 : // 10: 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
529 : // 11: 0x66 0x66 0x66 0x0F 0x1F 0x84 0x00 0x00 0x00 0x00 0x00
530 : //
531 : // It is further suggested not to put consecutive XCHG NOPs with prefixes,
532 : // but rather to mix them with 0x1F NOPs or XCHG NOPs without prefixes. The
533 : // basic nops without any operand prefixes (0x66) have been implemented as
534 : // helper functions nop1, nop4, nop5, nop7 and nop8. This implementation of
535 : // NOP sequences has been inspired by Oracle's HotSpot JVM JIT assembler
536 : // (http://openjdk.java.net/groups/hotspot/).
537 :
538 : // Eat up the NOPs in chunks of 15 bytes.
539 E : while (size >= 15) {
540 E : nop8(3); // 11-byte non-XCHG NOP.
541 E : nop1(3); // 4-byte prefixed XCHG NOP.
542 E : size -= 15;
543 E : }
544 E : DCHECK_GE(14u, size);
545 :
546 : // Handle the last chunk of bytes.
547 E : size_t prefix_count = 0;
548 E : switch (size) {
549 : // Handle 12- to 14-byte NOPs.
550 : case 14:
551 E : ++prefix_count;
552 : case 13:
553 E : ++prefix_count;
554 : case 12:
555 E : nop8(prefix_count); // 8- to 10-byte non-XCHG NOP.
556 E : nop1(3); // 4-byte prefixed XCHG NOP.
557 E : return;
558 :
559 : // Handle 8- to 11-byte NOPs.
560 : case 11:
561 E : ++prefix_count;
562 : case 10:
563 E : ++prefix_count;
564 : case 9:
565 E : ++prefix_count;
566 : case 8:
567 E : nop8(prefix_count); // 8- to 11-byte non-XCHG NOP.
568 E : return;
569 :
570 : // Handle 7-byte NOPs.
571 : case 7:
572 E : nop7(prefix_count); // 7-byte non-XCHG NOP.
573 E : return;
574 :
575 : // Handle 5- to 6-byte NOPs.
576 : case 6:
577 E : ++prefix_count;
578 : case 5:
579 E : nop5(prefix_count); // 5- to 6-byte non-XCHG NOP.
580 E : return;
581 :
582 : // Handle 4-byte NOPs.
583 : case 4:
584 E : nop4(prefix_count); // 4-byte non-XCHG NOP.
585 E : return;
586 :
587 : // Handle 1- to 3-byte NOPs.
588 : case 3:
589 E : ++prefix_count;
590 : case 2:
591 E : ++prefix_count;
592 : case 1:
593 E : nop1(prefix_count); // 1- to 3-byte XCHG NOP.
594 : return;
595 :
596 : case 0:
597 : // Nothing to do!
598 : break;
599 : }
600 : return;
601 E : }
602 :
603 : template <class ReferenceType>
604 E : void AssemblerBase<ReferenceType>::call(const Immediate& dst) {
605 E : InstructionBuffer instr(this);
606 :
607 E : instr.EmitOpCodeByte(0xE8);
608 E : instr.Emit32BitPCRelative(location_, dst);
609 E : }
610 :
611 : template <class ReferenceType>
612 E : void AssemblerBase<ReferenceType>::call(const Operand& dst) {
613 E : InstructionBuffer instr(this);
614 :
615 E : instr.EmitOpCodeByte(0xFF);
616 E : instr.EmitOperand(0x2, dst);
617 E : }
618 :
619 : template <class ReferenceType>
620 E : void AssemblerBase<ReferenceType>::j(ConditionCode cc, const Immediate& dst) {
621 E : DCHECK_LE(kMinConditionCode, cc);
622 E : DCHECK_GE(kMaxConditionCode, cc);
623 :
624 E : InstructionBuffer instr(this);
625 E : if (dst.size() == kSize32Bit) {
626 E : instr.EmitOpCodeByte(kTwoByteOpCodePrefix);
627 E : instr.EmitOpCodeByte(0x80 | cc);
628 E : instr.Emit32BitPCRelative(location_, dst);
629 E : } else {
630 E : DCHECK_EQ(kSize8Bit, dst.size());
631 E : instr.EmitOpCodeByte(0x70 | cc);
632 E : instr.Emit8BitPCRelative(location_, dst);
633 : }
634 E : }
635 :
636 : template <class ReferenceType>
637 : bool AssemblerBase<ReferenceType>::j(ConditionCode cc,
638 : Label* label,
639 E : RegisterSize size) {
640 E : DCHECK(label != NULL);
641 E : DCHECK_LE(kMinConditionCode, cc);
642 E : DCHECK_GE(kMaxConditionCode, cc);
643 E : DCHECK(size == kSize8Bit || size == kSize32Bit || size == kSizeNone);
644 :
645 E : Immediate dst;
646 E : if (label->bound()) {
647 : // Check whether the short reach is in range.
648 : // TODO(siggi): Utility function for this.
649 E : int32 offs = label->location() - (location() + kShortBranchSize);
650 : if (offs > std::numeric_limits<int8>::max() ||
651 E : offs < std::numeric_limits<int8>::min()) {
652 : // Short is out of range, fail if that's requested.
653 E : if (size == kSize8Bit)
654 E : return false;
655 : // Short is out of range, go long.
656 E : size = kSize32Bit;
657 E : } else {
658 : // Short is in range, pick short if there's a choice.
659 E : if (size == kSizeNone)
660 E : size = kSize8Bit;
661 : }
662 :
663 E : dst = Immediate(label->location(), size);
664 E : } else {
665 E : if (size == kSizeNone)
666 E : size = kSize32Bit;
667 :
668 E : size_t opcode_size = kShortBranchOpcodeSize;
669 E : if (size == kSize32Bit)
670 E : opcode_size = kLongBranchOpcodeSize;
671 :
672 : // The label is not yet bound, declare our use.
673 E : label->Use(location() + opcode_size, size);
674 : // Point the destination to our own instruction as a debugging aid.
675 E : dst = Immediate(location(), size);
676 : }
677 :
678 E : j(cc, dst);
679 :
680 E : return true;
681 E : }
682 :
683 : template <class ReferenceType>
684 E : bool AssemblerBase<ReferenceType>::j(ConditionCode cc, Label* label) {
685 E : return j(cc, label, kSizeNone);
686 E : }
687 :
688 : template <class ReferenceType>
689 E : void AssemblerBase<ReferenceType>::jecxz(const Immediate& dst) {
690 E : DCHECK_EQ(kSize8Bit, dst.size());
691 E : InstructionBuffer instr(this);
692 E : instr.EmitOpCodeByte(0xE3);
693 E : instr.Emit8BitPCRelative(location_, dst);
694 E : }
695 :
696 : template <class ReferenceType>
697 E : void AssemblerBase<ReferenceType>::jmp(const Immediate& dst) {
698 E : InstructionBuffer instr(this);
699 :
700 E : if (dst.size() == kSize32Bit) {
701 E : instr.EmitOpCodeByte(0xE9);
702 E : instr.Emit32BitPCRelative(location_, dst);
703 E : } else {
704 E : DCHECK_EQ(kSize8Bit, dst.size());
705 E : instr.EmitOpCodeByte(0xEB);
706 E : instr.Emit8BitPCRelative(location_, dst);
707 : }
708 E : }
709 :
710 : template <class ReferenceType>
711 E : void AssemblerBase<ReferenceType>::jmp(const Operand& dst) {
712 E : InstructionBuffer instr(this);
713 :
714 E : instr.EmitOpCodeByte(0xFF);
715 E : instr.EmitOperand(0x4, dst);
716 E : }
717 :
718 : template <class ReferenceType>
719 E : void AssemblerBase<ReferenceType>::l(LoopCode lc, const Immediate& dst) {
720 E : DCHECK_EQ(kSize8Bit, dst.size());
721 E : DCHECK_LE(0, lc);
722 E : DCHECK_GE(2, lc);
723 E : InstructionBuffer instr(this);
724 :
725 E : instr.EmitOpCodeByte(0xE0 | lc);
726 E : instr.Emit8BitPCRelative(location_, dst);
727 E : }
728 :
729 : template <class ReferenceType>
730 E : void AssemblerBase<ReferenceType>::ret() {
731 E : InstructionBuffer instr(this);
732 :
733 E : instr.EmitOpCodeByte(0xC3);
734 E : }
735 :
736 : template <class ReferenceType>
737 E : void AssemblerBase<ReferenceType>::ret(uint16 n) {
738 E : InstructionBuffer instr(this);
739 :
740 E : instr.EmitOpCodeByte(0xC2);
741 E : instr.Emit16BitValue(n);
742 E : }
743 :
744 : template <class ReferenceType>
745 : void AssemblerBase<ReferenceType>::set(ConditionCode cc,
746 E : const Register32& dst) {
747 E : DCHECK_LE(kMinConditionCode, cc);
748 E : DCHECK_GE(kMaxConditionCode, cc);
749 :
750 E : InstructionBuffer instr(this);
751 E : instr.EmitOpCodeByte(kTwoByteOpCodePrefix);
752 E : instr.EmitOpCodeByte(0x90 | cc);
753 :
754 : // AMD64 Architecture Programmers Manual Volume 3: General-Purpose and System
755 : // Instructions: The reg field in the ModR/M byte is unused.
756 E : const Register32& unused = eax;
757 E : instr.EmitModRMByte(kReg1, unused.id(), dst.id());
758 E : }
759 :
760 : template <class ReferenceType>
761 : void AssemblerBase<ReferenceType>::mov_b(const Operand& dst,
762 E : const Immediate& src) {
763 E : InstructionBuffer instr(this);
764 :
765 E : instr.EmitOpCodeByte(0xC6);
766 E : instr.EmitOperand(0, dst);
767 E : instr.Emit8BitImmediate(src);
768 E : }
769 :
770 : template <class ReferenceType>
771 : void AssemblerBase<ReferenceType>::movzx_b(const Register32& dst,
772 E : const Operand& src) {
773 E : InstructionBuffer instr(this);
774 E : instr.EmitOpCodeByte(kTwoByteOpCodePrefix);
775 E : instr.EmitOpCodeByte(0xB6);
776 E : instr.EmitOperand(dst.code(), src);
777 E : }
778 :
779 : template <class ReferenceType>
780 : void AssemblerBase<ReferenceType>::mov(const Register32& dst,
781 E : const Register32& src) {
782 E : InstructionBuffer instr(this);
783 :
784 E : instr.EmitOpCodeByte(0x8B);
785 E : instr.EmitModRMByte(kReg1, dst.id(), src.id());
786 E : }
787 :
788 : template <class ReferenceType>
789 : void AssemblerBase<ReferenceType>::mov(const Register32& dst,
790 E : const Operand& src) {
791 E : InstructionBuffer instr(this);
792 :
793 E : if (dst.id() == kRegisterEax && IsDisplacementOnly(src)) {
794 : // Special encoding for indirect displacement only to EAX.
795 E : instr.EmitOpCodeByte(0xA1);
796 E : instr.Emit32BitDisplacement(src.displacement());
797 E : } else {
798 E : instr.EmitOpCodeByte(0x8B);
799 E : instr.EmitOperand(dst.code(), src);
800 : }
801 E : }
802 :
803 : template <class ReferenceType>
804 : void AssemblerBase<ReferenceType>::mov(const Operand& dst,
805 E : const Register32& src) {
806 E : InstructionBuffer instr(this);
807 :
808 E : if (src.id() == kRegisterEax && IsDisplacementOnly(dst)) {
809 : // Special encoding for indirect displacement only from EAX.
810 E : instr.EmitOpCodeByte(0xA3);
811 E : instr.Emit32BitDisplacement(dst.displacement());
812 E : } else {
813 E : instr.EmitOpCodeByte(0x89);
814 E : instr.EmitOperand(src.code(), dst);
815 : }
816 E : }
817 :
818 : template <class ReferenceType>
819 : void AssemblerBase<ReferenceType>::mov(const Register32& dst,
820 E : const Immediate& src) {
821 E : DCHECK_NE(kSizeNone, src.size());
822 E : InstructionBuffer instr(this);
823 :
824 E : instr.EmitOpCodeByte(0xB8 | dst.code());
825 E : instr.Emit32BitImmediate(src);
826 E : }
827 :
828 : template <class ReferenceType>
829 : void AssemblerBase<ReferenceType>::mov(const Operand& dst,
830 E : const Immediate& src) {
831 E : InstructionBuffer instr(this);
832 :
833 E : instr.EmitOpCodeByte(0xC7);
834 E : instr.EmitOperand(0, dst);
835 E : instr.Emit32BitImmediate(src);
836 E : }
837 :
838 : template <class ReferenceType>
839 : void AssemblerBase<ReferenceType>::mov_fs(const Register32& dst,
840 E : const Operand& src) {
841 E : InstructionBuffer instr(this);
842 E : instr.EmitOpCodeByte(kFsSegmentPrefix);
843 :
844 E : if (dst.id() == kRegisterEax && IsDisplacementOnly(src)) {
845 : // Special encoding for indirect displacement only to EAX.
846 i : instr.EmitOpCodeByte(0xA1);
847 i : instr.Emit32BitDisplacement(src.displacement());
848 i : } else {
849 E : instr.EmitOpCodeByte(0x8B);
850 E : instr.EmitOperand(dst.code(), src);
851 : }
852 E : }
853 :
854 : template <class ReferenceType>
855 : void AssemblerBase<ReferenceType>::mov_fs(const Operand& dst,
856 E : const Register32& src) {
857 E : InstructionBuffer instr(this);
858 E : instr.EmitOpCodeByte(kFsSegmentPrefix);
859 :
860 E : if (src.id() == kRegisterEax && IsDisplacementOnly(dst)) {
861 : // Special encoding for indirect displacement only from EAX.
862 i : instr.EmitOpCodeByte(0xA3);
863 i : instr.Emit32BitDisplacement(dst.displacement());
864 i : } else {
865 E : instr.EmitOpCodeByte(0x89);
866 E : instr.EmitOperand(src.code(), dst);
867 : }
868 E : }
869 :
870 : template <class ReferenceType>
871 : void AssemblerBase<ReferenceType>::lea(const Register32& dst,
872 E : const Operand& src) {
873 E : InstructionBuffer instr(this);
874 :
875 E : instr.EmitOpCodeByte(0x8D);
876 E : instr.EmitOperand(dst.code(), src);
877 E : }
878 :
879 : template <class ReferenceType>
880 E : void AssemblerBase<ReferenceType>::push(const Register32& src) {
881 E : InstructionBuffer instr(this);
882 :
883 E : instr.EmitOpCodeByte(0x50 | src.code());
884 E : }
885 :
886 : template <class ReferenceType>
887 E : void AssemblerBase<ReferenceType>::push(const Immediate& src) {
888 E : DCHECK_EQ(kSize32Bit, src.size());
889 E : InstructionBuffer instr(this);
890 :
891 E : instr.EmitOpCodeByte(0x68);
892 E : instr.Emit32BitImmediate(src);
893 E : }
894 :
895 : template <class ReferenceType>
896 E : void AssemblerBase<ReferenceType>::push(const Operand& dst) {
897 E : InstructionBuffer instr(this);
898 :
899 E : instr.EmitOpCodeByte(0xFF);
900 E : instr.EmitOperand(0x6, dst);
901 E : }
902 :
903 : template <class ReferenceType>
904 E : void AssemblerBase<ReferenceType>::pushad() {
905 E : InstructionBuffer instr(this);
906 :
907 E : instr.EmitOpCodeByte(0x60);
908 E : }
909 :
910 : template <class ReferenceType>
911 E : void AssemblerBase<ReferenceType>::pop(const Register32& src) {
912 E : InstructionBuffer instr(this);
913 :
914 E : instr.EmitOpCodeByte(0x58 | src.code());
915 E : }
916 :
917 : template <class ReferenceType>
918 E : void AssemblerBase<ReferenceType>::pop(const Operand& dst) {
919 E : InstructionBuffer instr(this);
920 :
921 E : instr.EmitOpCodeByte(0x8F);
922 E : instr.EmitOperand(0, dst);
923 E : }
924 :
925 : template <class ReferenceType>
926 E : void AssemblerBase<ReferenceType>::popad() {
927 E : InstructionBuffer instr(this);
928 :
929 E : instr.EmitOpCodeByte(0x61);
930 E : }
931 :
932 : template <class ReferenceType>
933 E : void AssemblerBase<ReferenceType>::pushfd() {
934 E : InstructionBuffer instr(this);
935 E : instr.EmitOpCodeByte(0x9C);
936 E : }
937 :
938 : template <class ReferenceType>
939 E : void AssemblerBase<ReferenceType>::popfd() {
940 E : InstructionBuffer instr(this);
941 E : instr.EmitOpCodeByte(0x9D);
942 E : }
943 :
944 : template <class ReferenceType>
945 E : void AssemblerBase<ReferenceType>::lahf() {
946 E : InstructionBuffer instr(this);
947 E : instr.EmitOpCodeByte(0x9F);
948 E : }
949 :
950 : template <class ReferenceType>
951 E : void AssemblerBase<ReferenceType>::sahf() {
952 E : InstructionBuffer instr(this);
953 E : instr.EmitOpCodeByte(0x9E);
954 E : }
955 :
956 : template <class ReferenceType>
957 : void AssemblerBase<ReferenceType>::test(const Register8& dst,
958 E : const Register8& src) {
959 E : InstructionBuffer instr(this);
960 E : instr.EmitArithmeticInstruction(0x84, dst, src);
961 E : }
962 :
963 : template <class ReferenceType>
964 : void AssemblerBase<ReferenceType>::test(const Register8& dst,
965 E : const Immediate& src) {
966 E : InstructionBuffer instr(this);
967 E : instr.EmitArithmeticInstructionToRegister8(0xA8, 0xF6, 0, dst, src);
968 E : }
969 :
970 : template <class ReferenceType>
971 : void AssemblerBase<ReferenceType>::test(const Register32& dst,
972 E : const Register32& src) {
973 E : InstructionBuffer instr(this);
974 E : instr.EmitArithmeticInstruction(0x85, dst, src);
975 E : }
976 :
977 : template <class ReferenceType>
978 : void AssemblerBase<ReferenceType>::test(const Register32& dst,
979 E : const Operand& src) {
980 : // Use commutative property for a smaller encoding.
981 E : test(src, dst);
982 E : }
983 :
984 : template <class ReferenceType>
985 : void AssemblerBase<ReferenceType>::test(const Operand& dst,
986 E : const Register32& src) {
987 E : InstructionBuffer instr(this);
988 E : instr.EmitArithmeticInstruction(0x85, dst, src);
989 E : }
990 :
991 : template <class ReferenceType>
992 : void AssemblerBase<ReferenceType>::test(const Register32& dst,
993 E : const Immediate& src) {
994 E : if (src.size() == kSize8Bit) {
995 : // note: There is no encoding for a 8-bit immediate with 32-bit register.
996 E : test(dst, Immediate(src.value(), kSize32Bit));
997 E : } else {
998 E : InstructionBuffer instr(this);
999 E : instr.EmitArithmeticInstructionToRegister32(0xA9, 0xF7, 0xF7, 0, dst, src);
1000 E : }
1001 E : }
1002 :
1003 : template <class ReferenceType>
1004 : void AssemblerBase<ReferenceType>::test(const Operand& dst,
1005 E : const Immediate& src) {
1006 E : if (src.size() == kSize8Bit) {
1007 : // note: There is no encoding for a 8-bit immediate with 32-bit register.
1008 E : test(dst, Immediate(src.value(), kSize32Bit));
1009 E : } else {
1010 E : InstructionBuffer instr(this);
1011 E : instr.EmitArithmeticInstructionToOperand(0xF7, 0xF7, 0, dst, src);
1012 E : }
1013 E : }
1014 :
1015 : template <class ReferenceType>
1016 : void AssemblerBase<ReferenceType>::cmp(const Register8& dst,
1017 E : const Register8& src) {
1018 E : InstructionBuffer instr(this);
1019 E : instr.EmitArithmeticInstruction(0x3A, dst, src);
1020 E : }
1021 :
1022 : template <class ReferenceType>
1023 : void AssemblerBase<ReferenceType>::cmp(const Register8& dst,
1024 E : const Immediate& src) {
1025 E : InstructionBuffer instr(this);
1026 E : instr.EmitArithmeticInstructionToRegister8(0x3C, 0x80, 7, dst, src);
1027 E : }
1028 :
1029 : template <class ReferenceType>
1030 : void AssemblerBase<ReferenceType>::cmp(const Register32& dst,
1031 E : const Register32& src) {
1032 E : InstructionBuffer instr(this);
1033 E : instr.EmitArithmeticInstruction(0x3B, dst, src);
1034 E : }
1035 :
1036 : template <class ReferenceType>
1037 : void AssemblerBase<ReferenceType>::cmp(const Register32& dst,
1038 E : const Operand& src) {
1039 E : InstructionBuffer instr(this);
1040 E : instr.EmitArithmeticInstruction(0x3B, dst, src);
1041 E : }
1042 :
1043 : template <class ReferenceType>
1044 : void AssemblerBase<ReferenceType>::cmp(const Operand& dst,
1045 E : const Register32& src) {
1046 E : InstructionBuffer instr(this);
1047 E : instr.EmitArithmeticInstruction(0x39, dst, src);
1048 E : }
1049 :
1050 : template <class ReferenceType>
1051 : void AssemblerBase<ReferenceType>::cmp(const Register32& dst,
1052 E : const Immediate& src) {
1053 E : InstructionBuffer instr(this);
1054 E : instr.EmitArithmeticInstructionToRegister32(0x3D, 0x83, 0x81, 7, dst, src);
1055 E : }
1056 :
1057 : template <class ReferenceType>
1058 : void AssemblerBase<ReferenceType>::cmp(const Operand& dst,
1059 E : const Immediate& src) {
1060 E : InstructionBuffer instr(this);
1061 E : instr.EmitArithmeticInstructionToOperand(0x83, 0x81, 7, dst, src);
1062 E : }
1063 :
1064 : template <class ReferenceType>
1065 : void AssemblerBase<ReferenceType>::add(const Register8& dst,
1066 E : const Register8& src) {
1067 E : InstructionBuffer instr(this);
1068 E : instr.EmitArithmeticInstruction(0x02, dst, src);
1069 E : }
1070 :
1071 : template <class ReferenceType>
1072 : void AssemblerBase<ReferenceType>::add(const Register8& dst,
1073 E : const Immediate& src) {
1074 E : InstructionBuffer instr(this);
1075 E : instr.EmitArithmeticInstructionToRegister8(0x04, 0x80, 0, dst, src);
1076 E : }
1077 :
1078 : template <class ReferenceType>
1079 : void AssemblerBase<ReferenceType>::add(const Register32& dst,
1080 E : const Register32& src) {
1081 E : InstructionBuffer instr(this);
1082 E : instr.EmitArithmeticInstruction(0x03, dst, src);
1083 E : }
1084 :
1085 : template <class ReferenceType>
1086 : void AssemblerBase<ReferenceType>::add(const Register32& dst,
1087 E : const Operand& src) {
1088 E : InstructionBuffer instr(this);
1089 E : instr.EmitArithmeticInstruction(0x03, dst, src);
1090 E : }
1091 :
1092 : template <class ReferenceType>
1093 : void AssemblerBase<ReferenceType>::add(const Operand& dst,
1094 E : const Register32& src) {
1095 E : InstructionBuffer instr(this);
1096 E : instr.EmitArithmeticInstruction(0x01, dst, src);
1097 E : }
1098 :
1099 : template <class ReferenceType>
1100 : void AssemblerBase<ReferenceType>::add(const Register32& dst,
1101 E : const Immediate& src) {
1102 E : InstructionBuffer instr(this);
1103 E : instr.EmitArithmeticInstructionToRegister32(0x05, 0x83, 0x81, 0, dst, src);
1104 E : }
1105 :
1106 : template <class ReferenceType>
1107 : void AssemblerBase<ReferenceType>::add(const Operand& dst,
1108 E : const Immediate& src) {
1109 E : InstructionBuffer instr(this);
1110 E : instr.EmitArithmeticInstructionToOperand(0x83, 0x81, 0, dst, src);
1111 E : }
1112 :
1113 : template <class ReferenceType>
1114 : void AssemblerBase<ReferenceType>::sub(const Register8& dst,
1115 E : const Register8& src) {
1116 E : InstructionBuffer instr(this);
1117 E : instr.EmitArithmeticInstruction(0x2A, dst, src);
1118 E : }
1119 :
1120 : template <class ReferenceType>
1121 : void AssemblerBase<ReferenceType>::sub(const Register8& dst,
1122 E : const Immediate& src) {
1123 E : InstructionBuffer instr(this);
1124 E : instr.EmitArithmeticInstructionToRegister8(0x2C, 0x80, 5, dst, src);
1125 E : }
1126 :
1127 : template <class ReferenceType>
1128 : void AssemblerBase<ReferenceType>::sub(const Register32& dst,
1129 E : const Register32& src) {
1130 E : InstructionBuffer instr(this);
1131 E : instr.EmitArithmeticInstruction(0x2B, dst, src);
1132 E : }
1133 :
1134 : template <class ReferenceType>
1135 : void AssemblerBase<ReferenceType>::sub(const Register32& dst,
1136 E : const Operand& src) {
1137 E : InstructionBuffer instr(this);
1138 E : instr.EmitArithmeticInstruction(0x2B, dst, src);
1139 E : }
1140 :
1141 : template <class ReferenceType>
1142 : void AssemblerBase<ReferenceType>::sub(const Operand& dst,
1143 E : const Register32& src) {
1144 E : InstructionBuffer instr(this);
1145 E : instr.EmitArithmeticInstruction(0x29, dst, src);
1146 E : }
1147 :
1148 : template <class ReferenceType>
1149 : void AssemblerBase<ReferenceType>::sub(const Register32& dst,
1150 E : const Immediate& src) {
1151 E : InstructionBuffer instr(this);
1152 E : instr.EmitArithmeticInstructionToRegister32(0x2D, 0x83, 0x81, 5, dst, src);
1153 E : }
1154 :
1155 : template <class ReferenceType>
1156 : void AssemblerBase<ReferenceType>::sub(const Operand& dst,
1157 E : const Immediate& src) {
1158 E : InstructionBuffer instr(this);
1159 E : instr.EmitArithmeticInstructionToOperand(0x83, 0x81, 5, dst, src);
1160 E : }
1161 :
1162 : template <class ReferenceType>
1163 : void AssemblerBase<ReferenceType>::shl(const Register32& dst,
1164 E : const Immediate& src) {
1165 E : InstructionBuffer instr(this);
1166 E : if (src.value() == 1) {
1167 E : instr.EmitOpCodeByte(0xD1);
1168 E : instr.EmitModRMByte(kReg1, 4, dst.id());
1169 E : } else {
1170 E : instr.EmitOpCodeByte(0xC1);
1171 E : instr.EmitModRMByte(kReg1, 4, dst.id());
1172 E : instr.Emit8BitImmediate(src);
1173 : }
1174 E : }
1175 :
1176 : template <class ReferenceType>
1177 : void AssemblerBase<ReferenceType>::shr(const Register32& dst,
1178 E : const Immediate& src) {
1179 E : InstructionBuffer instr(this);
1180 E : if (src.value() == 1) {
1181 E : instr.EmitOpCodeByte(0xD1);
1182 E : instr.EmitModRMByte(kReg1, 5, dst.id());
1183 E : } else {
1184 E : instr.EmitOpCodeByte(0xC1);
1185 E : instr.EmitModRMByte(kReg1, 5, dst.id());
1186 E : instr.Emit8BitImmediate(src);
1187 : }
1188 E : }
1189 :
1190 : template <class ReferenceType>
1191 : void AssemblerBase<ReferenceType>::xchg(const Register32& dst,
1192 E : const Register32& src) {
1193 E : InstructionBuffer instr(this);
1194 E : instr.EmitXchg(kSize32Bit, dst.id(), src.id());
1195 E : }
1196 :
1197 : template <class ReferenceType>
1198 : void AssemblerBase<ReferenceType>::xchg(const Register16& dst,
1199 E : const Register16& src) {
1200 E : InstructionBuffer instr(this);
1201 E : instr.EmitXchg(kSize16Bit, dst.id(), src.id());
1202 E : }
1203 :
1204 : template <class ReferenceType>
1205 : void AssemblerBase<ReferenceType>::xchg(const Register8& dst,
1206 E : const Register8& src) {
1207 E : InstructionBuffer instr(this);
1208 E : instr.EmitXchg(kSize8Bit, dst.id(), src.id());
1209 E : }
1210 :
1211 : template <class ReferenceType>
1212 : void AssemblerBase<ReferenceType>::xchg(const Register32& dst,
1213 E : const Operand& src) {
1214 E : InstructionBuffer instr(this);
1215 E : instr.EmitOpCodeByte(0x87);
1216 E : instr.EmitOperand(dst.code(), src);
1217 E : }
1218 :
1219 : template <class ReferenceType>
1220 E : void AssemblerBase<ReferenceType>::nop1(size_t prefix_count) {
1221 E : InstructionBuffer instr(this);
1222 E : instr.EmitOperandSizePrefix(prefix_count);
1223 E : instr.EmitXchg(kSize32Bit, kRegisterEax, kRegisterEax);
1224 E : }
1225 :
1226 : template <class ReferenceType>
1227 E : void AssemblerBase<ReferenceType>::nop4(size_t prefix_count) {
1228 E : InstructionBuffer instr(this);
1229 E : instr.EmitOperandSizePrefix(prefix_count);
1230 : // 4 bytes: NOP DWORD PTR [EAX + 0] 8-bit offset
1231 E : instr.EmitOpCodeByte(kTwoByteOpCodePrefix);
1232 E : instr.EmitOpCodeByte(kNopOpCode);
1233 E : instr.EmitModRMByte(kReg1ByteDisp, 0, kRegisterEax);
1234 E : instr.Emit8BitDisplacement(Displacement(0, kSize8Bit));
1235 E : }
1236 :
1237 : template <class ReferenceType>
1238 E : void AssemblerBase<ReferenceType>::nop5(size_t prefix_count) {
1239 E : InstructionBuffer instr(this);
1240 E : instr.EmitOperandSizePrefix(prefix_count);
1241 : // 5 bytes: NOP DWORD PTR [EAX + EAX * 1 + 0] 8-bit offset
1242 E : instr.EmitOpCodeByte(kTwoByteOpCodePrefix);
1243 E : instr.EmitOpCodeByte(kNopOpCode);
1244 : // esp in the ModR/M byte indicates SIB to follow.
1245 E : instr.EmitModRMByte(kReg1ByteDisp, 0, kRegisterEsp);
1246 E : instr.EmitScaleIndexBaseByte(kTimes1, kRegisterEax, kRegisterEax);
1247 E : instr.Emit8BitDisplacement(Displacement(0, kSize8Bit));
1248 E : }
1249 :
1250 : template <class ReferenceType>
1251 E : void AssemblerBase<ReferenceType>::nop7(size_t prefix_count) {
1252 E : InstructionBuffer instr(this);
1253 E : instr.EmitOperandSizePrefix(prefix_count);
1254 : // 7 bytes: NOP DWORD PTR [EAX + 0] 32-bit offset
1255 E : instr.EmitOpCodeByte(kTwoByteOpCodePrefix);
1256 E : instr.EmitOpCodeByte(kNopOpCode);
1257 E : instr.EmitModRMByte(kReg1WordDisp, 0, kRegisterEax);
1258 E : instr.Emit32BitDisplacement(Displacement(0, kSize32Bit));
1259 E : }
1260 :
1261 : template <class ReferenceType>
1262 E : void AssemblerBase<ReferenceType>::nop8(size_t prefix_count) {
1263 E : InstructionBuffer instr(this);
1264 E : instr.EmitOperandSizePrefix(prefix_count);
1265 : // 8 bytes: NOP DWORD PTR [EAX + EAX * 1 + 0] 32-bit offset
1266 E : instr.EmitOpCodeByte(kTwoByteOpCodePrefix);
1267 E : instr.EmitOpCodeByte(kNopOpCode);
1268 : // esp in the ModR/M byte indicates SIB to follow.
1269 E : instr.EmitModRMByte(kReg1WordDisp, 0, kRegisterEsp);
1270 E : instr.EmitScaleIndexBaseByte(kTimes1, kRegisterEax, kRegisterEax);
1271 E : instr.Emit32BitDisplacement(Displacement(0, kSize32Bit));
1272 E : }
1273 :
1274 : template <class ReferenceType>
1275 E : void AssemblerBase<ReferenceType>::Output(const InstructionBuffer& instr) {
1276 : serializer_->AppendInstruction(location_,
1277 : instr.buf(),
1278 : instr.len(),
1279 : instr.reference_infos(),
1280 E : instr.num_reference_infos());
1281 :
1282 E : location_ += instr.len();
1283 E : }
1284 :
1285 : template <class ReferenceType>
1286 : bool AssemblerBase<ReferenceType>::FinalizeLabel(
1287 E : uint32 location, uint32 destination, RegisterSize size) {
1288 E : if (size == kSize8Bit) {
1289 : // Compute the relative value, note that this is computed relative to
1290 : // the end of the PC-relative constant, e.g. from the start of the next
1291 : // instruction.
1292 E : int32 relative_value = destination - (location + 1);
1293 : if (relative_value < std::numeric_limits<int8>::min() ||
1294 E : relative_value > std::numeric_limits<int8>::max()) {
1295 : // Out of bounds...
1296 E : return false;
1297 : }
1298 E : uint8 byte = relative_value & 0xFF;
1299 E : return serializer_->FinalizeLabel(location, &byte, sizeof(byte));
1300 i : } else {
1301 E : DCHECK_EQ(kSize32Bit, size);
1302 E : int32 relative_value = destination - (location + 4);
1303 :
1304 : return serializer_->FinalizeLabel(
1305 : location,
1306 : reinterpret_cast<const uint8*>(&relative_value),
1307 E : sizeof(relative_value));
1308 : }
1309 E : }
1310 :
1311 : } // namespace assm
1312 :
1313 : #endif // SYZYGY_ASSM_ASSEMBLER_BASE_IMPL_H_
|