1 // [AsmJit]
2 // Complete JIT Assembler for C++ Language.
3 //
4 // [License]
5 // Zlib - See COPYING file in this package.
6
7 #define ASMJIT_EXPORTS
8
9 // [Dependencies - AsmJit]
10 #include "../core/assembler.h"
11 #include "../core/context.h"
12 #include "../core/cpuinfo.h"
13 #include "../core/defs.h"
14 #include "../core/intutil.h"
15 #include "../core/logger.h"
16 #include "../core/memorymanager.h"
17 #include "../core/memorymarker.h"
18 #include "../core/stringutil.h"
19
20 #include "../x86/x86assembler.h"
21 #include "../x86/x86cpuinfo.h"
22 #include "../x86/x86defs.h"
23 #include "../x86/x86operand.h"
24 #include "../x86/x86util.h"
25
26 // [Api-Begin]
27 #include "../core/apibegin.h"
28
29 namespace AsmJit {
30
31 // ============================================================================
32 // [Constants]
33 // ============================================================================
34
35 enum { kMaxCommentLength = 80 };
36
37 // ============================================================================
38 // [AsmJit::X64TrampolineWriter]
39 // ============================================================================
40
41 #if defined(ASMJIT_X64)
42 //! @brief Class used to determine size of trampoline and as trampoline writer.
43 struct X64TrampolineWriter
44 {
45 // Size of trampoline
46 enum
47 {
48 kSizeJmp = 6,
49 kSizeAddr = 8,
50 kSizeTotal = kSizeJmp + kSizeAddr
51 };
52
53 // Write trampoline into code at address @a code that will jump to @a target.
writeTrampolineAsmJit::X64TrampolineWriter54 static void writeTrampoline(uint8_t* code, uint64_t target)
55 {
56 code[0] = 0xFF; // Jmp OpCode.
57 code[1] = 0x25; // ModM (RIP addressing).
58 ((uint32_t*)(code + 2))[0] = 0; // Offset (zero).
59 ((uint64_t*)(code + kSizeJmp))[0] = (uint64_t)target; // Absolute address.
60 }
61 };
62 #endif // ASMJIT_X64
63
64 // ============================================================================
65 // [AsmJit::X86Assembler - Construction / Destruction]
66 // ============================================================================
67
X86Assembler(Context * context)68 X86Assembler::X86Assembler(Context* context) :
69 Assembler(context)
70 {
71 _properties = IntUtil::maskFromIndex(kX86PropertyOptimizedAlign);
72 }
73
~X86Assembler()74 X86Assembler::~X86Assembler()
75 {
76 }
77
78 // ============================================================================
79 // [AsmJit::X86Assembler - Buffer - Setters (X86-Extensions)]
80 // ============================================================================
81
setVarAt(size_t pos,sysint_t i,uint8_t isUnsigned,uint32_t size)82 void X86Assembler::setVarAt(size_t pos, sysint_t i, uint8_t isUnsigned, uint32_t size)
83 {
84 if (size == 1 && !isUnsigned) setByteAt (pos, (int8_t )i);
85 else if (size == 1 && isUnsigned) setByteAt (pos, (uint8_t )i);
86 else if (size == 2 && !isUnsigned) setWordAt (pos, (int16_t )i);
87 else if (size == 2 && isUnsigned) setWordAt (pos, (uint16_t)i);
88 else if (size == 4 && !isUnsigned) setDWordAt(pos, (int32_t )i);
89 else if (size == 4 && isUnsigned) setDWordAt(pos, (uint32_t)i);
90
91 #if defined(ASMJIT_X64)
92 else if (size == 8 && !isUnsigned) setQWordAt(pos, (int64_t )i);
93 else if (size == 8 && isUnsigned) setQWordAt(pos, (uint64_t)i);
94 #endif // ASMJIT_X64
95
96 else
97 ASMJIT_ASSERT(0);
98 }
99
100 // ============================================================================
101 // [AsmJit::X86Assembler - Emit]
102 // ============================================================================
103
_emitModM(uint8_t opReg,const Mem & mem,sysint_t immSize)104 void X86Assembler::_emitModM(
105 uint8_t opReg, const Mem& mem, sysint_t immSize)
106 {
107 ASMJIT_ASSERT(mem.getType() == kOperandMem);
108
109 uint8_t baseReg = mem.getBase() & 0x7;
110 uint8_t indexReg = mem.getIndex() & 0x7;
111 sysint_t disp = mem.getDisplacement();
112 uint32_t shift = mem.getShift();
113
114 if (mem.getMemType() == kOperandMemNative)
115 {
116 // [base + displacemnt]
117 if (!mem.hasIndex())
118 {
119 // ESP/RSP/R12 == 4
120 if (baseReg == 4)
121 {
122 uint8_t mod = 0;
123
124 if (disp)
125 mod = IntUtil::isInt8(disp) ? 1 : 2;
126
127 _emitMod(mod, opReg, 4);
128 _emitSib(0, 4, 4);
129
130 if (disp)
131 {
132 if (IntUtil::isInt8(disp))
133 _emitByte((int8_t)disp);
134 else
135 _emitInt32((int32_t)disp);
136 }
137 }
138 // EBP/RBP/R13 == 5
139 else if (baseReg != 5 && disp == 0)
140 {
141 _emitMod(0, opReg, baseReg);
142 }
143 else if (IntUtil::isInt8(disp))
144 {
145 _emitMod(1, opReg, baseReg);
146 _emitByte((int8_t)disp);
147 }
148 else
149 {
150 _emitMod(2, opReg, baseReg);
151 _emitInt32((int32_t)disp);
152 }
153 }
154
155 // [base + index * scale + displacemnt]
156 else
157 {
158 // ASMJIT_ASSERT(indexReg != RID_ESP);
159
160 // EBP/RBP/R13 == 5
161 if (baseReg != 5 && disp == 0)
162 {
163 _emitMod(0, opReg, 4);
164 _emitSib(shift, indexReg, baseReg);
165 }
166 else if (IntUtil::isInt8(disp))
167 {
168 _emitMod(1, opReg, 4);
169 _emitSib(shift, indexReg, baseReg);
170 _emitByte((int8_t)disp);
171 }
172 else
173 {
174 _emitMod(2, opReg, 4);
175 _emitSib(shift, indexReg, baseReg);
176 _emitInt32((int32_t)disp);
177 }
178 }
179 }
180
181 // Address | 32-bit mode | 64-bit mode
182 // ------------------------------+-------------+---------------
183 // [displacement] | ABSOLUTE | RELATIVE (RIP)
184 // [index * scale + displacemnt] | ABSOLUTE | ABSOLUTE (ZERO EXTENDED)
185 else
186 {
187 // - In 32-bit mode the absolute addressing model is used.
188 // - In 64-bit mode the relative addressing model is used together with
189 // the absolute addressing. Main problem is that if instruction
190 // contains SIB then relative addressing (RIP) is not possible.
191
192 #if defined(ASMJIT_X86)
193
194 if (mem.hasIndex())
195 {
196 // ASMJIT_ASSERT(mem.getMemIndex() != 4); // ESP/RSP == 4
197 _emitMod(0, opReg, 4);
198 _emitSib(shift, indexReg, 5);
199 }
200 else
201 {
202 _emitMod(0, opReg, 5);
203 }
204
205 // X86 uses absolute addressing model, all relative addresses will be
206 // relocated to absolute ones.
207 if (mem.getMemType() == kOperandMemLabel)
208 {
209 LabelData& l_data = _labels[mem._mem.base & kOperandIdValueMask];
210 RelocData r_data;
211 uint32_t relocId = _relocData.getLength();
212
213 // Relative addressing will be relocated to absolute address.
214 r_data.type = kRelocRelToAbs;
215 r_data.size = 4;
216 r_data.offset = getOffset();
217 r_data.destination = disp;
218
219 if (l_data.offset != -1)
220 {
221 // Bound label.
222 r_data.destination += l_data.offset;
223
224 // Add a dummy DWORD.
225 _emitInt32(0);
226 }
227 else
228 {
229 // Non-bound label.
230 _emitDisplacement(l_data, -4 - immSize, 4)->relocId = relocId;
231 }
232
233 _relocData.append(r_data);
234 }
235 else
236 {
237 // Absolute address
238 _emitInt32( (int32_t)((uint8_t*)mem._mem.target + disp) );
239 }
240
241 #else
242
243 // X64 uses relative addressing model
244 if (mem.getMemType() == kOperandMemLabel)
245 {
246 LabelData& l_data = _labels[mem._mem.base & kOperandIdValueMask];
247
248 if (mem.hasIndex())
249 {
250 // Indexing is not possible.
251 setError(kErrorIllegalAddressing);
252 return;
253 }
254
255 // Relative address (RIP +/- displacement).
256 _emitMod(0, opReg, 5);
257
258 disp -= (4 + immSize);
259
260 if (l_data.offset != -1)
261 {
262 // Bound label.
263 disp += getOffset() - l_data.offset;
264
265 // Displacement is known.
266 _emitInt32((int32_t)disp);
267 }
268 else
269 {
270 // Non-bound label.
271 _emitDisplacement(l_data, disp, 4);
272 }
273 }
274 else
275 {
276 // Absolute address (truncated to 32-bits), this kind of address requires
277 // SIB byte (4).
278 _emitMod(0, opReg, 4);
279
280 if (mem.hasIndex())
281 {
282 // ASMJIT_ASSERT(mem.getMemIndex() != 4); // ESP/RSP == 4
283 _emitSib(shift, indexReg, 5);
284 }
285 else
286 {
287 _emitSib(0, 4, 5);
288 }
289
290 // Truncate to 32-bits.
291 sysuint_t target = (sysuint_t)((uint8_t*)mem._mem.target + disp);
292
293 if (target > (sysuint_t)0xFFFFFFFF)
294 {
295 if (_logger)
296 {
297 _logger->logString("*** ASSEMBER WARNING - Absolute address truncated to 32-bits.\n");
298 }
299 target &= 0xFFFFFFFF;
300 }
301
302 _emitInt32( (int32_t)((uint32_t)target) );
303 }
304
305 #endif // ASMJIT_X64
306
307 }
308 }
309
_emitModRM(uint8_t opReg,const Operand & op,sysint_t immSize)310 void X86Assembler::_emitModRM(
311 uint8_t opReg, const Operand& op, sysint_t immSize)
312 {
313 ASMJIT_ASSERT(op.getType() == kOperandReg || op.getType() == kOperandMem);
314
315 if (op.getType() == kOperandReg)
316 _emitModR(opReg, reinterpret_cast<const Reg&>(op).getRegCode());
317 else
318 _emitModM(opReg, reinterpret_cast<const Mem&>(op), immSize);
319 }
320
_emitSegmentPrefix(const Operand & rm)321 void X86Assembler::_emitSegmentPrefix(const Operand& rm)
322 {
323 static const uint8_t segmentCode[6] =
324 {
325 0x26, // ES
326 0x2E, // SS
327 0x36, // SS
328 0x3E, // DS
329 0x64, // FS
330 0x65 // GS
331 };
332
333 if (!rm.isMem())
334 return;
335
336 uint32_t seg = reinterpret_cast<const Mem&>(rm).getSegment();
337 if (seg >= kX86RegNumSeg)
338 return;
339
340 _emitByte(segmentCode[seg]);
341 }
342
_emitX86Inl(uint32_t opCode,uint8_t i16bit,uint8_t rexw,uint8_t reg,bool forceRexPrefix)343 void X86Assembler::_emitX86Inl(
344 uint32_t opCode, uint8_t i16bit, uint8_t rexw, uint8_t reg, bool forceRexPrefix)
345 {
346 // 16-bit prefix.
347 if (i16bit) _emitByte(0x66);
348
349 // Instruction prefix.
350 if (opCode & 0xFF000000) _emitByte((uint8_t)((opCode & 0xFF000000) >> 24));
351
352 // REX prefix.
353 #if defined(ASMJIT_X64)
354 _emitRexR(rexw, 0, reg, forceRexPrefix);
355 #endif // ASMJIT_X64
356
357 // Instruction opcodes.
358 if (opCode & 0x00FF0000) _emitByte((uint8_t)((opCode & 0x00FF0000) >> 16));
359 if (opCode & 0x0000FF00) _emitByte((uint8_t)((opCode & 0x0000FF00) >> 8));
360
361 _emitByte((uint8_t)(opCode & 0x000000FF) + (reg & 0x7));
362 }
363
_emitX86RM(uint32_t opCode,uint8_t i16bit,uint8_t rexw,uint8_t o,const Operand & op,sysint_t immSize,bool forceRexPrefix)364 void X86Assembler::_emitX86RM(
365 uint32_t opCode, uint8_t i16bit, uint8_t rexw, uint8_t o,
366 const Operand& op, sysint_t immSize, bool forceRexPrefix)
367 {
368 // 16-bit prefix.
369 if (i16bit) _emitByte(0x66);
370
371 // Segment prefix.
372 _emitSegmentPrefix(op);
373
374 // Instruction prefix.
375 if (opCode & 0xFF000000) _emitByte((uint8_t)((opCode & 0xFF000000) >> 24));
376
377 // REX prefix.
378 #if defined(ASMJIT_X64)
379 _emitRexRM(rexw, o, op, forceRexPrefix);
380 #endif // ASMJIT_X64
381
382 // Instruction opcodes.
383 if (opCode & 0x00FF0000) _emitByte((uint8_t)((opCode & 0x00FF0000) >> 16));
384 if (opCode & 0x0000FF00) _emitByte((uint8_t)((opCode & 0x0000FF00) >> 8));
385 _emitByte((uint8_t)(opCode & 0x000000FF));
386
387 // Mod R/M.
388 _emitModRM(o, op, immSize);
389 }
390
_emitFpu(uint32_t opCode)391 void X86Assembler::_emitFpu(uint32_t opCode)
392 {
393 _emitOpCode(opCode);
394 }
395
_emitFpuSTI(uint32_t opCode,uint32_t sti)396 void X86Assembler::_emitFpuSTI(uint32_t opCode, uint32_t sti)
397 {
398 // Illegal stack offset.
399 ASMJIT_ASSERT(0 <= sti && sti < 8);
400 _emitOpCode(opCode + sti);
401 }
402
_emitFpuMEM(uint32_t opCode,uint8_t opReg,const Mem & mem)403 void X86Assembler::_emitFpuMEM(uint32_t opCode, uint8_t opReg, const Mem& mem)
404 {
405 // Segment prefix.
406 _emitSegmentPrefix(mem);
407
408 // Instruction prefix.
409 if (opCode & 0xFF000000) _emitByte((uint8_t)((opCode & 0xFF000000) >> 24));
410
411 // REX prefix.
412 #if defined(ASMJIT_X64)
413 _emitRexRM(0, opReg, mem, false);
414 #endif // ASMJIT_X64
415
416 // Instruction opcodes.
417 if (opCode & 0x00FF0000) _emitByte((uint8_t)((opCode & 0x00FF0000) >> 16));
418 if (opCode & 0x0000FF00) _emitByte((uint8_t)((opCode & 0x0000FF00) >> 8));
419
420 _emitByte((uint8_t)((opCode & 0x000000FF)));
421 _emitModM(opReg, mem, 0);
422 }
423
_emitMmu(uint32_t opCode,uint8_t rexw,uint8_t opReg,const Operand & src,sysint_t immSize)424 void X86Assembler::_emitMmu(uint32_t opCode, uint8_t rexw, uint8_t opReg,
425 const Operand& src, sysint_t immSize)
426 {
427 // Segment prefix.
428 _emitSegmentPrefix(src);
429
430 // Instruction prefix.
431 if (opCode & 0xFF000000) _emitByte((uint8_t)((opCode & 0xFF000000) >> 24));
432
433 // REX prefix.
434 #if defined(ASMJIT_X64)
435 _emitRexRM(rexw, opReg, src, false);
436 #endif // ASMJIT_X64
437
438 // Instruction opcodes.
439 if (opCode & 0x00FF0000) _emitByte((uint8_t)((opCode & 0x00FF0000) >> 16));
440
441 // No checking, MMX/SSE instructions have always two opcodes or more.
442 _emitByte((uint8_t)((opCode & 0x0000FF00) >> 8));
443 _emitByte((uint8_t)((opCode & 0x000000FF)));
444
445 if (src.isReg())
446 _emitModR(opReg, reinterpret_cast<const Reg&>(src).getRegCode());
447 else
448 _emitModM(opReg, reinterpret_cast<const Mem&>(src), immSize);
449 }
450
_emitDisplacement(LabelData & l_data,sysint_t inlinedDisplacement,int size)451 X86Assembler::LabelLink* X86Assembler::_emitDisplacement(
452 LabelData& l_data, sysint_t inlinedDisplacement, int size)
453 {
454 ASMJIT_ASSERT(l_data.offset == -1);
455 ASMJIT_ASSERT(size == 1 || size == 4);
456
457 // Chain with label.
458 LabelLink* link = _newLabelLink();
459 link->prev = l_data.links;
460 link->offset = getOffset();
461 link->displacement = inlinedDisplacement;
462
463 l_data.links = link;
464
465 // Emit label size as dummy data.
466 if (size == 1)
467 _emitByte(0x01);
468 else // if (size == 4)
469 _emitDWord(0x04040404);
470
471 return link;
472 }
473
_emitJmpOrCallReloc(uint32_t instruction,void * target)474 void X86Assembler::_emitJmpOrCallReloc(uint32_t instruction, void* target)
475 {
476 RelocData rd;
477
478 rd.type = kRelocTrampoline;
479
480 #if defined(ASMJIT_X64)
481 // If we are compiling in 64-bit mode, we can use trampoline if relative jump
482 // is not possible.
483 _trampolineSize += X64TrampolineWriter::kSizeTotal;
484 #endif // ARCHITECTURE_SPECIFIC
485
486 rd.size = 4;
487 rd.offset = getOffset();
488 rd.address = target;
489
490 _relocData.append(rd);
491
492 // Emit dummy 32-bit integer (will be overwritten by relocCode()).
493 _emitInt32(0);
494 }
495
496 //! @internal
497 //!
498 //! @brief Get whether the extended register (additional eight registers
499 //! introduced by 64-bit mode) is used.
X86Assembler_isExtRegisterUsed(const Operand & op)500 static inline bool X86Assembler_isExtRegisterUsed(const Operand& op)
501 {
502 // Hacky, but correct.
503 // - If operand type is register then extended register is register with
504 // index 8 and greater (8 to 15 inclusive).
505 // - If operand type is memory operand then we need to take care about
506 // label (in _mem.base) and kInvalidValue, we just decrement the value
507 // by 8 and check if it's at interval 0 to 7 inclusive (if it's there
508 // then it's extended register.
509 return (op.isReg() && (op._reg.code & kRegIndexMask) >= 8U) ||
510 (op.isMem() && ((((uint32_t)op._mem.base - 8U) < 8U) ||
511 (((uint32_t)op._mem.index - 8U) < 8U) ));
512 }
513
514 // Logging helpers.
515 static const char* AssemblerX86_operandSize[] =
516 {
517 NULL,
518 "byte ptr ",
519 "word ptr ",
520 NULL,
521 "dword ptr ",
522 NULL,
523 NULL,
524 NULL,
525 "qword ptr ",
526 NULL,
527 "tword ptr ",
528 NULL,
529 NULL,
530 NULL,
531 NULL,
532 NULL,
533 "dqword ptr "
534 };
535
536 static const char X86Assembler_segmentName[] =
537 "es:\0"
538 "cs:\0"
539 "ss:\0"
540 "ds:\0"
541 "fs:\0"
542 "gs:\0"
543 "\0\0\0\0";
544
X86Assembler_dumpInstructionName(char * buf,uint32_t code)545 static char* X86Assembler_dumpInstructionName(char* buf, uint32_t code)
546 {
547 ASMJIT_ASSERT(code < _kX86InstCount);
548 return StringUtil::copy(buf, x86InstInfo[code].getName());
549 }
550
X86Assembler_dumpRegister(char * buf,uint32_t type,uint32_t index)551 char* X86Assembler_dumpRegister(char* buf, uint32_t type, uint32_t index)
552 {
553 // NE == Not-Encodable.
554 const char reg8l[] = "al\0\0" "cl\0\0" "dl\0\0" "bl\0\0" "spl\0" "bpl\0" "sil\0" "dil\0" ;
555 const char reg8h[] = "ah\0\0" "ch\0\0" "dh\0\0" "bh\0\0" "NE\0\0" "NE\0\0" "NE\0\0" "NE\0\0";
556 const char reg16[] = "ax\0\0" "cx\0\0" "dx\0\0" "bx\0\0" "sp\0\0" "bp\0\0" "si\0\0" "di\0\0";
557
558 switch (type)
559 {
560 case kX86RegTypeGpbLo:
561 if (index < 8)
562 return StringUtil::copy(buf, ®8l[index*4]);
563
564 *buf++ = 'r';
565 goto _EmitID;
566
567 case kX86RegTypeGpbHi:
568 if (index < 4)
569 return StringUtil::copy(buf, ®8h[index*4]);
570
571 _EmitNE:
572 return StringUtil::copy(buf, "NE");
573
574 case kX86RegTypeGpw:
575 if (index < 8)
576 return StringUtil::copy(buf, ®16[index*4]);
577
578 *buf++ = 'r';
579 buf = StringUtil::utoa(buf, index);
580 *buf++ = 'w';
581 return buf;
582
583 case kX86RegTypeGpd:
584 if (index < 8)
585 {
586 *buf++ = 'e';
587 return StringUtil::copy(buf, ®16[index*4]);
588 }
589
590 *buf++ = 'r';
591 buf = StringUtil::utoa(buf, index);
592 *buf++ = 'd';
593 return buf;
594
595 case kX86RegTypeGpq:
596 *buf++ = 'r';
597
598 if (index < 8)
599 return StringUtil::copy(buf, ®16[index*4]);
600
601 _EmitID:
602 return StringUtil::utoa(buf, index);
603
604 case kX86RegTypeX87:
605 *buf++ = 's';
606 *buf++ = 't';
607 goto _EmitID;
608
609 case kX86RegTypeMm:
610 *buf++ = 'm';
611 *buf++ = 'm';
612 goto _EmitID;
613
614 case kX86RegTypeXmm:
615 *buf++ = 'x';
616 *buf++ = 'm';
617 *buf++ = 'm';
618 goto _EmitID;
619
620 case kX86RegTypeYmm:
621 *buf++ = 'y';
622 *buf++ = 'm';
623 *buf++ = 'm';
624 goto _EmitID;
625
626 case kX86RegTypeSeg:
627 if (index < kX86RegNumSeg)
628 return StringUtil::copy(buf, &X86Assembler_segmentName[index*4], 2);
629
630 goto _EmitNE;
631
632 default:
633 return buf;
634 }
635 }
636
X86Assembler_dumpOperand(char * buf,const Operand * op,uint32_t memRegType,uint32_t loggerFlags)637 char* X86Assembler_dumpOperand(char* buf, const Operand* op, uint32_t memRegType, uint32_t loggerFlags)
638 {
639 if (op->isReg())
640 {
641 const Reg& reg = reinterpret_cast<const Reg&>(*op);
642 return X86Assembler_dumpRegister(buf, reg.getRegType(), reg.getRegIndex());
643 }
644 else if (op->isMem())
645 {
646 const Mem& mem = reinterpret_cast<const Mem&>(*op);
647 uint32_t seg = mem.getSegment();
648
649 bool isAbsolute = false;
650
651 if (op->getSize() <= 16)
652 buf = StringUtil::copy(buf, AssemblerX86_operandSize[op->getSize()]);
653
654 if (seg < kX86RegNumSeg)
655 buf = StringUtil::copy(buf, &X86Assembler_segmentName[seg * 4]);
656
657 *buf++ = '[';
658
659 switch (mem.getMemType())
660 {
661 case kOperandMemNative:
662 {
663 // [base + index << shift + displacement]
664 buf = X86Assembler_dumpRegister(buf, memRegType, mem.getBase());
665 break;
666 }
667 case kOperandMemLabel:
668 {
669 // [label + index << shift + displacement]
670 buf += sprintf(buf, "L.%u", mem.getBase() & kOperandIdValueMask);
671 break;
672 }
673 case kOperandMemAbsolute:
674 {
675 // [absolute]
676 isAbsolute = true;
677 buf = StringUtil::utoa(buf, (sysuint_t)mem.getTarget() + mem.getDisplacement(), 16);
678 break;
679 }
680 }
681
682 if (mem.hasIndex())
683 {
684 buf = StringUtil::copy(buf, " + ");
685 buf = X86Assembler_dumpRegister(buf, memRegType, mem.getIndex());
686
687 if (mem.getShift())
688 {
689 buf = StringUtil::copy(buf, " * ");
690 *buf++ = "1248"[mem.getShift() & 3];
691 }
692 }
693
694 if (mem.getDisplacement() && !isAbsolute)
695 {
696 sysint_t d = mem.getDisplacement();
697 uint32_t base = 10;
698 char sign = '+';
699
700 if (d < 0)
701 {
702 d = -d;
703 sign = '-';
704 }
705
706 buf[0] = ' ';
707 buf[1] = sign;
708 buf[2] = ' ';
709 buf += 3;
710
711 if ((loggerFlags & kLoggerOutputHexDisplacement) != 0 && d > 9)
712 {
713 buf[0] = '0';
714 buf[1] = 'x';
715 buf += 2;
716 base = 16;
717 }
718
719 buf = StringUtil::utoa(buf, static_cast<uintptr_t>(d), base);
720 }
721
722 *buf++ = ']';
723 return buf;
724 }
725 else if (op->isImm())
726 {
727 const Imm& i = reinterpret_cast<const Imm&>(*op);
728
729 sysuint_t value = i.getUValue();
730 uint32_t base = 10;
731
732 if ((loggerFlags & kLoggerOutputHexImmediate) && value > 9)
733 base = 16;
734
735 if (i.isUnsigned() || base == 16)
736 {
737 return StringUtil::utoa(buf, value, base);
738 }
739 else
740 {
741 return StringUtil::itoa(buf, static_cast<sysint_t>(value), base);
742 }
743 }
744 else if (op->isLabel())
745 {
746 return buf + sprintf(buf, "L.%u", op->getId() & kOperandIdValueMask);
747 }
748 else
749 {
750 return StringUtil::copy(buf, "None");
751 }
752 }
753
X86Assembler_dumpInstruction(char * buf,uint32_t code,uint32_t emitOptions,const Operand * o0,const Operand * o1,const Operand * o2,uint32_t memRegType,uint32_t loggerFlags)754 static char* X86Assembler_dumpInstruction(char* buf,
755 uint32_t code, uint32_t emitOptions,
756 const Operand* o0,
757 const Operand* o1,
758 const Operand* o2,
759 uint32_t memRegType,
760 uint32_t loggerFlags)
761 {
762 // Rex, lock, and short prefix.
763 if (emitOptions & kX86EmitOptionRex)
764 buf = StringUtil::copy(buf, "rex ", 4);
765
766 if (emitOptions & kX86EmitOptionLock)
767 buf = StringUtil::copy(buf, "lock ", 5);
768
769 if (emitOptions & kX86EmitOptionShortJump)
770 buf = StringUtil::copy(buf, "short ", 6);
771
772 // Dump instruction name.
773 buf = X86Assembler_dumpInstructionName(buf, code);
774
775 // Dump operands.
776 if (!o0->isNone()) { *buf++ = ' '; buf = X86Assembler_dumpOperand(buf, o0, memRegType, loggerFlags); }
777 if (!o1->isNone()) { *buf++ = ','; *buf++ = ' '; buf = X86Assembler_dumpOperand(buf, o1, memRegType, loggerFlags); }
778 if (!o2->isNone()) { *buf++ = ','; *buf++ = ' '; buf = X86Assembler_dumpOperand(buf, o2, memRegType, loggerFlags); }
779
780 return buf;
781 }
782
X86Assembler_dumpComment(char * buf,size_t len,const uint8_t * binaryData,size_t binaryLen,const char * comment)783 static char* X86Assembler_dumpComment(char* buf, size_t len, const uint8_t* binaryData, size_t binaryLen, const char* comment)
784 {
785 size_t currentLength = len;
786 size_t commentLength = comment ? strnlen(comment, kMaxCommentLength) : 0;
787
788 if (binaryLen || commentLength)
789 {
790 size_t align = 32;
791 char sep = ';';
792
793 for (size_t i = (binaryLen == 0); i < 2; i++)
794 {
795 char* bufBegin = buf;
796
797 // Append align.
798 if (currentLength < align)
799 {
800 buf = StringUtil::fill(buf, ' ', align - currentLength);
801 }
802
803 // Append separator.
804 if (sep)
805 {
806 *buf++ = sep;
807 *buf++ = ' ';
808 }
809
810 // Append binary data or comment.
811 if (i == 0)
812 {
813 buf = StringUtil::hex(buf, binaryData, binaryLen);
814 if (commentLength == 0)
815 break;
816 }
817 else
818 {
819 buf = StringUtil::copy(buf, comment, commentLength);
820 }
821
822 currentLength += (size_t)(buf - bufBegin);
823 align += 18;
824 sep = '|';
825 }
826 }
827
828 *buf++ = '\n';
829 return buf;
830 }
831
832 static const _OpReg _patchedHiRegs[4] =
833 {
834 // Operand |Size|Reserved0|Reserved1| OperandId | RegisterCode |
835 // ----------+----+---------+---------+--------------+-----------------------+
836 { kOperandReg, 1, {0 ,0 }, kInvalidValue, kX86RegTypeGpbLo | 4 },
837 { kOperandReg, 1, {0 ,0 }, kInvalidValue, kX86RegTypeGpbLo | 5 },
838 { kOperandReg, 1, {0 ,0 }, kInvalidValue, kX86RegTypeGpbLo | 6 },
839 { kOperandReg, 1, {0 ,0 }, kInvalidValue, kX86RegTypeGpbLo | 7 }
840 };
841
_emitInstruction(uint32_t code)842 void X86Assembler::_emitInstruction(uint32_t code)
843 {
844 _emitInstruction(code, &noOperand, &noOperand, &noOperand);
845 }
846
_emitInstruction(uint32_t code,const Operand * o0)847 void X86Assembler::_emitInstruction(uint32_t code, const Operand* o0)
848 {
849 _emitInstruction(code, o0, &noOperand, &noOperand);
850 }
851
_emitInstruction(uint32_t code,const Operand * o0,const Operand * o1)852 void X86Assembler::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1)
853 {
854 _emitInstruction(code, o0, o1, &noOperand);
855 }
856
_emitInstruction(uint32_t code,const Operand * o0,const Operand * o1,const Operand * o2)857 void X86Assembler::_emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2)
858 {
859 ASMJIT_ASSERT(o0 != NULL);
860 ASMJIT_ASSERT(o1 != NULL);
861 ASMJIT_ASSERT(o2 != NULL);
862
863 const Operand* _loggerOperands[3];
864
865 uint32_t bLoHiUsed = 0;
866 #if defined(ASMJIT_X86)
867 uint32_t forceRexPrefix = false;
868 #else
869 uint32_t forceRexPrefix = _emitOptions & kX86EmitOptionRex;
870 #endif
871 uint32_t memRegType = kX86RegTypeGpz;
872
873 #if defined(ASMJIT_DEBUG)
874 bool assertIllegal = false;
875 #endif // ASMJIT_DEBUG
876
877 const Imm* immOperand = NULL;
878 uint32_t immSize;
879
880 #define _FINISHED() \
881 goto _End
882
883 #define _FINISHED_IMMEDIATE(_Operand_, _Size_) \
884 do { \
885 immOperand = reinterpret_cast<const Imm*>(_Operand_); \
886 immSize = (_Size_); \
887 goto _EmitImmediate; \
888 } while (0)
889
890 // Convert operands to kOperandNone if needed.
891 if (o0->isReg()) bLoHiUsed |= o0->_reg.code & (kX86RegTypeGpbLo | kX86RegTypeGpbHi);
892 if (o1->isReg()) bLoHiUsed |= o1->_reg.code & (kX86RegTypeGpbLo | kX86RegTypeGpbHi);
893 if (o2->isReg()) bLoHiUsed |= o2->_reg.code & (kX86RegTypeGpbLo | kX86RegTypeGpbHi);
894
895 size_t beginOffset = getOffset();
896 const X86InstInfo* id = &x86InstInfo[code];
897
898 if (code >= _kX86InstCount)
899 {
900 setError(kErrorUnknownInstruction);
901 goto _Cleanup;
902 }
903
904 // Check if register operand is BPL, SPL, SIL, DIL and do action that depends
905 // to current mode:
906 // - 64-bit: - Force REX prefix.
907 //
908 // Check if register operand is AH, BH, CH or DH and do action that depends
909 // to current mode:
910 // - 32-bit: - Patch operand index (index += 4), because we are using
911 // different index what is used in opcode.
912 // - 64-bit: - Check whether there is REX prefix and raise error if it is.
913 // - Do the same as in 32-bit mode - patch register index.
914 //
915 // NOTE: This is a hit hacky, but I added this to older code-base and I have
916 // no energy to rewrite it. Maybe in future all of this can be cleaned up!
917 if (bLoHiUsed | forceRexPrefix)
918 {
919 _loggerOperands[0] = o0;
920 _loggerOperands[1] = o1;
921 _loggerOperands[2] = o2;
922
923 #if defined(ASMJIT_X64)
924 // Check if there is register that makes this instruction un-encodable.
925
926 forceRexPrefix |= (uint32_t)X86Assembler_isExtRegisterUsed(*o0);
927 forceRexPrefix |= (uint32_t)X86Assembler_isExtRegisterUsed(*o1);
928 forceRexPrefix |= (uint32_t)X86Assembler_isExtRegisterUsed(*o2);
929
930 if (o0->isRegType(kX86RegTypeGpbLo) && (o0->_reg.code & kRegIndexMask) >= 4) forceRexPrefix = true;
931 else if (o1->isRegType(kX86RegTypeGpbLo) && (o1->_reg.code & kRegIndexMask) >= 4) forceRexPrefix = true;
932 else if (o2->isRegType(kX86RegTypeGpbLo) && (o2->_reg.code & kRegIndexMask) >= 4) forceRexPrefix = true;
933
934 if ((bLoHiUsed & kX86RegTypeGpbHi) != 0 && forceRexPrefix)
935 {
936 goto _IllegalInstruction;
937 }
938 #endif // ASMJIT_X64
939
940 // Patch GPB.HI operand index.
941 if ((bLoHiUsed & kX86RegTypeGpbHi) != 0)
942 {
943 if (o0->isRegType(kX86RegTypeGpbHi)) o0 = reinterpret_cast<const Operand*>(&_patchedHiRegs[o0->_reg.code & kRegIndexMask]);
944 if (o1->isRegType(kX86RegTypeGpbHi)) o1 = reinterpret_cast<const Operand*>(&_patchedHiRegs[o1->_reg.code & kRegIndexMask]);
945 if (o2->isRegType(kX86RegTypeGpbHi)) o2 = reinterpret_cast<const Operand*>(&_patchedHiRegs[o2->_reg.code & kRegIndexMask]);
946 }
947 }
948
949 // Check for buffer space (and grow if needed).
950 if (!canEmit()) goto _Cleanup;
951
952 if (_emitOptions & kX86EmitOptionLock)
953 {
954 if (!id->isLockable())
955 goto _IllegalInstruction;
956 _emitByte(0xF0);
957 }
958
959 switch (id->getGroup())
960 {
961 case kX86InstGroupNone:
962 {
963 _FINISHED();
964 }
965
966 case kX86InstGroupEmit:
967 {
968 _emitOpCode(id->_opCode[0]);
969 _FINISHED();
970 }
971
972 case kX86InstGroupArith:
973 {
974 uint32_t opCode = id->_opCode[0];
975 uint8_t opReg = (uint8_t)id->_opCodeR;
976
977 // Mem <- Reg
978 if (o0->isMem() && o1->isReg())
979 {
980 _emitX86RM(opCode + (o1->getSize() != 1),
981 o1->getSize() == 2,
982 o1->getSize() == 8,
983 reinterpret_cast<const GpReg&>(*o1).getRegCode(),
984 reinterpret_cast<const Operand&>(*o0),
985 0, forceRexPrefix);
986 _FINISHED();
987 }
988
989 // Reg <- Reg|Mem
990 if (o0->isReg() && o1->isRegMem())
991 {
992 _emitX86RM(opCode + 2 + (o0->getSize() != 1),
993 o0->getSize() == 2,
994 o0->getSize() == 8,
995 reinterpret_cast<const GpReg&>(*o0).getRegCode(),
996 reinterpret_cast<const Operand&>(*o1),
997 0, forceRexPrefix);
998 _FINISHED();
999 }
1000
1001 // Alternate Form - AL, AX, EAX, RAX.
1002 if (o0->isRegIndex(0) && o1->isImm())
1003 {
1004 if (o0->getSize() == 1 || !IntUtil::isInt8(static_cast<const Imm*>(o1)->getValue()))
1005 {
1006 if (o0->getSize() == 2)
1007 _emitByte(0x66); // 16-bit.
1008 else if (o0->getSize() == 8)
1009 _emitByte(0x48); // REX.W.
1010
1011 _emitByte((opReg << 3) | (0x04 + (o0->getSize() != 1)));
1012 _FINISHED_IMMEDIATE(o1, IntUtil::_min<uint32_t>(o0->getSize(), 4));
1013 }
1014 }
1015
1016 if (o0->isRegMem() && o1->isImm())
1017 {
1018 const Imm& imm = reinterpret_cast<const Imm&>(*o1);
1019 immSize = IntUtil::isInt8(imm.getValue()) ? 1 : IntUtil::_min<uint32_t>(o0->getSize(), 4);
1020
1021 _emitX86RM(id->_opCode[1] + (o0->getSize() != 1 ? (immSize != 1 ? 1 : 3) : 0),
1022 o0->getSize() == 2,
1023 o0->getSize() == 8,
1024 opReg, reinterpret_cast<const Operand&>(*o0),
1025 immSize, forceRexPrefix);
1026 _FINISHED_IMMEDIATE(&imm, immSize);
1027 }
1028
1029 break;
1030 }
1031
1032 case kX86InstGroupBSwap:
1033 {
1034 if (o0->isReg())
1035 {
1036 const GpReg& dst = reinterpret_cast<const GpReg&>(*o0);
1037
1038 #if defined(ASMJIT_X64)
1039 _emitRexR(dst.getRegType() == kX86RegTypeGpq, 1, dst.getRegCode(), forceRexPrefix);
1040 #endif // ASMJIT_X64
1041 _emitByte(0x0F);
1042 _emitModR(1, dst.getRegCode());
1043 _FINISHED();
1044 }
1045
1046 break;
1047 }
1048
1049 case kX86InstGroupBTest:
1050 {
1051 if (o0->isRegMem() && o1->isReg())
1052 {
1053 const Operand& dst = reinterpret_cast<const Operand&>(*o0);
1054 const GpReg& src = reinterpret_cast<const GpReg&>(*o1);
1055
1056 _emitX86RM(id->_opCode[0],
1057 src.isRegType(kX86RegTypeGpw),
1058 src.isRegType(kX86RegTypeGpq),
1059 src.getRegCode(),
1060 dst,
1061 0, forceRexPrefix);
1062 _FINISHED();
1063 }
1064
1065 if (o0->isRegMem() && o1->isImm())
1066 {
1067 const Operand& dst = reinterpret_cast<const Operand&>(*o0);
1068 const Imm& src = reinterpret_cast<const Imm&>(*o1);
1069
1070 _emitX86RM(id->_opCode[1],
1071 dst.getSize() == 2,
1072 dst.getSize() == 8,
1073 (uint8_t)id->_opCodeR,
1074 dst,
1075 1, forceRexPrefix);
1076 _FINISHED_IMMEDIATE(o1, 1);
1077 }
1078
1079 break;
1080 }
1081
1082 case kX86InstGroupCall:
1083 {
1084 if (o0->isRegTypeMem(kX86RegTypeGpz))
1085 {
1086 const Operand& dst = reinterpret_cast<const Operand&>(*o0);
1087 _emitX86RM(0xFF,
1088 0,
1089 0, 2, dst,
1090 0, forceRexPrefix);
1091 _FINISHED();
1092 }
1093
1094 if (o0->isImm())
1095 {
1096 const Imm& imm = reinterpret_cast<const Imm&>(*o0);
1097 _emitByte(0xE8);
1098 _emitJmpOrCallReloc(kX86InstGroupCall, (void*)imm.getValue());
1099 _FINISHED();
1100 }
1101
1102 if (o0->isLabel())
1103 {
1104 LabelData& l_data = _labels[reinterpret_cast<const Label*>(o0)->getId() & kOperandIdValueMask];
1105
1106 if (l_data.offset != -1)
1107 {
1108 // Bound label.
1109 static const sysint_t rel32_size = 5;
1110 sysint_t offs = l_data.offset - getOffset();
1111
1112 ASMJIT_ASSERT(offs <= 0);
1113
1114 _emitByte(0xE8);
1115 _emitInt32((int32_t)(offs - rel32_size));
1116 }
1117 else
1118 {
1119 // Non-bound label.
1120 _emitByte(0xE8);
1121 _emitDisplacement(l_data, -4, 4);
1122 }
1123 _FINISHED();
1124 }
1125
1126 break;
1127 }
1128
1129 case kX86InstGroupCrc32:
1130 {
1131 if (o0->isReg() && o1->isRegMem())
1132 {
1133 const GpReg& dst = reinterpret_cast<const GpReg&>(*o0);
1134 const Operand& src = reinterpret_cast<const Operand&>(*o1);
1135 ASMJIT_ASSERT(dst.getRegType() == kX86RegTypeGpd || dst.getRegType() == kX86RegTypeGpq);
1136
1137 _emitX86RM(id->_opCode[0] + (src.getSize() != 1),
1138 src.getSize() == 2,
1139 dst.getRegType() == 8, dst.getRegCode(), src,
1140 0, forceRexPrefix);
1141 _FINISHED();
1142 }
1143
1144 break;
1145 }
1146
1147 case kX86InstGroupEnter:
1148 {
1149 if (o0->isImm() && o1->isImm())
1150 {
1151 _emitByte(0xC8);
1152 _emitWord((uint16_t)(uintptr_t)reinterpret_cast<const Imm&>(*o2).getValue());
1153 _emitByte((uint8_t )(uintptr_t)reinterpret_cast<const Imm&>(*o1).getValue());
1154 _FINISHED();
1155 }
1156 break;
1157 }
1158
1159 case kX86InstGroupIMul:
1160 {
1161 // 1 operand
1162 if (o0->isRegMem() && o1->isNone() && o2->isNone())
1163 {
1164 const Operand& src = reinterpret_cast<const Operand&>(*o0);
1165 _emitX86RM(0xF6 + (src.getSize() != 1),
1166 src.getSize() == 2,
1167 src.getSize() == 8, 5, src,
1168 0, forceRexPrefix);
1169 _FINISHED();
1170 }
1171 // 2 operands
1172 else if (o0->isReg() && !o1->isNone() && o2->isNone())
1173 {
1174 const GpReg& dst = reinterpret_cast<const GpReg&>(*o0);
1175 ASMJIT_ASSERT(!dst.isRegType(kX86RegTypeGpw));
1176
1177 if (o1->isRegMem())
1178 {
1179 const Operand& src = reinterpret_cast<const Operand&>(*o1);
1180
1181 _emitX86RM(0x0FAF,
1182 dst.isRegType(kX86RegTypeGpw),
1183 dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), src,
1184 0, forceRexPrefix);
1185 _FINISHED();
1186 }
1187 else if (o1->isImm())
1188 {
1189 const Imm& imm = reinterpret_cast<const Imm&>(*o1);
1190
1191 if (IntUtil::isInt8(imm.getValue()))
1192 {
1193 _emitX86RM(0x6B,
1194 dst.isRegType(kX86RegTypeGpw),
1195 dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), dst,
1196 1, forceRexPrefix);
1197 _FINISHED_IMMEDIATE(&imm, 1);
1198 }
1199 else
1200 {
1201 immSize = dst.isRegType(kX86RegTypeGpw) ? 2 : 4;
1202 _emitX86RM(0x69,
1203 dst.isRegType(kX86RegTypeGpw),
1204 dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), dst,
1205 immSize, forceRexPrefix);
1206 _FINISHED_IMMEDIATE(&imm, immSize);
1207 }
1208 }
1209 }
1210 // 3 operands
1211 else if (o0->isReg() && o1->isRegMem() && o2->isImm())
1212 {
1213 const GpReg& dst = reinterpret_cast<const GpReg&>(*o0);
1214 const Operand& src = reinterpret_cast<const Operand&>(*o1);
1215 const Imm& imm = reinterpret_cast<const Imm&>(*o2);
1216
1217 if (IntUtil::isInt8(imm.getValue()))
1218 {
1219 _emitX86RM(0x6B,
1220 dst.isRegType(kX86RegTypeGpw),
1221 dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), src,
1222 1, forceRexPrefix);
1223 _FINISHED_IMMEDIATE(&imm, 1);
1224 }
1225 else
1226 {
1227 immSize = dst.isRegType(kX86RegTypeGpw) ? 2 : 4;
1228 _emitX86RM(0x69,
1229 dst.isRegType(kX86RegTypeGpw),
1230 dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), src,
1231 immSize, forceRexPrefix);
1232 _FINISHED_IMMEDIATE(&imm, immSize);
1233 }
1234 }
1235
1236 break;
1237 }
1238
1239 case kX86InstGroupIncDec:
1240 {
1241 if (o0->isRegMem())
1242 {
1243 const Operand& dst = reinterpret_cast<const Operand&>(*o0);
1244
1245 // INC [r16|r32] in 64-bit mode is not encodable.
1246 #if defined(ASMJIT_X86)
1247 if ((dst.isReg()) && (dst.isRegType(kX86RegTypeGpw) || dst.isRegType(kX86RegTypeGpd)))
1248 {
1249 _emitX86Inl(id->_opCode[0],
1250 dst.isRegType(kX86RegTypeGpw),
1251 0, reinterpret_cast<const Reg&>(dst).getRegCode(),
1252 false);
1253 _FINISHED();
1254 }
1255 #endif // ASMJIT_X86
1256
1257 _emitX86RM(id->_opCode[1] + (dst.getSize() != 1),
1258 dst.getSize() == 2,
1259 dst.getSize() == 8, (uint8_t)id->_opCodeR, dst,
1260 0, forceRexPrefix);
1261 _FINISHED();
1262 }
1263
1264 break;
1265 }
1266
1267 case kX86InstGroupJcc:
1268 {
1269 if (o0->isLabel())
1270 {
1271 LabelData& l_data = _labels[reinterpret_cast<const Label*>(o0)->getId() & kOperandIdValueMask];
1272
1273 uint32_t hint = (uint32_t)(o1->isImm() ? reinterpret_cast<const Imm&>(*o1).getValue() : 0);
1274 bool isShortJump = (_emitOptions & kX86EmitOptionShortJump) != 0;
1275
1276 // Emit jump hint if configured for that.
1277 if ((hint & (kCondHintLikely | kCondHintUnlikely)) && (_properties & (1 << kX86PropertyJumpHints)))
1278 {
1279 if (hint & kCondHintLikely)
1280 _emitByte(kX86CondPrefixLikely);
1281 else if (hint & kCondHintUnlikely)
1282 _emitByte(kX86CondPrefixUnlikely);
1283 }
1284
1285 if (l_data.offset != -1)
1286 {
1287 // Bound label.
1288 static const sysint_t rel8_size = 2;
1289 static const sysint_t rel32_size = 6;
1290 sysint_t offs = l_data.offset - getOffset();
1291
1292 ASMJIT_ASSERT(offs <= 0);
1293
1294 if (IntUtil::isInt8(offs - rel8_size))
1295 {
1296 _emitByte(0x70 | (uint8_t)id->_opCode[0]);
1297 _emitByte((uint8_t)(int8_t)(offs - rel8_size));
1298
1299 // Change the emit options so logger can log instruction correctly.
1300 _emitOptions |= kX86EmitOptionShortJump;
1301 }
1302 else
1303 {
1304 if (isShortJump && _logger)
1305 {
1306 _logger->logString("*** ASSEMBLER WARNING: Emitting long conditional jump, but short jump instruction forced!\n");
1307 _emitOptions &= ~kX86EmitOptionShortJump;
1308 }
1309
1310 _emitByte(0x0F);
1311 _emitByte(0x80 | (uint8_t)id->_opCode[0]);
1312 _emitInt32((int32_t)(offs - rel32_size));
1313 }
1314 }
1315 else
1316 {
1317 // Non-bound label.
1318 if (isShortJump)
1319 {
1320 _emitByte(0x70 | (uint8_t)id->_opCode[0]);
1321 _emitDisplacement(l_data, -1, 1);
1322 }
1323 else
1324 {
1325 _emitByte(0x0F);
1326 _emitByte(0x80 | (uint8_t)id->_opCode[0]);
1327 _emitDisplacement(l_data, -4, 4);
1328 }
1329 }
1330 _FINISHED();
1331 }
1332
1333 break;
1334 }
1335
1336 case kX86InstGroupJmp:
1337 {
1338 if (o0->isRegMem())
1339 {
1340 const Operand& dst = reinterpret_cast<const Operand&>(*o0);
1341
1342 _emitX86RM(0xFF,
1343 0,
1344 0, 4, dst,
1345 0, forceRexPrefix);
1346 _FINISHED();
1347 }
1348
1349 if (o0->isImm())
1350 {
1351 const Imm& imm = reinterpret_cast<const Imm&>(*o0);
1352 _emitByte(0xE9);
1353 _emitJmpOrCallReloc(kX86InstGroupJmp, (void*)imm.getValue());
1354 _FINISHED();
1355 }
1356
1357 if (o0->isLabel())
1358 {
1359 LabelData& l_data = _labels[reinterpret_cast<const Label*>(o0)->getId() & kOperandIdValueMask];
1360 bool isShortJump = (_emitOptions & kX86EmitOptionShortJump) != 0;
1361
1362 if (l_data.offset != -1)
1363 {
1364 // Bound label.
1365 const sysint_t rel8_size = 2;
1366 const sysint_t rel32_size = 5;
1367 sysint_t offs = l_data.offset - getOffset();
1368
1369 if (IntUtil::isInt8(offs - rel8_size))
1370 {
1371 _emitByte(0xEB);
1372 _emitByte((uint8_t)(int8_t)(offs - rel8_size));
1373
1374 // Change the emit options so logger can log instruction correctly.
1375 _emitOptions |= kX86EmitOptionShortJump;
1376 }
1377 else
1378 {
1379 if (isShortJump)
1380 {
1381 if (_logger)
1382 {
1383 _logger->logString("*** ASSEMBLER WARNING: Emitting long jump, but short jump instruction forced!\n");
1384 _emitOptions &= ~kX86EmitOptionShortJump;
1385 }
1386 }
1387
1388 _emitByte(0xE9);
1389 _emitInt32((int32_t)(offs - rel32_size));
1390 }
1391 }
1392 else
1393 {
1394 // Non-bound label.
1395 if (isShortJump)
1396 {
1397 _emitByte(0xEB);
1398 _emitDisplacement(l_data, -1, 1);
1399 }
1400 else
1401 {
1402 _emitByte(0xE9);
1403 _emitDisplacement(l_data, -4, 4);
1404 }
1405 }
1406 _FINISHED();
1407 }
1408
1409 break;
1410 }
1411
1412 case kX86InstGroupLea:
1413 {
1414 if (o0->isReg() && o1->isMem())
1415 {
1416 const GpReg& dst = reinterpret_cast<const GpReg&>(*o0);
1417 const Mem& src = reinterpret_cast<const Mem&>(*o1);
1418
1419 // Size override prefix support.
1420 if (src.getSizePrefix())
1421 {
1422 _emitByte(0x67);
1423 #if defined(ASMJIT_X86)
1424 memRegType = kX86RegTypeGpw;
1425 #else
1426 memRegType = kX86RegTypeGpd;
1427 #endif
1428 }
1429
1430 _emitX86RM(0x8D,
1431 dst.isRegType(kX86RegTypeGpw),
1432 dst.isRegType(kX86RegTypeGpq), dst.getRegCode(), src,
1433 0, forceRexPrefix);
1434 _FINISHED();
1435 }
1436
1437 break;
1438 }
1439
1440 case kX86InstGroupMem:
1441 {
1442 if (o0->isMem())
1443 {
1444 _emitX86RM(id->_opCode[0], 0, (uint8_t)id->_opCode[1], (uint8_t)id->_opCodeR, reinterpret_cast<const Mem&>(*o0), 0, forceRexPrefix);
1445 _FINISHED();
1446 }
1447 break;
1448 }
1449
1450 case kX86InstGroupMov:
1451 {
1452 const Operand& dst = *o0;
1453 const Operand& src = *o1;
1454
1455 switch (dst.getType() << 4 | src.getType())
1456 {
1457 // Reg <- Reg/Mem
1458 case (kOperandReg << 4) | kOperandReg:
1459 {
1460 // Reg <- Sreg
1461 if (src.isRegType(kX86RegTypeSeg))
1462 {
1463 ASMJIT_ASSERT(dst.isRegType(kX86RegTypeGpw) ||
1464 dst.isRegType(kX86RegTypeGpd) ||
1465 dst.isRegType(kX86RegTypeGpq) );
1466
1467 _emitX86RM(0x8C,
1468 dst.getSize() == 2,
1469 dst.getSize() == 8,
1470 reinterpret_cast<const SegmentReg&>(src).getRegCode(),
1471 reinterpret_cast<const Operand&>(dst),
1472 0, forceRexPrefix);
1473 _FINISHED();
1474 }
1475
1476 // Sreg <- Reg/Mem
1477 if (dst.isRegType(kX86RegTypeSeg))
1478 {
1479 ASMJIT_ASSERT(src.isRegType(kX86RegTypeGpw ) ||
1480 src.isRegType(kX86RegTypeGpd ) ||
1481 src.isRegType(kX86RegTypeGpq ) );
1482
1483 _Emit_Mov_Sreg_RM:
1484 _emitX86RM(0x8E,
1485 src.getSize() == 2,
1486 src.getSize() == 8,
1487 reinterpret_cast<const SegmentReg&>(dst).getRegCode(),
1488 reinterpret_cast<const Operand&>(src),
1489 0, forceRexPrefix);
1490 _FINISHED();
1491 }
1492
1493 ASMJIT_ASSERT(src.isRegType(kX86RegTypeGpbLo) ||
1494 src.isRegType(kX86RegTypeGpbHi) ||
1495 src.isRegType(kX86RegTypeGpw ) ||
1496 src.isRegType(kX86RegTypeGpd ) ||
1497 src.isRegType(kX86RegTypeGpq ) );
1498 // ... fall through ...
1499 }
1500 case (kOperandReg << 4) | kOperandMem:
1501 {
1502 // Sreg <- Mem
1503 if (dst.isRegType(kX86RegTypeSeg))
1504 {
1505 goto _Emit_Mov_Sreg_RM;
1506 }
1507
1508 ASMJIT_ASSERT(dst.isRegType(kX86RegTypeGpbLo) ||
1509 dst.isRegType(kX86RegTypeGpbHi) ||
1510 dst.isRegType(kX86RegTypeGpw ) ||
1511 dst.isRegType(kX86RegTypeGpd ) ||
1512 dst.isRegType(kX86RegTypeGpq ) );
1513
1514 _emitX86RM(0x0000008A + (dst.getSize() != 1),
1515 dst.isRegType(kX86RegTypeGpw),
1516 dst.isRegType(kX86RegTypeGpq),
1517 reinterpret_cast<const GpReg&>(dst).getRegCode(),
1518 reinterpret_cast<const Operand&>(src),
1519 0, forceRexPrefix);
1520 _FINISHED();
1521 }
1522
1523 // Reg <- Imm
1524 case (kOperandReg << 4) | kOperandImm:
1525 {
1526 const GpReg& dst = reinterpret_cast<const GpReg&>(*o0);
1527 const Imm& src = reinterpret_cast<const Imm&>(*o1);
1528
1529 // In 64-bit mode the immediate can be 64-bits long if the
1530 // destination operand type is register (otherwise 32-bits).
1531 immSize = dst.getSize();
1532
1533 #if defined(ASMJIT_X64)
1534 // Optimize instruction size by using 32-bit immediate if value can
1535 // fit into it.
1536 if (immSize == 8 && IntUtil::isInt32(src.getValue()))
1537 {
1538 _emitX86RM(0xC7,
1539 0, // 16BIT
1540 1, // REX.W
1541 0, // O
1542 dst,
1543 0, forceRexPrefix);
1544 immSize = 4;
1545 }
1546 else
1547 {
1548 #endif // ASMJIT_X64
1549 _emitX86Inl((dst.getSize() == 1 ? 0xB0 : 0xB8),
1550 dst.isRegType(kX86RegTypeGpw),
1551 dst.isRegType(kX86RegTypeGpq),
1552 dst.getRegCode(), forceRexPrefix);
1553 #if defined(ASMJIT_X64)
1554 }
1555 #endif // ASMJIT_X64
1556
1557 _FINISHED_IMMEDIATE(&src, immSize);
1558 }
1559
1560 // Mem <- Reg/Sreg
1561 case (kOperandMem << 4) | kOperandReg:
1562 {
1563 if (src.isRegType(kX86RegTypeSeg))
1564 {
1565 // Mem <- Sreg
1566 _emitX86RM(0x8C,
1567 dst.getSize() == 2,
1568 dst.getSize() == 8,
1569 reinterpret_cast<const SegmentReg&>(src).getRegCode(),
1570 reinterpret_cast<const Operand&>(dst),
1571 0, forceRexPrefix);
1572 _FINISHED();
1573 }
1574 else
1575 {
1576 // Mem <- Reg
1577 ASMJIT_ASSERT(src.isRegType(kX86RegTypeGpbLo) ||
1578 src.isRegType(kX86RegTypeGpbHi) ||
1579 src.isRegType(kX86RegTypeGpw ) ||
1580 src.isRegType(kX86RegTypeGpd ) ||
1581 src.isRegType(kX86RegTypeGpq ) );
1582
1583 _emitX86RM(0x88 + (src.getSize() != 1),
1584 src.isRegType(kX86RegTypeGpw),
1585 src.isRegType(kX86RegTypeGpq),
1586 reinterpret_cast<const GpReg&>(src).getRegCode(),
1587 reinterpret_cast<const Operand&>(dst),
1588 0, forceRexPrefix);
1589 _FINISHED();
1590 }
1591 }
1592
1593 // Mem <- Imm
1594 case (kOperandMem << 4) | kOperandImm:
1595 {
1596 immSize = IntUtil::_min<uint32_t>(dst.getSize(), 4);
1597
1598 _emitX86RM(0xC6 + (dst.getSize() != 1),
1599 dst.getSize() == 2,
1600 dst.getSize() == 8,
1601 0,
1602 reinterpret_cast<const Operand&>(dst),
1603 immSize, forceRexPrefix);
1604 _FINISHED_IMMEDIATE(&src, immSize);
1605 }
1606 }
1607
1608 break;
1609 }
1610
1611 case kX86InstGroupMovPtr:
1612 {
1613 if ((o0->isReg() && o1->isImm()) || (o0->isImm() && o1->isReg()))
1614 {
1615 bool reverse = o1->getType() == kOperandReg;
1616 uint8_t opCode = !reverse ? 0xA0 : 0xA2;
1617 const GpReg& reg = reinterpret_cast<const GpReg&>(!reverse ? *o0 : *o1);
1618 const Imm& imm = reinterpret_cast<const Imm&>(!reverse ? *o1 : *o0);
1619
1620 if (reg.getRegIndex() != 0)
1621 goto _IllegalInstruction;
1622
1623 if (reg.isRegType(kX86RegTypeGpw)) _emitByte(0x66);
1624 #if defined(ASMJIT_X64)
1625 _emitRexR(reg.getSize() == 8, 0, 0, forceRexPrefix);
1626 #endif // ASMJIT_X64
1627 _emitByte(opCode + (reg.getSize() != 1));
1628 _FINISHED_IMMEDIATE(&imm, sizeof(sysint_t));
1629 }
1630
1631 break;
1632 }
1633
1634 case kX86InstGroupMovSxMovZx:
1635 {
1636 if (o0->isReg() && o1->isRegMem())
1637 {
1638 const GpReg& dst = reinterpret_cast<const GpReg&>(*o0);
1639 const Operand& src = reinterpret_cast<const Operand&>(*o1);
1640
1641 if (dst.getSize() == 1)
1642 goto _IllegalInstruction;
1643
1644 if (src.getSize() != 1 && src.getSize() != 2)
1645 goto _IllegalInstruction;
1646
1647 if (src.getSize() == 2 && dst.getSize() == 2)
1648 goto _IllegalInstruction;
1649
1650 _emitX86RM(id->_opCode[0] + (src.getSize() != 1),
1651 dst.isRegType(kX86RegTypeGpw),
1652 dst.isRegType(kX86RegTypeGpq),
1653 dst.getRegCode(),
1654 src,
1655 0, forceRexPrefix);
1656 _FINISHED();
1657 }
1658
1659 break;
1660 }
1661
1662 #if defined(ASMJIT_X64)
1663 case kX86InstGroupMovSxD:
1664 {
1665 if (o0->isReg() && o1->isRegMem())
1666 {
1667 const GpReg& dst = reinterpret_cast<const GpReg&>(*o0);
1668 const Operand& src = reinterpret_cast<const Operand&>(*o1);
1669 _emitX86RM(0x00000063,
1670 0,
1671 1, dst.getRegCode(), src,
1672 0, forceRexPrefix);
1673 _FINISHED();
1674 }
1675
1676 break;
1677 }
1678 #endif // ASMJIT_X64
1679
1680 case kX86InstGroupPush:
1681 {
1682 if (o0->isRegType(kX86RegTypeSeg))
1683 {
1684 static const uint32_t opcodeList[] =
1685 {
1686 0x06, // ES.
1687 0x0E, // CS.
1688 0x16, // SS.
1689 0x1E, // DS.
1690 0x0FA0, // FS.
1691 0x0FA8 // GS.
1692 };
1693
1694 unsigned int segment = reinterpret_cast<const SegmentReg*>(o0)->getRegIndex();
1695 ASMJIT_ASSERT(segment < kX86SegCount);
1696
1697 unsigned int opcode = opcodeList[segment];
1698
1699 if (opcode > 0xFF)
1700 _emitByte(opcode >> 8);
1701 _emitByte(opcode & 0xFF);
1702
1703 _FINISHED();
1704 }
1705
1706 // This section is only for immediates, memory/register operands are handled in kX86InstGroupPop.
1707 if (o0->isImm())
1708 {
1709 const Imm& imm = reinterpret_cast<const Imm&>(*o0);
1710
1711 if (IntUtil::isInt8(imm.getValue()))
1712 {
1713 _emitByte(0x6A);
1714 _FINISHED_IMMEDIATE(&imm, 1);
1715 }
1716 else
1717 {
1718 _emitByte(0x68);
1719 _FINISHED_IMMEDIATE(&imm, 4);
1720 }
1721 }
1722
1723 // ... goto kX86InstGroupPop ...
1724 }
1725
1726 case kX86InstGroupPop:
1727 {
1728 if (o0->isRegType(kX86RegTypeSeg))
1729 {
1730 static const uint32_t opcodeList[] =
1731 {
1732 0x07, // ES.
1733 0, // CS.
1734 0x17, // SS.
1735 0x1F, // DS.
1736 0x0FA1, // FS.
1737 0x0FA9 // GS.
1738 };
1739
1740 unsigned int segment = reinterpret_cast<const SegmentReg*>(o0)->getRegIndex();
1741 ASMJIT_ASSERT(segment < kX86SegCount);
1742
1743 unsigned int opcode = opcodeList[segment];
1744 ASMJIT_ASSERT(opcode != 0);
1745
1746 if (opcode > 0xFF)
1747 _emitByte(opcode >> 8);
1748 _emitByte(opcode & 0xFF);
1749
1750 _FINISHED();
1751 }
1752
1753 if (o0->isReg())
1754 {
1755 ASMJIT_ASSERT(o0->isRegType(kX86RegTypeGpw) || o0->isRegType(kX86RegTypeGpz));
1756 _emitX86Inl(id->_opCode[0], o0->isRegType(kX86RegTypeGpw), 0, reinterpret_cast<const GpReg&>(*o0).getRegCode(), forceRexPrefix);
1757 _FINISHED();
1758 }
1759
1760 if (o0->isMem())
1761 {
1762 _emitX86RM(id->_opCode[1], o0->getSize() == 2, 0, (uint8_t)id->_opCodeR, reinterpret_cast<const Operand&>(*o0), 0, forceRexPrefix);
1763 _FINISHED();
1764 }
1765
1766 break;
1767 }
1768
1769 case kX86InstGroupRegRm:
1770 {
1771 if (o0->isReg() && o1->isRegMem())
1772 {
1773 const GpReg& dst = reinterpret_cast<const GpReg&>(*o0);
1774 const Operand& src = reinterpret_cast<const Operand&>(*o1);
1775 ASMJIT_ASSERT(dst.getSize() != 1);
1776
1777 _emitX86RM(id->_opCode[0],
1778 dst.getRegType() == kX86RegTypeGpw,
1779 dst.getRegType() == kX86RegTypeGpq, dst.getRegCode(), src,
1780 0, forceRexPrefix);
1781 _FINISHED();
1782 }
1783
1784 break;
1785 }
1786
1787 case kX86InstGroupRm:
1788 {
1789 if (o0->isRegMem())
1790 {
1791 const Operand& op = reinterpret_cast<const Operand&>(*o0);
1792 _emitX86RM(id->_opCode[0] + (op.getSize() != 1),
1793 op.getSize() == 2,
1794 op.getSize() == 8, (uint8_t)id->_opCodeR, op,
1795 0, forceRexPrefix);
1796 _FINISHED();
1797 }
1798
1799 break;
1800 }
1801
1802 case kX86InstGroupRmByte:
1803 {
1804 if (o0->isRegMem())
1805 {
1806 const Operand& op = reinterpret_cast<const Operand&>(*o0);
1807
1808 // Only BYTE register or BYTE/TYPELESS memory location can be used.
1809 ASMJIT_ASSERT(op.getSize() <= 1);
1810
1811 _emitX86RM(id->_opCode[0], false, false, 0, op, 0, forceRexPrefix);
1812 _FINISHED();
1813 }
1814
1815 break;
1816 }
1817
1818 case kX86InstGroupRmReg:
1819 {
1820 if (o0->isRegMem() && o1->isReg())
1821 {
1822 const Operand& dst = reinterpret_cast<const Operand&>(*o0);
1823 const GpReg& src = reinterpret_cast<const GpReg&>(*o1);
1824 _emitX86RM(id->_opCode[0] + (src.getSize() != 1),
1825 src.getRegType() == kX86RegTypeGpw,
1826 src.getRegType() == kX86RegTypeGpq, src.getRegCode(), dst,
1827 0, forceRexPrefix);
1828 _FINISHED();
1829 }
1830
1831 break;
1832 }
1833
1834 case kX86InstGroupRep:
1835 {
1836 uint32_t opCode = id->_opCode[0];
1837 uint32_t opSize = id->_opCode[1];
1838
1839 // Emit REP prefix (1 BYTE).
1840 _emitByte(opCode >> 24);
1841
1842 if (opSize != 1) opCode++; // D, Q and W form.
1843 if (opSize == 2) _emitByte(0x66); // 16-bit prefix.
1844 #if defined(ASMJIT_X64)
1845 else if (opSize == 8) _emitByte(0x48); // REX.W prefix.
1846 #endif // ASMJIT_X64
1847
1848 // Emit opcode (1 BYTE).
1849 _emitByte(opCode & 0xFF);
1850 _FINISHED();
1851 }
1852
1853 case kX86InstGroupRet:
1854 {
1855 if (o0->isNone())
1856 {
1857 _emitByte(0xC3);
1858 _FINISHED();
1859 }
1860 else if (o0->isImm())
1861 {
1862 const Imm& imm = reinterpret_cast<const Imm&>(*o0);
1863 ASMJIT_ASSERT(IntUtil::isUInt16(imm.getValue()));
1864
1865 if (imm.getValue() == 0)
1866 {
1867 _emitByte(0xC3);
1868 _FINISHED();
1869 }
1870 else
1871 {
1872 _emitByte(0xC2);
1873 _FINISHED_IMMEDIATE(&imm, 2);
1874 }
1875 }
1876
1877 break;
1878 }
1879
1880 case kX86InstGroupRot:
1881 {
1882 if (o0->isRegMem() && (o1->isRegCode(kX86RegCl) || o1->isImm()))
1883 {
1884 // generate opcode. For these operations is base 0xC0 or 0xD0.
1885 bool useImm8 = o1->isImm() && reinterpret_cast<const Imm&>(*o1).getValue() != 1;
1886 uint32_t opCode = useImm8 ? 0xC0 : 0xD0;
1887
1888 // size and operand type modifies the opcode
1889 if (o0->getSize() != 1) opCode |= 0x01;
1890 if (o1->getType() == kOperandReg) opCode |= 0x02;
1891
1892 _emitX86RM(opCode,
1893 o0->getSize() == 2,
1894 o0->getSize() == 8,
1895 (uint8_t)id->_opCodeR, reinterpret_cast<const Operand&>(*o0),
1896 useImm8 ? 1 : 0, forceRexPrefix);
1897
1898 if (useImm8)
1899 _FINISHED_IMMEDIATE(o1, 1);
1900 else
1901 _FINISHED();
1902 }
1903
1904 break;
1905 }
1906
1907 case kX86InstGroupShldShrd:
1908 {
1909 if (o0->isRegMem() && o1->isReg() && (o2->isImm() || (o2->isReg() && o2->isRegCode(kX86RegCl))))
1910 {
1911 const Operand& dst = reinterpret_cast<const Operand&>(*o0);
1912 const GpReg& src1 = reinterpret_cast<const GpReg&>(*o1);
1913 const Operand& src2 = reinterpret_cast<const Operand&>(*o2);
1914
1915 ASMJIT_ASSERT(dst.getSize() == src1.getSize());
1916
1917 _emitX86RM(id->_opCode[0] + src2.isReg(),
1918 src1.isRegType(kX86RegTypeGpw),
1919 src1.isRegType(kX86RegTypeGpq),
1920 src1.getRegCode(), dst,
1921 src2.isImm() ? 1 : 0, forceRexPrefix);
1922 if (src2.isImm())
1923 _FINISHED_IMMEDIATE(&src2, 1);
1924 else
1925 _FINISHED();
1926 }
1927
1928 break;
1929 }
1930
1931 case kX86InstGroupTest:
1932 {
1933 if (o0->isRegMem() && o1->isReg())
1934 {
1935 ASMJIT_ASSERT(o0->getSize() == o1->getSize());
1936 _emitX86RM(0x84 + (o1->getSize() != 1),
1937 o1->getSize() == 2, o1->getSize() == 8,
1938 reinterpret_cast<const Reg&>(*o1).getRegCode(),
1939 reinterpret_cast<const Operand&>(*o0),
1940 0, forceRexPrefix);
1941 _FINISHED();
1942 }
1943
1944 // Alternate Form - AL, AX, EAX, RAX.
1945 if (o0->isRegIndex(0) && o1->isImm())
1946 {
1947 immSize = IntUtil::_min<uint32_t>(o0->getSize(), 4);
1948
1949 if (o0->getSize() == 2) _emitByte(0x66); // 16-bit.
1950 #if defined(ASMJIT_X64)
1951 _emitRexRM(o0->getSize() == 8, 0, reinterpret_cast<const Operand&>(*o0), forceRexPrefix);
1952 #endif // ASMJIT_X64
1953 _emitByte(0xA8 + (o0->getSize() != 1));
1954 _FINISHED_IMMEDIATE(o1, immSize);
1955 }
1956
1957 if (o0->isRegMem() && o1->isImm())
1958 {
1959 immSize = IntUtil::_min<uint32_t>(o0->getSize(), 4);
1960
1961 if (o0->getSize() == 2) _emitByte(0x66); // 16-bit.
1962 _emitSegmentPrefix(reinterpret_cast<const Operand&>(*o0)); // Segment prefix.
1963 #if defined(ASMJIT_X64)
1964 _emitRexRM(o0->getSize() == 8, 0, reinterpret_cast<const Operand&>(*o0), forceRexPrefix);
1965 #endif // ASMJIT_X64
1966 _emitByte(0xF6 + (o0->getSize() != 1));
1967 _emitModRM(0, reinterpret_cast<const Operand&>(*o0), immSize);
1968 _FINISHED_IMMEDIATE(o1, immSize);
1969 }
1970
1971 break;
1972 }
1973
1974 case kX86InstGroupXchg:
1975 {
1976 if (o0->isRegMem() && o1->isReg())
1977 {
1978 const Operand& dst = reinterpret_cast<const Operand&>(*o0);
1979 const GpReg& src = reinterpret_cast<const GpReg&>(*o1);
1980
1981 if (src.isRegType(kX86RegTypeGpw)) _emitByte(0x66); // 16-bit.
1982 _emitSegmentPrefix(dst); // segment prefix
1983 #if defined(ASMJIT_X64)
1984 _emitRexRM(src.isRegType(kX86RegTypeGpq), src.getRegCode(), dst, forceRexPrefix);
1985 #endif // ASMJIT_X64
1986
1987 // Special opcode for index 0 registers (AX, EAX, RAX vs register).
1988 if ((dst.getType() == kOperandReg && dst.getSize() > 1) &&
1989 (reinterpret_cast<const GpReg&>(dst).getRegCode() == 0 ||
1990 reinterpret_cast<const GpReg&>(src).getRegCode() == 0 ))
1991 {
1992 uint8_t index = reinterpret_cast<const GpReg&>(dst).getRegCode() | src.getRegCode();
1993 _emitByte(0x90 + index);
1994 _FINISHED();
1995 }
1996
1997 _emitByte(0x86 + (src.getSize() != 1));
1998 _emitModRM(src.getRegCode(), dst, 0);
1999 _FINISHED();
2000 }
2001
2002 break;
2003 }
2004
2005 case kX86InstGroupMovBE:
2006 {
2007 if (o0->isReg() && o1->isMem())
2008 {
2009 _emitX86RM(0x000F38F0,
2010 o0->isRegType(kX86RegTypeGpw),
2011 o0->isRegType(kX86RegTypeGpq),
2012 reinterpret_cast<const GpReg&>(*o0).getRegCode(),
2013 reinterpret_cast<const Mem&>(*o1),
2014 0, forceRexPrefix);
2015 _FINISHED();
2016 }
2017
2018 if (o0->isMem() && o1->isReg())
2019 {
2020 _emitX86RM(0x000F38F1,
2021 o1->isRegType(kX86RegTypeGpw),
2022 o1->isRegType(kX86RegTypeGpq),
2023 reinterpret_cast<const GpReg&>(*o1).getRegCode(),
2024 reinterpret_cast<const Mem&>(*o0),
2025 0, forceRexPrefix);
2026 _FINISHED();
2027 }
2028
2029 break;
2030 }
2031
2032 case kX86InstGroupX87StM:
2033 {
2034 if (o0->isRegType(kX86RegTypeX87))
2035 {
2036 uint8_t i1 = reinterpret_cast<const X87Reg&>(*o0).getRegIndex();
2037 uint8_t i2 = 0;
2038
2039 if (code != kX86InstFCom && code != kX86InstFComP)
2040 {
2041 if (!o1->isRegType(kX86RegTypeX87))
2042 goto _IllegalInstruction;
2043 i2 = reinterpret_cast<const X87Reg&>(*o1).getRegIndex();
2044 }
2045 else if (i1 != 0 && i2 != 0)
2046 {
2047 goto _IllegalInstruction;
2048 }
2049
2050 _emitByte(i1 == 0
2051 ? ((id->_opCode[0] & 0xFF000000) >> 24)
2052 : ((id->_opCode[0] & 0x00FF0000) >> 16));
2053 _emitByte(i1 == 0
2054 ? ((id->_opCode[0] & 0x0000FF00) >> 8) + i2
2055 : ((id->_opCode[0] & 0x000000FF) ) + i1);
2056 _FINISHED();
2057 }
2058
2059 if (o0->isMem() && (o0->getSize() == 4 || o0->getSize() == 8) && o1->isNone())
2060 {
2061 const Mem& m = reinterpret_cast<const Mem&>(*o0);
2062
2063 // Segment prefix.
2064 _emitSegmentPrefix(m);
2065
2066 _emitByte(o0->getSize() == 4
2067 ? ((id->_opCode[0] & 0xFF000000) >> 24)
2068 : ((id->_opCode[0] & 0x00FF0000) >> 16));
2069 _emitModM((uint8_t)id->_opCodeR, m, 0);
2070 _FINISHED();
2071 }
2072
2073 break;
2074 }
2075
2076 case kX86InstGroupX87StI:
2077 {
2078 if (o0->isRegType(kX86RegTypeX87))
2079 {
2080 uint8_t i = reinterpret_cast<const X87Reg&>(*o0).getRegIndex();
2081 _emitByte((uint8_t)((id->_opCode[0] & 0x0000FF00) >> 8));
2082 _emitByte((uint8_t)((id->_opCode[0] & 0x000000FF) + i));
2083 _FINISHED();
2084 }
2085 break;
2086 }
2087
2088 case kX86InstGroupX87Status:
2089 {
2090 if (o0->isReg() &&
2091 reinterpret_cast<const Reg&>(*o0).getRegType() <= kX86RegTypeGpq &&
2092 reinterpret_cast<const Reg&>(*o0).getRegIndex() == 0)
2093 {
2094 _emitOpCode(id->_opCode[1]);
2095 _FINISHED();
2096 }
2097
2098 if (o0->isMem())
2099 {
2100 _emitX86RM(id->_opCode[0], 0, 0, (uint8_t)id->_opCodeR, reinterpret_cast<const Mem&>(*o0), 0, forceRexPrefix);
2101 _FINISHED();
2102 }
2103
2104 break;
2105 }
2106
2107 case kX86InstGroupX87FldFst:
2108 {
2109 if (o0->isRegType(kX86RegTypeX87))
2110 {
2111 _emitByte((uint8_t)((id->_opCode[1] & 0xFF000000) >> 24));
2112 _emitByte((uint8_t)((id->_opCode[1] & 0x00FF0000) >> 16) +
2113 reinterpret_cast<const X87Reg&>(*o0).getRegIndex());
2114 _FINISHED();
2115 }
2116
2117 // ... fall through to kX86InstGroupX87Mem ...
2118 }
2119
2120 case kX86InstGroupX87Mem:
2121 {
2122 if (!o0->isMem())
2123 goto _IllegalInstruction;
2124 const Mem& m = reinterpret_cast<const Mem&>(*o0);
2125
2126 uint8_t opCode = 0x00, mod = 0;
2127
2128 if (o0->getSize() == 2 && (id->_opFlags[0] & kX86InstOpStM2))
2129 {
2130 opCode = (uint8_t)((id->_opCode[0] & 0xFF000000) >> 24);
2131 mod = (uint8_t)id->_opCodeR;
2132 }
2133 if (o0->getSize() == 4 && (id->_opFlags[0] & kX86InstOpStM4))
2134 {
2135 opCode = (uint8_t)((id->_opCode[0] & 0x00FF0000) >> 16);
2136 mod = (uint8_t)id->_opCodeR;
2137 }
2138 if (o0->getSize() == 8 && (id->_opFlags[0] & kX86InstOpStM8))
2139 {
2140 opCode = (uint8_t)((id->_opCode[0] & 0x0000FF00) >> 8);
2141 mod = (uint8_t)((id->_opCode[0] & 0x000000FF) );
2142 }
2143
2144 if (opCode)
2145 {
2146 _emitSegmentPrefix(m);
2147 _emitByte(opCode);
2148 _emitModM(mod, m, 0);
2149 _FINISHED();
2150 }
2151
2152 break;
2153 }
2154
2155 case kX86InstGroupMmuMov:
2156 {
2157 ASMJIT_ASSERT(id->_opFlags[0] != 0);
2158 ASMJIT_ASSERT(id->_opFlags[1] != 0);
2159
2160 // Check parameters (X)MM|GP32_64 <- (X)MM|GP32_64|Mem|Imm
2161 if ((o0->isMem() && (id->_opFlags[0] & kX86InstOpMem) == 0) ||
2162 (o0->isRegType(kX86RegTypeMm ) && (id->_opFlags[0] & kX86InstOpMm ) == 0) ||
2163 (o0->isRegType(kX86RegTypeXmm) && (id->_opFlags[0] & kX86InstOpXmm) == 0) ||
2164 (o0->isRegType(kX86RegTypeGpd) && (id->_opFlags[0] & kX86InstOpGd ) == 0) ||
2165 (o0->isRegType(kX86RegTypeGpq) && (id->_opFlags[0] & kX86InstOpGq ) == 0) ||
2166 (o1->isRegType(kX86RegTypeMm ) && (id->_opFlags[1] & kX86InstOpMm ) == 0) ||
2167 (o1->isRegType(kX86RegTypeXmm) && (id->_opFlags[1] & kX86InstOpXmm) == 0) ||
2168 (o1->isRegType(kX86RegTypeGpd) && (id->_opFlags[1] & kX86InstOpGd ) == 0) ||
2169 (o1->isRegType(kX86RegTypeGpq) && (id->_opFlags[1] & kX86InstOpGq ) == 0) ||
2170 (o1->isMem() && (id->_opFlags[1] & kX86InstOpMem) == 0) )
2171 {
2172 goto _IllegalInstruction;
2173 }
2174
2175 // Illegal.
2176 if (o0->isMem() && o1->isMem())
2177 goto _IllegalInstruction;
2178
2179 uint8_t rexw = ((id->_opFlags[0] | id->_opFlags[1]) & kX86InstOpNoRex)
2180 ? 0
2181 : o0->isRegType(kX86RegTypeGpq) | o1->isRegType(kX86RegTypeGpq);
2182
2183 // (X)MM|Reg <- (X)MM|Reg
2184 if (o0->isReg() && o1->isReg())
2185 {
2186 _emitMmu(id->_opCode[0], rexw,
2187 reinterpret_cast<const Reg&>(*o0).getRegCode(),
2188 reinterpret_cast<const Reg&>(*o1),
2189 0);
2190 _FINISHED();
2191 }
2192
2193 // (X)MM|Reg <- Mem
2194 if (o0->isReg() && o1->isMem())
2195 {
2196 _emitMmu(id->_opCode[0], rexw,
2197 reinterpret_cast<const Reg&>(*o0).getRegCode(),
2198 reinterpret_cast<const Mem&>(*o1),
2199 0);
2200 _FINISHED();
2201 }
2202
2203 // Mem <- (X)MM|Reg
2204 if (o0->isMem() && o1->isReg())
2205 {
2206 _emitMmu(id->_opCode[1], rexw,
2207 reinterpret_cast<const Reg&>(*o1).getRegCode(),
2208 reinterpret_cast<const Mem&>(*o0),
2209 0);
2210 _FINISHED();
2211 }
2212
2213 break;
2214 }
2215
2216 case kX86InstGroupMmuMovD:
2217 {
2218 if ((o0->isRegType(kX86RegTypeMm) || o0->isRegType(kX86RegTypeXmm)) && (o1->isRegType(kX86RegTypeGpd) || o1->isMem()))
2219 {
2220 _emitMmu(o0->isRegType(kX86RegTypeXmm) ? 0x66000F6E : 0x00000F6E, 0,
2221 reinterpret_cast<const Reg&>(*o0).getRegCode(),
2222 reinterpret_cast<const Operand&>(*o1),
2223 0);
2224 _FINISHED();
2225 }
2226
2227 if ((o0->isRegType(kX86RegTypeGpd) || o0->isMem()) && (o1->isRegType(kX86RegTypeMm) || o1->isRegType(kX86RegTypeXmm)))
2228 {
2229 _emitMmu(o1->isRegType(kX86RegTypeXmm) ? 0x66000F7E : 0x00000F7E, 0,
2230 reinterpret_cast<const Reg&>(*o1).getRegCode(),
2231 reinterpret_cast<const Operand&>(*o0),
2232 0);
2233 _FINISHED();
2234 }
2235
2236 break;
2237 }
2238
2239 case kX86InstGroupMmuMovQ:
2240 {
2241 if (o0->isRegType(kX86RegTypeMm) && o1->isRegType(kX86RegTypeMm))
2242 {
2243 _emitMmu(0x00000F6F, 0,
2244 reinterpret_cast<const MmReg&>(*o0).getRegCode(),
2245 reinterpret_cast<const MmReg&>(*o1),
2246 0);
2247 _FINISHED();
2248 }
2249
2250 if (o0->isRegType(kX86RegTypeXmm) && o1->isRegType(kX86RegTypeXmm))
2251 {
2252 _emitMmu(0xF3000F7E, 0,
2253 reinterpret_cast<const XmmReg&>(*o0).getRegCode(),
2254 reinterpret_cast<const XmmReg&>(*o1),
2255 0);
2256 _FINISHED();
2257 }
2258
2259 // Convenience - movdq2q
2260 if (o0->isRegType(kX86RegTypeMm) && o1->isRegType(kX86RegTypeXmm))
2261 {
2262 _emitMmu(0xF2000FD6, 0,
2263 reinterpret_cast<const MmReg&>(*o0).getRegCode(),
2264 reinterpret_cast<const XmmReg&>(*o1),
2265 0);
2266 _FINISHED();
2267 }
2268
2269 // Convenience - movq2dq
2270 if (o0->isRegType(kX86RegTypeXmm) && o1->isRegType(kX86RegTypeMm))
2271 {
2272 _emitMmu(0xF3000FD6, 0,
2273 reinterpret_cast<const XmmReg&>(*o0).getRegCode(),
2274 reinterpret_cast<const MmReg&>(*o1),
2275 0);
2276 _FINISHED();
2277 }
2278
2279 if (o0->isRegType(kX86RegTypeMm) && o1->isMem())
2280 {
2281 _emitMmu(0x00000F6F, 0,
2282 reinterpret_cast<const MmReg&>(*o0).getRegCode(),
2283 reinterpret_cast<const Mem&>(*o1),
2284 0);
2285 _FINISHED();
2286 }
2287
2288 if (o0->isRegType(kX86RegTypeXmm) && o1->isMem())
2289 {
2290 _emitMmu(0xF3000F7E, 0,
2291 reinterpret_cast<const XmmReg&>(*o0).getRegCode(),
2292 reinterpret_cast<const Mem&>(*o1),
2293 0);
2294 _FINISHED();
2295 }
2296
2297 if (o0->isMem() && o1->isRegType(kX86RegTypeMm))
2298 {
2299 _emitMmu(0x00000F7F, 0,
2300 reinterpret_cast<const MmReg&>(*o1).getRegCode(),
2301 reinterpret_cast<const Mem&>(*o0),
2302 0);
2303 _FINISHED();
2304 }
2305
2306 if (o0->isMem() && o1->isRegType(kX86RegTypeXmm))
2307 {
2308 _emitMmu(0x66000FD6, 0,
2309 reinterpret_cast<const XmmReg&>(*o1).getRegCode(),
2310 reinterpret_cast<const Mem&>(*o0),
2311 0);
2312 _FINISHED();
2313 }
2314
2315 #if defined(ASMJIT_X64)
2316 if ((o0->isRegType(kX86RegTypeMm) || o0->isRegType(kX86RegTypeXmm)) && (o1->isRegType(kX86RegTypeGpq) || o1->isMem()))
2317 {
2318 _emitMmu(o0->isRegType(kX86RegTypeXmm) ? 0x66000F6E : 0x00000F6E, 1,
2319 reinterpret_cast<const Reg&>(*o0).getRegCode(),
2320 reinterpret_cast<const Operand&>(*o1),
2321 0);
2322 _FINISHED();
2323 }
2324
2325 if ((o0->isRegType(kX86RegTypeGpq) || o0->isMem()) && (o1->isRegType(kX86RegTypeMm) || o1->isRegType(kX86RegTypeXmm)))
2326 {
2327 _emitMmu(o1->isRegType(kX86RegTypeXmm) ? 0x66000F7E : 0x00000F7E, 1,
2328 reinterpret_cast<const Reg&>(*o1).getRegCode(),
2329 reinterpret_cast<const Operand&>(*o0),
2330 0);
2331 _FINISHED();
2332 }
2333 #endif // ASMJIT_X64
2334
2335 break;
2336 }
2337
2338 case kX86InstGroupMmuExtract:
2339 {
2340 if (!(o0->isRegMem() &&
2341 (o1->isRegType(kX86RegTypeXmm) || (code == kX86InstPExtrW && o1->isRegType(kX86RegTypeMm))) &&
2342 o2->isImm()))
2343 {
2344 goto _IllegalInstruction;
2345 }
2346
2347 uint32_t opCode = id->_opCode[0];
2348 uint8_t isGpdGpq = o0->isRegType(kX86RegTypeGpd) | o0->isRegType(kX86RegTypeGpq);
2349
2350 if (code == kX86InstPExtrB && (o0->getSize() != 0 && o0->getSize() != 1) && !isGpdGpq)
2351 goto _IllegalInstruction;
2352 if (code == kX86InstPExtrW && (o0->getSize() != 0 && o0->getSize() != 2) && !isGpdGpq)
2353 goto _IllegalInstruction;
2354 if (code == kX86InstPExtrD && (o0->getSize() != 0 && o0->getSize() != 4) && !isGpdGpq)
2355 goto _IllegalInstruction;
2356 if (code == kX86InstPExtrQ && (o0->getSize() != 0 && o0->getSize() != 8) && !isGpdGpq)
2357 goto _IllegalInstruction;
2358
2359 if (o1->isRegType(kX86RegTypeXmm)) opCode |= 0x66000000;
2360
2361 if (o0->isReg())
2362 {
2363 _emitMmu(opCode, id->_opCodeR | (uint8_t)o0->isRegType(kX86RegTypeGpq),
2364 reinterpret_cast<const Reg&>(*o1).getRegCode(),
2365 reinterpret_cast<const Reg&>(*o0), 1);
2366 _FINISHED_IMMEDIATE(o2, 1);
2367 }
2368
2369 if (o0->isMem())
2370 {
2371 _emitMmu(opCode, (uint8_t)id->_opCodeR,
2372 reinterpret_cast<const Reg&>(*o1).getRegCode(),
2373 reinterpret_cast<const Mem&>(*o0), 1);
2374 _FINISHED_IMMEDIATE(o2, 1);
2375 }
2376
2377 break;
2378 }
2379
2380 case kX86InstGroupMmuPrefetch:
2381 {
2382 if (o0->isMem() && o1->isImm())
2383 {
2384 const Mem& mem = reinterpret_cast<const Mem&>(*o0);
2385 const Imm& hint = reinterpret_cast<const Imm&>(*o1);
2386
2387 _emitMmu(0x00000F18, 0, (uint8_t)hint.getValue(), mem, 0);
2388 _FINISHED();
2389 }
2390
2391 break;
2392 }
2393
2394 case kX86InstGroupMmuRmI:
2395 {
2396 ASMJIT_ASSERT(id->_opFlags[0] != 0);
2397 ASMJIT_ASSERT(id->_opFlags[1] != 0);
2398
2399 // Check parameters (X)MM|GP32_64 <- (X)MM|GP32_64|Mem|Imm
2400 if (!o0->isReg() ||
2401 (o0->isRegType(kX86RegTypeMm ) && (id->_opFlags[0] & kX86InstOpMm ) == 0) ||
2402 (o0->isRegType(kX86RegTypeXmm) && (id->_opFlags[0] & kX86InstOpXmm) == 0) ||
2403 (o0->isRegType(kX86RegTypeGpd) && (id->_opFlags[0] & kX86InstOpGd ) == 0) ||
2404 (o0->isRegType(kX86RegTypeGpq) && (id->_opFlags[0] & kX86InstOpGq ) == 0) ||
2405 (o1->isRegType(kX86RegTypeMm ) && (id->_opFlags[1] & kX86InstOpMm ) == 0) ||
2406 (o1->isRegType(kX86RegTypeXmm) && (id->_opFlags[1] & kX86InstOpXmm) == 0) ||
2407 (o1->isRegType(kX86RegTypeGpd) && (id->_opFlags[1] & kX86InstOpGd ) == 0) ||
2408 (o1->isRegType(kX86RegTypeGpq) && (id->_opFlags[1] & kX86InstOpGq ) == 0) ||
2409 (o1->isMem() && (id->_opFlags[1] & kX86InstOpMem) == 0) ||
2410 (o1->isImm() && (id->_opFlags[1] & kX86InstOpImm) == 0))
2411 {
2412 goto _IllegalInstruction;
2413 }
2414
2415 uint32_t prefix =
2416 ((id->_opFlags[0] & kX86InstOpMmXmm) == kX86InstOpMmXmm && o0->isRegType(kX86RegTypeXmm)) ||
2417 ((id->_opFlags[1] & kX86InstOpMmXmm) == kX86InstOpMmXmm && o1->isRegType(kX86RegTypeXmm))
2418 ? 0x66000000
2419 : 0x00000000;
2420
2421 uint8_t rexw = ((id->_opFlags[0] | id->_opFlags[1]) & kX86InstOpNoRex)
2422 ? 0
2423 : o0->isRegType(kX86RegTypeGpq) | o1->isRegType(kX86RegTypeGpq);
2424
2425 // (X)MM <- (X)MM (opcode0)
2426 if (o1->isReg())
2427 {
2428 if ((id->_opFlags[1] & (kX86InstOpMmXmm | kX86InstOpGqd)) == 0)
2429 goto _IllegalInstruction;
2430 _emitMmu(id->_opCode[0] | prefix, rexw,
2431 reinterpret_cast<const Reg&>(*o0).getRegCode(),
2432 reinterpret_cast<const Reg&>(*o1), 0);
2433 _FINISHED();
2434 }
2435 // (X)MM <- Mem (opcode0)
2436 if (o1->isMem())
2437 {
2438 if ((id->_opFlags[1] & kX86InstOpMem) == 0)
2439 goto _IllegalInstruction;
2440 _emitMmu(id->_opCode[0] | prefix, rexw,
2441 reinterpret_cast<const Reg&>(*o0).getRegCode(),
2442 reinterpret_cast<const Mem&>(*o1), 0);
2443 _FINISHED();
2444 }
2445 // (X)MM <- Imm (opcode1+opcodeR)
2446 if (o1->isImm())
2447 {
2448 if ((id->_opFlags[1] & kX86InstOpImm) == 0)
2449 goto _IllegalInstruction;
2450 _emitMmu(id->_opCode[1] | prefix, rexw,
2451 (uint8_t)id->_opCodeR,
2452 reinterpret_cast<const Reg&>(*o0), 1);
2453 _FINISHED_IMMEDIATE(o1, 1);
2454 }
2455
2456 break;
2457 }
2458
2459 case kX86InstGroupMmuRmImm8:
2460 {
2461 ASMJIT_ASSERT(id->_opFlags[0] != 0);
2462 ASMJIT_ASSERT(id->_opFlags[1] != 0);
2463
2464 // Check parameters (X)MM|GP32_64 <- (X)MM|GP32_64|Mem|Imm
2465 if (!o0->isReg() ||
2466 (o0->isRegType(kX86RegTypeMm ) && (id->_opFlags[0] & kX86InstOpMm ) == 0) ||
2467 (o0->isRegType(kX86RegTypeXmm) && (id->_opFlags[0] & kX86InstOpXmm) == 0) ||
2468 (o0->isRegType(kX86RegTypeGpd) && (id->_opFlags[0] & kX86InstOpGd ) == 0) ||
2469 (o0->isRegType(kX86RegTypeGpq) && (id->_opFlags[0] & kX86InstOpGq ) == 0) ||
2470 (o1->isRegType(kX86RegTypeMm ) && (id->_opFlags[1] & kX86InstOpMm ) == 0) ||
2471 (o1->isRegType(kX86RegTypeXmm) && (id->_opFlags[1] & kX86InstOpXmm) == 0) ||
2472 (o1->isRegType(kX86RegTypeGpd) && (id->_opFlags[1] & kX86InstOpGd ) == 0) ||
2473 (o1->isRegType(kX86RegTypeGpq) && (id->_opFlags[1] & kX86InstOpGq ) == 0) ||
2474 (o1->isMem() && (id->_opFlags[1] & kX86InstOpMem) == 0) ||
2475 !o2->isImm())
2476 {
2477 goto _IllegalInstruction;
2478 }
2479
2480 uint32_t prefix =
2481 ((id->_opFlags[0] & kX86InstOpMmXmm) == kX86InstOpMmXmm && o0->isRegType(kX86RegTypeXmm)) ||
2482 ((id->_opFlags[1] & kX86InstOpMmXmm) == kX86InstOpMmXmm && o1->isRegType(kX86RegTypeXmm))
2483 ? 0x66000000
2484 : 0x00000000;
2485
2486 uint8_t rexw = ((id->_opFlags[0]|id->_opFlags[1]) & kX86InstOpNoRex)
2487 ? 0
2488 : o0->isRegType(kX86RegTypeGpq) | o1->isRegType(kX86RegTypeGpq);
2489
2490 // (X)MM <- (X)MM (opcode0)
2491 if (o1->isReg())
2492 {
2493 if ((id->_opFlags[1] & (kX86InstOpMmXmm | kX86InstOpGqd)) == 0)
2494 goto _IllegalInstruction;
2495 _emitMmu(id->_opCode[0] | prefix, rexw,
2496 reinterpret_cast<const Reg&>(*o0).getRegCode(),
2497 reinterpret_cast<const Reg&>(*o1), 1);
2498 _FINISHED_IMMEDIATE(o2, 1);
2499 }
2500 // (X)MM <- Mem (opcode0)
2501 if (o1->isMem())
2502 {
2503 if ((id->_opFlags[1] & kX86InstOpMem) == 0)
2504 goto _IllegalInstruction;
2505 _emitMmu(id->_opCode[0] | prefix, rexw,
2506 reinterpret_cast<const Reg&>(*o0).getRegCode(),
2507 reinterpret_cast<const Mem&>(*o1), 1);
2508 _FINISHED_IMMEDIATE(o2, 1);
2509 }
2510
2511 break;
2512 }
2513
2514 case kX86InstGroupMmuRm3dNow:
2515 {
2516 if (o0->isRegType(kX86RegTypeMm) && (o1->isRegType(kX86RegTypeMm) || o1->isMem()))
2517 {
2518 _emitMmu(id->_opCode[0], 0,
2519 reinterpret_cast<const Reg&>(*o0).getRegCode(),
2520 reinterpret_cast<const Mem&>(*o1), 1);
2521 _emitByte((uint8_t)id->_opCode[1]);
2522 _FINISHED();
2523 }
2524
2525 break;
2526 }
2527 }
2528
2529 _IllegalInstruction:
2530 // Set an error. If we run in release mode assertion will be not used, so we
2531 // must inform about invalid state.
2532 setError(kErrorIllegalInstruction);
2533
2534 #if defined(ASMJIT_DEBUG)
2535 assertIllegal = true;
2536 #endif // ASMJIT_DEBUG
2537 goto _End;
2538
2539 _EmitImmediate:
2540 {
2541 sysint_t value = immOperand->getValue();
2542 switch (immSize)
2543 {
2544 case 1: _emitByte ((uint8_t )(sysuint_t)value); break;
2545 case 2: _emitWord ((uint16_t)(sysuint_t)value); break;
2546 case 4: _emitDWord((uint32_t)(sysuint_t)value); break;
2547 #if defined(ASMJIT_X64)
2548 case 8: _emitQWord((uint64_t)(sysuint_t)value); break;
2549 #endif // ASMJIT_X64
2550 default: ASMJIT_ASSERT(0);
2551 }
2552 }
2553
2554 _End:
2555 if (_logger
2556 #if defined(ASMJIT_DEBUG)
2557 || assertIllegal
2558 #endif // ASMJIT_DEBUG
2559 )
2560 {
2561 char bufStorage[512];
2562 char* buf = bufStorage;
2563
2564 // Detect truncated operand.
2565 Imm immTemporary(0);
2566 uint32_t loggerFlags = 0;
2567
2568 // Use the original operands, because BYTE some of them were replaced.
2569 if (bLoHiUsed)
2570 {
2571 o0 = _loggerOperands[0];
2572 o1 = _loggerOperands[1];
2573 o2 = _loggerOperands[2];
2574 }
2575
2576 if (immOperand)
2577 {
2578 sysint_t value = immOperand->getValue();
2579 bool isUnsigned = immOperand->isUnsigned();
2580
2581 switch (immSize)
2582 {
2583 case 1: if ( isUnsigned && !IntUtil::isUInt8 (value)) { immTemporary.setValue((uint8_t)(sysuint_t)value, true ); break; }
2584 if (!isUnsigned && !IntUtil::isInt8 (value)) { immTemporary.setValue((uint8_t)(sysuint_t)value, false); break; }
2585 break;
2586 case 2: if ( isUnsigned && !IntUtil::isUInt16(value)) { immTemporary.setValue((uint16_t)(sysuint_t)value, true ); break; }
2587 if (!isUnsigned && !IntUtil::isInt16 (value)) { immTemporary.setValue((uint16_t)(sysuint_t)value, false); break; }
2588 break;
2589 case 4: if ( isUnsigned && !IntUtil::isUInt32(value)) { immTemporary.setValue((uint32_t)(sysuint_t)value, true ); break; }
2590 if (!isUnsigned && !IntUtil::isInt32 (value)) { immTemporary.setValue((uint32_t)(sysuint_t)value, false); break; }
2591 break;
2592 }
2593
2594 if (immTemporary.getValue() != 0)
2595 {
2596 if (o0 == immOperand) o0 = &immTemporary;
2597 if (o1 == immOperand) o1 = &immTemporary;
2598 if (o2 == immOperand) o2 = &immTemporary;
2599 }
2600 }
2601
2602 if (_logger)
2603 {
2604 buf = StringUtil::copy(buf, _logger->getInstructionPrefix());
2605 loggerFlags = _logger->getFlags();
2606 }
2607
2608 buf = X86Assembler_dumpInstruction(buf, code, _emitOptions, o0, o1, o2, memRegType, loggerFlags);
2609
2610 if ((loggerFlags & kLoggerOutputBinary) != 0)
2611 buf = X86Assembler_dumpComment(buf, (size_t)(buf - bufStorage), getCode() + beginOffset, getOffset() - beginOffset, _inlineComment);
2612 else
2613 buf = X86Assembler_dumpComment(buf, (size_t)(buf - bufStorage), NULL, 0, _inlineComment);
2614
2615 // We don't need to NULL terminate the resulting string.
2616 #if defined(ASMJIT_DEBUG)
2617 if (_logger)
2618 #endif // ASMJIT_DEBUG
2619 _logger->logString(bufStorage, (size_t)(buf - bufStorage));
2620
2621 #if defined(ASMJIT_DEBUG)
2622 if (assertIllegal)
2623 {
2624 // Here we need to NULL terminate.
2625 buf[0] = '\0';
2626
2627 // Raise an assertion failure, because this situation shouldn't happen.
2628 assertionFailure(__FILE__, __LINE__, bufStorage);
2629 }
2630 #endif // ASMJIT_DEBUG
2631 }
2632
2633 _Cleanup:
2634 _inlineComment = NULL;
2635 _emitOptions = 0;
2636 }
2637
_emitJcc(uint32_t code,const Label * label,uint32_t hint)2638 void X86Assembler::_emitJcc(uint32_t code, const Label* label, uint32_t hint)
2639 {
2640 if (hint == kCondHintNone)
2641 {
2642 _emitInstruction(code, label);
2643 }
2644 else
2645 {
2646 Imm imm(hint);
2647 _emitInstruction(code, label, &imm);
2648 }
2649 }
2650
2651 // ============================================================================
2652 // [AsmJit::Assembler - Relocation helpers]
2653 // ============================================================================
2654
relocCode(void * _dst,sysuint_t addressBase) const2655 size_t X86Assembler::relocCode(void* _dst, sysuint_t addressBase) const
2656 {
2657 // Copy code to virtual memory (this is a given _dst pointer).
2658 uint8_t* dst = reinterpret_cast<uint8_t*>(_dst);
2659
2660 size_t coff = _buffer.getOffset();
2661 size_t csize = getCodeSize();
2662
2663 // We are copying the exact size of the generated code. Extra code for trampolines
2664 // is generated on-the-fly by relocator (this code doesn't exist at the moment).
2665 memcpy(dst, _buffer.getData(), coff);
2666
2667 #if defined(ASMJIT_X64)
2668 // Trampoline pointer.
2669 uint8_t* tramp = dst + coff;
2670 #endif // ASMJIT_X64
2671
2672 // Relocate all recorded locations.
2673 size_t i;
2674 size_t len = _relocData.getLength();
2675
2676 for (i = 0; i < len; i++)
2677 {
2678 const RelocData& r = _relocData[i];
2679 sysint_t val;
2680
2681 #if defined(ASMJIT_X64)
2682 // Whether to use trampoline, can be only used if relocation type is
2683 // kRelocAbsToRel.
2684 bool useTrampoline = false;
2685 #endif // ASMJIT_X64
2686
2687 // Be sure that reloc data structure is correct.
2688 ASMJIT_ASSERT((size_t)(r.offset + r.size) <= csize);
2689
2690 switch (r.type)
2691 {
2692 case kRelocAbsToAbs:
2693 val = (sysint_t)(r.address);
2694 break;
2695
2696 case kRelocRelToAbs:
2697 val = (sysint_t)(addressBase + r.destination);
2698 break;
2699
2700 case kRelocAbsToRel:
2701 case kRelocTrampoline:
2702 val = (sysint_t)( (sysuint_t)r.address - (addressBase + (sysuint_t)r.offset + 4) );
2703
2704 #if defined(ASMJIT_X64)
2705 if (r.type == kRelocTrampoline && !IntUtil::isInt32(val))
2706 {
2707 val = (sysint_t)( (sysuint_t)tramp - ((sysuint_t)_dst + (sysuint_t)r.offset + 4) );
2708 useTrampoline = true;
2709 }
2710 #endif // ASMJIT_X64
2711 break;
2712
2713 default:
2714 ASMJIT_ASSERT(0);
2715 }
2716
2717 switch (r.size)
2718 {
2719 case 4:
2720 *reinterpret_cast<int32_t*>(dst + r.offset) = static_cast<int32_t>(val);
2721 break;
2722
2723 case 8:
2724 *reinterpret_cast<int64_t*>(dst + r.offset) = static_cast<int64_t>(val);
2725 break;
2726
2727 default:
2728 ASMJIT_ASSERT(0);
2729 }
2730
2731 #if defined(ASMJIT_X64)
2732 if (useTrampoline)
2733 {
2734 if (getLogger())
2735 {
2736 getLogger()->logFormat("; Trampoline from %p -> %p\n", (int8_t*)addressBase + r.offset, r.address);
2737 }
2738
2739 X64TrampolineWriter::writeTrampoline(tramp, (uint64_t)r.address);
2740 tramp += X64TrampolineWriter::kSizeTotal;
2741 }
2742 #endif // ASMJIT_X64
2743 }
2744
2745 #if defined(ASMJIT_X64)
2746 return (size_t)(tramp - dst);
2747 #else
2748 return (size_t)(coff);
2749 #endif // ASMJIT_X64
2750 }
2751
2752 // ============================================================================
2753 // [AsmJit::Assembler - EmbedLabel]
2754 // ============================================================================
2755
embedLabel(const Label & label)2756 void X86Assembler::embedLabel(const Label& label)
2757 {
2758 ASMJIT_ASSERT(label.getId() != kInvalidValue);
2759 if (!canEmit()) return;
2760
2761 LabelData& l_data = _labels[label.getId() & kOperandIdValueMask];
2762 RelocData r_data;
2763
2764 if (_logger)
2765 {
2766 _logger->logFormat(sizeof(sysint_t) == 4 ? ".dd L.%u\n" : ".dq L.%u\n", (uint32_t)label.getId() & kOperandIdValueMask);
2767 }
2768
2769 r_data.type = kRelocRelToAbs;
2770 r_data.size = sizeof(sysint_t);
2771 r_data.offset = getOffset();
2772 r_data.destination = 0;
2773
2774 if (l_data.offset != -1)
2775 {
2776 // Bound label.
2777 r_data.destination = l_data.offset;
2778 }
2779 else
2780 {
2781 // Non-bound label. Need to chain.
2782 LabelLink* link = _newLabelLink();
2783
2784 link->prev = (LabelLink*)l_data.links;
2785 link->offset = getOffset();
2786 link->displacement = 0;
2787 link->relocId = _relocData.getLength();
2788
2789 l_data.links = link;
2790 }
2791
2792 _relocData.append(r_data);
2793
2794 // Emit dummy intptr_t (4 or 8 bytes that depends on address size).
2795 _emitIntPtrT(0);
2796 }
2797
2798 // ============================================================================
2799 // [AsmJit::Assembler - Align]
2800 // ============================================================================
2801
align(uint32_t m)2802 void X86Assembler::align(uint32_t m)
2803 {
2804 if (!canEmit())
2805 return;
2806
2807 if (_logger)
2808 _logger->logFormat("%s.align %u\n", _logger->getInstructionPrefix(), (uint)m);
2809
2810 if (!m) return;
2811
2812 if (m > 64)
2813 {
2814 ASMJIT_ASSERT(0);
2815 return;
2816 }
2817
2818 sysint_t i = m - (getOffset() % m);
2819 if (i == m) return;
2820
2821 if (_properties & (1 << kX86PropertyOptimizedAlign))
2822 {
2823 const X86CpuInfo* ci = X86CpuInfo::getGlobal();
2824
2825 // NOPs optimized for Intel:
2826 // Intel 64 and IA-32 Architectures Software Developer's Manual
2827 // - Volume 2B
2828 // - Instruction Set Reference N-Z
2829 // - NOP
2830
2831 // NOPs optimized for AMD:
2832 // Software Optimization Guide for AMD Family 10h Processors (Quad-Core)
2833 // - 4.13 - Code Padding with Operand-Size Override and Multibyte NOP
2834
2835 // Intel and AMD.
2836 static const uint8_t nop1[] = { 0x90 };
2837 static const uint8_t nop2[] = { 0x66, 0x90 };
2838 static const uint8_t nop3[] = { 0x0F, 0x1F, 0x00 };
2839 static const uint8_t nop4[] = { 0x0F, 0x1F, 0x40, 0x00 };
2840 static const uint8_t nop5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 };
2841 static const uint8_t nop6[] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 };
2842 static const uint8_t nop7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
2843 static const uint8_t nop8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
2844 static const uint8_t nop9[] = { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
2845
2846 // AMD.
2847 static const uint8_t nop10[] = { 0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
2848 static const uint8_t nop11[] = { 0x66, 0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
2849
2850 const uint8_t* p;
2851 sysint_t n;
2852
2853 if (ci->getVendorId() == kCpuIntel && ((ci->getFamily() & 0x0F) == 6 || (ci->getFamily() & 0x0F) == 15))
2854 {
2855 do {
2856 switch (i)
2857 {
2858 case 1: p = nop1; n = 1; break;
2859 case 2: p = nop2; n = 2; break;
2860 case 3: p = nop3; n = 3; break;
2861 case 4: p = nop4; n = 4; break;
2862 case 5: p = nop5; n = 5; break;
2863 case 6: p = nop6; n = 6; break;
2864 case 7: p = nop7; n = 7; break;
2865 case 8: p = nop8; n = 8; break;
2866 default: p = nop9; n = 9; break;
2867 }
2868
2869 i -= n;
2870 do { _emitByte(*p++); } while(--n);
2871 } while (i);
2872
2873 return;
2874 }
2875
2876 if (ci->getVendorId() == kCpuAmd && ci->getFamily() >= 0x0F)
2877 {
2878 do {
2879 switch (i)
2880 {
2881 case 1: p = nop1 ; n = 1; break;
2882 case 2: p = nop2 ; n = 2; break;
2883 case 3: p = nop3 ; n = 3; break;
2884 case 4: p = nop4 ; n = 4; break;
2885 case 5: p = nop5 ; n = 5; break;
2886 case 6: p = nop6 ; n = 6; break;
2887 case 7: p = nop7 ; n = 7; break;
2888 case 8: p = nop8 ; n = 8; break;
2889 case 9: p = nop9 ; n = 9; break;
2890 case 10: p = nop10; n = 10; break;
2891 default: p = nop11; n = 11; break;
2892 }
2893
2894 i -= n;
2895 do { _emitByte(*p++); } while(--n);
2896 } while (i);
2897
2898 return;
2899 }
2900 #if defined(ASMJIT_X86)
2901 // Legacy NOPs, 0x90 with 0x66 prefix.
2902 do {
2903 switch (i)
2904 {
2905 default: _emitByte(0x66); i--;
2906 case 3: _emitByte(0x66); i--;
2907 case 2: _emitByte(0x66); i--;
2908 case 1: _emitByte(0x90); i--;
2909 }
2910 } while(i);
2911 #endif
2912 }
2913
2914 // Legacy NOPs, only 0x90. In 64-bit mode, we can't use 0x66 prefix.
2915 do {
2916 _emitByte(0x90);
2917 } while(--i);
2918 }
2919
2920 // ============================================================================
2921 // [AsmJit::Assembler - Label]
2922 // ============================================================================
2923
newLabel()2924 Label X86Assembler::newLabel()
2925 {
2926 Label label;
2927 label._base.id = (uint32_t)_labels.getLength() | kOperandIdTypeLabel;
2928
2929 LabelData l_data;
2930 l_data.offset = -1;
2931 l_data.links = NULL;
2932 _labels.append(l_data);
2933
2934 return label;
2935 }
2936
registerLabels(size_t count)2937 void X86Assembler::registerLabels(size_t count)
2938 {
2939 // Duplicated newLabel() code, but we are not creating Label instances.
2940 LabelData l_data;
2941 l_data.offset = -1;
2942 l_data.links = NULL;
2943
2944 for (size_t i = 0; i < count; i++)
2945 _labels.append(l_data);
2946 }
2947
bind(const Label & label)2948 void X86Assembler::bind(const Label& label)
2949 {
2950 // Only labels created by newLabel() can be used by Assembler.
2951 ASMJIT_ASSERT(label.getId() != kInvalidValue);
2952 // Never go out of bounds.
2953 ASMJIT_ASSERT((label.getId() & kOperandIdValueMask) < _labels.getLength());
2954
2955 // Get label data based on label id.
2956 LabelData& l_data = _labels[label.getId() & kOperandIdValueMask];
2957
2958 // Label can be bound only once.
2959 ASMJIT_ASSERT(l_data.offset == -1);
2960
2961 // Log.
2962 if (_logger) _logger->logFormat("L.%u:\n", (uint32_t)label.getId() & kOperandIdValueMask);
2963
2964 sysint_t pos = getOffset();
2965
2966 LabelLink* link = l_data.links;
2967 LabelLink* prev = NULL;
2968
2969 while (link)
2970 {
2971 sysint_t offset = link->offset;
2972
2973 if (link->relocId != -1)
2974 {
2975 // If linked label points to RelocData then instead of writing relative
2976 // displacement to assembler stream, we will write it to RelocData.
2977 _relocData[link->relocId].destination += pos;
2978 }
2979 else
2980 {
2981 // Not using relocId, this means that we overwriting real displacement
2982 // in assembler stream.
2983 int32_t patchedValue = (int32_t)(pos - offset + link->displacement);
2984 uint32_t size = getByteAt(offset);
2985
2986 // Only these size specifiers are allowed.
2987 ASMJIT_ASSERT(size == 1 || size == 4);
2988
2989 if (size == 4)
2990 {
2991 setInt32At(offset, patchedValue);
2992 }
2993 else // if (size == 1)
2994 {
2995 if (IntUtil::isInt8(patchedValue))
2996 {
2997 setByteAt(offset, (uint8_t)(int8_t)patchedValue);
2998 }
2999 else
3000 {
3001 // Fatal error.
3002 setError(kErrorIllegalShortJump);
3003 }
3004 }
3005 }
3006
3007 prev = link->prev;
3008 link = prev;
3009 }
3010
3011 // Chain unused links.
3012 link = l_data.links;
3013 if (link)
3014 {
3015 if (prev == NULL) prev = link;
3016
3017 prev->prev = _unusedLinks;
3018 _unusedLinks = link;
3019 }
3020
3021 // Unlink label if it was linked.
3022 l_data.offset = pos;
3023 l_data.links = NULL;
3024 }
3025
3026 // ============================================================================
3027 // [AsmJit::Assembler - Make]
3028 // ============================================================================
3029
make()3030 void* X86Assembler::make()
3031 {
3032 // Do nothing on error state or when no instruction was emitted.
3033 if (_error || getCodeSize() == 0)
3034 return NULL;
3035
3036 void* p;
3037 _error = _context->generate(&p, this);
3038 return p;
3039 }
3040
3041 } // AsmJit namespace
3042
3043 // [Api-End]
3044 #include "../core/apiend.h"
3045