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