void reclaimTranslation(TransLoc loc) { BlockingLeaseHolder writer(Translator::WriteLease()); ITRACE(1, "Reclaiming translation M[{}, {}] C[{}, {}] F[{}, {}]\n", loc.mainStart(), loc.mainEnd(), loc.coldStart(), loc.coldEnd(), loc.frozenStart(), loc.frozenEnd()); Trace::Indent _i; auto& cache = mcg->code(); cache.blockFor(loc.mainStart()).free(loc.mainStart(), loc.mainSize()); cache.blockFor(loc.coldStart()).free(loc.coldStart(), loc.coldSize()); if (loc.coldStart() != loc.frozenStart()) { cache.blockFor(loc.frozenStart()).free(loc.frozenStart(), loc.frozenSize()); } for (auto it = s_smashedBranches.begin(); it != s_smashedBranches.end();) { auto br = it++; if (loc.contains(br->first)) { ITRACE(1, "Erasing smashed branch @ {} from SrcRec addr={}\n", br->first, (void*)br->second); br->second->removeIncomingBranch(br->first); s_smashedBranches.erase(br); } } // Erase meta-data about these regions of the TC { ITRACE(1, "Clearing translation meta-data\n"); Trace::Indent _i; clearTCMaps(loc.mainStart(), loc.mainEnd()); clearTCMaps(loc.coldCodeStart(), loc.coldEnd()); clearTCMaps(loc.frozenCodeStart(), loc.frozenEnd()); } if (debug) { // Ensure no one calls into the function ITRACE(1, "Overwriting function\n"); auto clearBlock = [] (CodeBlock& cb) { X64Assembler a {cb}; while (cb.available() >= 2) a.ud2(); if (cb.available() > 0) a.int3(); always_assert(!cb.available()); }; CodeBlock main, cold, frozen; main.init(loc.mainStart(), loc.mainSize(), "Dead Main"); cold.init(loc.coldStart(), loc.coldSize(), "Dead Cold"); frozen.init(loc.frozenStart(), loc.frozenSize(), "Dead Frozen"); clearBlock(main); clearBlock(cold); clearBlock(frozen); } }
void smashJcc(TCA inst, TCA target, ConditionCode cc) { always_assert(is_aligned(inst, Alignment::SmashJcc)); if (cc == CC_None) { X64Assembler::patchJcc(inst, target); } else { auto& cb = mcg->code().blockFor(inst); CodeCursor cursor { cb, inst }; X64Assembler a { cb }; a.jcc(cc, target); } }
void smashJmp(TCA inst, TCA target) { always_assert(is_aligned(inst, Alignment::SmashJmp)); auto& cb = mcg->code().blockFor(inst); CodeCursor cursor { cb, inst }; X64Assembler a { cb }; if (target > inst && target - inst <= smashableJmpLen()) { a.emitNop(target - inst); } else { a.jmp(target); } }
StoreImmPatcher::StoreImmPatcher(X64Assembler& as, uint64_t initial, register_name_t reg, int32_t offset, register_name_t base) { is32 = deltaFits(initial, sz::dword); if (is32) { as.store_imm64_disp_reg64(initial, offset, base); } else { as.mov_imm64_reg(initial, reg); as.store_reg64_disp_reg64(reg, offset, base); } m_addr = as.code.frontier - (is32 ? 4 : 8); ASSERT((is32 ? (uint64_t)*(int32_t*)m_addr : *(uint64_t*)m_addr) == initial); }
StoreImmPatcher::StoreImmPatcher(X64Assembler& as, uint64_t initial, RegNumber reg, int32_t offset, RegNumber base) { m_is32 = deltaFits(initial, sz::dword); if (m_is32) { as.store_imm64_disp_reg64(initial, offset, base); } else { as.mov_imm64_reg(initial, reg); as.store_reg64_disp_reg64(reg, offset, base); } m_addr = as.frontier() - (m_is32 ? 4 : 8); assert((m_is32 ? (uint64_t)*(int32_t*)m_addr : *(uint64_t*)m_addr) == initial); }
void operator()() { auto codeLock = mcg->lockCode(); for (auto& e : entries) { CodeBlock cb; cb.init(e.first, e.second - e.first, "relocated"); X64Assembler a { cb }; while (a.canEmit(2)) { a.ud2(); } if (a.canEmit(1)) a.int3(); } okToRelocate = true; }
std::pair<TCA,TCA> emitSmashableJccAndJmp(CodeBlock& cb, TCA target, ConditionCode cc) { assertx(cc != CC_None); align(cb, Alignment::SmashJccAndJmp, AlignContext::Live); X64Assembler a { cb }; auto const jcc = cb.frontier(); a.jcc(cc, target); auto const jmp = cb.frontier(); a.jmp(target); return std::make_pair(jcc, jmp); }
/* * Satisfy an alignment constraint. Bridge the gap with int3's. */ void moveToAlign(CodeBlock& cb, const size_t align /* =kJmpTargetAlign */) { X64Assembler a { cb }; assertx(folly::isPowTwo(align)); size_t leftInBlock = align - ((align - 1) & uintptr_t(cb.frontier())); if (leftInBlock == align) return; if (leftInBlock > 2) { a.ud2(); leftInBlock -= 2; } if (leftInBlock > 0) { a.emitInt3s(leftInBlock); } }
void smashCall(TCA inst, TCA target) { always_assert(is_aligned(inst, Alignment::SmashCall)); /* * TODO(#7889486): We'd like this just to be: * * X64Assembler::patchCall(inst, target); * * but presently this causes asserts to fire in MCGenerator because of a bug * with PGO and relocation. */ auto& cb = mcg->code().blockFor(inst); CodeCursor cursor { cb, inst }; X64Assembler a { cb }; a.call(target); }
StoreImmPatcher::StoreImmPatcher(CodeBlock& cb, uint64_t initial, RegNumber reg, int32_t offset, RegNumber base) { X64Assembler as { cb }; m_is32 = deltaFits(initial, sz::dword); if (m_is32) { as.store_imm64_disp_reg64(initial, offset, base); m_addr = cb.frontier() - 4; } else { as.mov_imm64_reg(initial, reg); m_addr = cb.frontier() - 8; as.store_reg64_disp_reg64(reg, offset, base); } assert((m_is32 ? (uint64_t)*(int32_t*)m_addr : *(uint64_t*)m_addr) == initial); }
void operator()() { LeaseHolder writer(Translator::WriteLease()); if (!writer) { Treadmill::enqueue(std::move(*this)); return; } for (auto& e : entries) { CodeBlock cb; cb.init(e.first, e.second - e.first, "relocated"); X64Assembler a { cb }; while (a.canEmit(2)) { a.ud2(); } if (a.canEmit(1)) a.int3(); } okToRelocate = true; }
/* * Satisfy an alignment constraint. Bridge the gap with int3's. */ void moveToAlign(CodeBlock& cb, const size_t align /* =kJmpTargetAlign */) { // TODO(2967396) implement properly, move function if (arch() == Arch::ARM) return; using namespace HPHP::Util; X64Assembler a { cb }; assert(isPowerOfTwo(align)); size_t leftInBlock = align - ((align - 1) & uintptr_t(cb.frontier())); if (leftInBlock == align) return; if (leftInBlock > 2) { a.ud2(); leftInBlock -= 2; } if (leftInBlock > 0) { a.emitInt3s(leftInBlock); } }
/* * Satisfy an alignment constraint. Bridge the gap with int3's. */ void moveToAlign(CodeBlock& cb, const size_t align /* =kJmpTargetAlign */) { switch (arch()) { case Arch::X64: { X64Assembler a { cb }; assert(folly::isPowTwo(align)); size_t leftInBlock = align - ((align - 1) & uintptr_t(cb.frontier())); if (leftInBlock == align) return; if (leftInBlock > 2) { a.ud2(); leftInBlock -= 2; } break; } case Arch::ARM: // TODO(2967396) implement properly, move function break; } }
void emitFuncGuard(const Func* func, CodeBlock& cb) { using namespace reg; X64Assembler a { cb }; assertx(x64::abi(CodeKind::CrossTrace).gpUnreserved.contains(rax)); TCA start DEBUG_ONLY = a.frontier(); auto const funcImm = Immed64(func); if (funcImm.fits(sz::dword)) { emitSmashableCmpq(a.code(), funcImm.l(), rVmFp, safe_cast<int8_t>(AROFF(m_func))); } else { // Although func doesn't fit in a signed 32-bit immediate, it may still fit // in an unsigned one. Rather than deal with yet another case (which only // happens when we disable jemalloc), just emit a smashable mov followed by // a register cmp. emitSmashableMovq(a.code(), uint64_t(func), rax); a. cmpq (rax, rVmFp[AROFF(m_func)]); } a. jnz (mcg->tx().uniqueStubs.funcPrologueRedispatch); assertx(funcPrologueToGuard(a.frontier(), func) == start); assertx(funcPrologueHasGuard(a.frontier(), func)); }
void emitFuncGuard(const Func* func, CodeBlock& cb, CGMeta& fixups) { using namespace reg; X64Assembler a { cb }; assertx(x64::abi(CodeKind::CrossTrace).gpUnreserved.contains(rax)); auto const funcImm = Immed64(func); if (funcImm.fits(sz::dword)) { emitSmashableCmpq(a.code(), fixups, funcImm.l(), rvmfp(), safe_cast<int8_t>(AROFF(m_func))); } else { // Although func doesn't fit in a signed 32-bit immediate, it may still fit // in an unsigned one. Rather than deal with yet another case (which only // happens when we disable jemalloc), just emit a smashable mov followed by // a register cmp. emitSmashableMovq(a.code(), fixups, uint64_t(func), rax); a. cmpq (rax, rvmfp()[AROFF(m_func)]); } a. jnz (tc::ustubs().funcPrologueRedispatch); DEBUG_ONLY auto guard = funcGuardFromPrologue(a.frontier(), func); assertx(funcGuardMatches(guard, func)); }
void emitFuncGuard(const Func* func, CodeBlock& cb) { using namespace reg; X64Assembler a { cb }; assertx(cross_trace_abi.gpUnreserved.contains(rax)); auto const funcImm = Immed64(func); int nbytes, offset; if (!funcImm.fits(sz::dword)) { nbytes = kFuncGuardSmash; offset = kFuncGuardImm; } else { nbytes = kFuncGuardShortSmash; offset = kFuncGuardShortImm; } mcg->backEnd().prepareForSmash(a.code(), nbytes, offset); TCA start DEBUG_ONLY = a.frontier(); if (!funcImm.fits(sz::dword)) { // Although func doesnt fit in a signed 32-bit immediate, it may still fit // in an unsigned one. Rather than deal with yet another case (which only // happens when we disable jemalloc), just force it to be an 8-byte // immediate, and patch it up afterwards. a. movq (0xdeadbeeffeedface, rax); auto immptr = reinterpret_cast<uintptr_t*>(a.frontier()) - 1; assertx(*immptr == 0xdeadbeeffeedface); *immptr = uintptr_t(func); a. cmpq (rax, rVmFp[AROFF(m_func)]); } else { a. cmpq (funcImm.l(), rVmFp[AROFF(m_func)]); } a. jnz (mcg->tx().uniqueStubs.funcPrologueRedispatch); assertx(funcPrologueToGuard(a.frontier(), func) == start); assertx(funcPrologueHasGuard(a.frontier(), func)); }
MovImmPatcher::MovImmPatcher(X64Assembler& as, uint64_t initial, register_name_t reg) { is32 = deltaFits(initial, sz::dword); as.mov_imm64_reg(initial, reg); m_addr = as.code.frontier - (is32 ? 4 : 8); }
TCA emitCallToExit(CodeBlock& cb) { X64Assembler a { cb }; // Emit a byte of padding. This is a kind of hacky way to avoid // hitting an assert in recordGdbStub when we call it with stub - 1 // as the start address. a.emitNop(1); auto const start = a.frontier(); if (RuntimeOption::EvalHHIRGenerateAsserts) { Label ok; a.emitImmReg(uintptr_t(enterTCExit), reg::rax); a.cmpq(reg::rax, *rsp()); a.je8 (ok); a.ud2(); asm_label(a, ok); } // Emulate a ret to enterTCExit without actually doing one to avoid // unbalancing the return stack buffer. The call from enterTCHelper() that // got us into the TC was popped off the RSB by the ret that got us to this // stub. a.addq(8, rsp()); if (a.jmpDeltaFits(TCA(enterTCExit))) { a.jmp(TCA(enterTCExit)); } else { // can't do a near jmp and a rip-relative load/jmp would require threading // through extra state to allocate a literal. use an indirect jump through // a register a.emitImmReg(uintptr_t(enterTCExit), reg::rax); a.jmp(reg::rax); } // On a backtrace, gdb tries to locate the calling frame at address // returnRIP-1. However, for the first VM frame, there is no code at // returnRIP-1, since the AR was set up manually. For this frame, // record the tracelet address as starting from this callToExit-1, // so gdb does not barf. return start; }
void PhysRegSaverParity::emitPops(X64Assembler& as, RegSet regs) { emitPops(Vauto(as.code()).main(), regs); }
PhysRegSaverParity::PhysRegSaverParity(int parity, X64Assembler& as, RegSet regs) : PhysRegSaverParity{parity, Vauto(as.code()).main(), regs} { m_v = nullptr; m_as = &as; }
void testEmitMethods() { X64Assembler e; e.init(10 << 20); using namespace HPHP::VM::Transl::reg; int n = sizeof(instr_list) / sizeof(instr_list[0]); for (int i = 0; i < n; ++i) { X64Instr op = instr_list[i]; printf("%s:\n", instr_names[i]); if (supported_AM[i] & MASK_none) { printf(" Address mode: none\n"); e.emit(op); } if (supported_AM[i] & MASK_R) { printf(" Address mode: R\n"); e.emitR(op, rax); e.emitR(op, rsi); e.emitR(op, rbp); e.emitR(op, rsp); e.emitR(op, r8); e.emitR(op, r15); e.emitR(op, r13); e.emitR(op, r12); } if (supported_AM[i] & MASK_RR) { printf(" Address mode: RR\n"); e.emitRR(op, rsi, rax); e.emitRR(op, rax, rdi); e.emitRR(op, rsi, rdi); e.emitRR(op, rbp, rsp); e.emitRR(op, rsp, rbp); e.emitRR(op, rsi, r8); e.emitRR(op, rax, r15); e.emitRR(op, rsi, r15); e.emitRR(op, rbp, r12); e.emitRR(op, rsp, r13); e.emitRR(op, r14, rax); e.emitRR(op, r8, rdi); e.emitRR(op, r14, rdi); e.emitRR(op, r13, rsp); e.emitRR(op, r12, rbp); e.emitRR(op, r14, r8); e.emitRR(op, r8, r15); e.emitRR(op, r14, r15); e.emitRR(op, r13, r12); e.emitRR(op, r12, r13); e.emitRR(op, rax, rax); e.emitRR(op, rax, r8); e.emitRR(op, r8, rax); e.emitRR(op, r8, r8); } if (supported_AM[i] & MASK_I) { printf(" Address mode: I\n"); e.emitI(op, -128); e.emitI(op, 127); e.emitI(op, 0xF1); e.emitI(op, 1); } if (supported_AM[i] & MASK_IR) { printf(" Address mode: IR\n"); e.emitIR(op, rbx, 1); e.emitIR(op, rax, -128); e.emitIR(op, rsi, -128); e.emitIR(op, rbp, 127); e.emitIR(op, rsp, 0xF1); e.emitIR(op, rsp, 1); e.emitIR(op, r11, 1); e.emitIR(op, r8, -128); e.emitIR(op, r14, -128); e.emitIR(op, r13, 127); e.emitIR(op, r12, 0xF1); e.emitIR(op, r12, 1); if (i == 13 /*instr_mov*/) { e.emitIR(op, rax, (ssize_t)0x1234123412341234); e.emitIR(op, r8, (ssize_t)0x1234123412341234); } } if (supported_AM[i] & MASK_IRR) { printf(" Address mode: IRR\n"); e.emitIRR(op, rsi, rax, -128); e.emitIRR(op, rax, rdi, -128); e.emitIRR(op, rbp, rsp, 127); e.emitIRR(op, rsp, rbp, 0xF1); e.emitIRR(op, rsp, rbp, 1); e.emitIRR(op, r14, rax, -128); e.emitIRR(op, r8, rdi, -128); e.emitIRR(op, r13, rsp, 127); e.emitIRR(op, r12, rbp, 0xF1); e.emitIRR(op, r12, rbp, 1); e.emitIRR(op, rsi, r8, -128); e.emitIRR(op, rax, r15, -128); e.emitIRR(op, rbp, r12, 127); e.emitIRR(op, rsp, r13, 0xF1); e.emitIRR(op, rsp, r13, 1); e.emitIRR(op, r14, r8, -128); e.emitIRR(op, r8, r15, -128); e.emitIRR(op, r13, r12, 127); e.emitIRR(op, r12, r13, 0xF1); e.emitIRR(op, r12, r13, 1); e.emitIRR(op, rax, rax, 1); e.emitIRR(op, rax, r8, 1); e.emitIRR(op, r8, rax, 1); e.emitIRR(op, r8, r8, 1); } if (supported_AM[i] & MASK_M) { printf(" Address mode: M\n"); e.emitM(op, rsi, rdi, sz::word, -128); e.emitM(op, rbp, noreg, sz::dword, 127); e.emitM(op, noreg, rbp, sz::byte, 127); e.emitM(op, rsp, rbp, sz::qword, 0xF1); e.emitM(op, rsi, r15, sz::word, -128); e.emitM(op, rbp, noreg, sz::dword, 127); e.emitM(op, noreg, r13, sz::byte, 127); e.emitM(op, rsp, r13, sz::qword, 0xF1); e.emitM(op, r14, rdi, sz::word, -128); e.emitM(op, r13, noreg, sz::dword, 127); e.emitM(op, noreg, rbp, sz::byte, 127); e.emitM(op, r12, rbp, sz::qword, 0xF1); e.emitM(op, r14, r15, sz::word, -128); e.emitM(op, r13, noreg, sz::dword, 127); e.emitM(op, noreg, r13, sz::byte, 127); e.emitM(op, r12, r13, sz::qword, 0xF1); // Providing only an immediate with no base register and no index // register produces the RIP relative form e.emitM(op, noreg, noreg, sz::byte, 0xF1F1); } if (supported_AM[i] & MASK_RM) { printf(" Address mode: RM\n"); e.emitRM(op, rsi, rdi, sz::word, -128, rax); e.emitRM(op, rbp, noreg, sz::dword, 127, rcx); e.emitRM(op, noreg, rbp, sz::byte, 127, rcx); e.emitRM(op, rsp, rbp, sz::qword, 0xF1, rbp); e.emitRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp); e.emitRM(op, rsi, rdi, sz::word, -128, r8); e.emitRM(op, rbp, noreg, sz::dword, 127, r9); e.emitRM(op, noreg, rbp, sz::byte, 127, r9); e.emitRM(op, rsp, rbp, sz::qword, 0xF1, r13); e.emitRM(op, noreg, noreg, sz::byte, 0xF1F1, r12); e.emitRM(op, r14, rdi, sz::word, -128, rax); e.emitRM(op, r13, noreg, sz::dword, 127, rcx); e.emitRM(op, noreg, rbp, sz::byte, 127, rcx); e.emitRM(op, r12, rbp, sz::qword, 0xF1, rbp); e.emitRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp); e.emitRM(op, r14, rdi, sz::word, -128, r8); e.emitRM(op, r13, noreg, sz::dword, 127, r9); e.emitRM(op, noreg, rbp, sz::byte, 127, r9); e.emitRM(op, r12, rbp, sz::qword, 0xF1, r13); e.emitRM(op, noreg, noreg, sz::byte, 0xF1F1, r12); } if (supported_AM[i] & MASK_MR) { printf(" Address mode: MR\n"); e.emitMR(op, rsi, rdi, sz::word, -128, rax); e.emitMR(op, rbp, noreg, sz::dword, 127, rcx); e.emitMR(op, noreg, rbp, sz::byte, 127, rcx); e.emitMR(op, rsp, rbp, sz::qword, 0xF1, rbp); e.emitMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp); e.emitMR(op, rsi, rdi, sz::word, -128, r8); e.emitMR(op, rbp, noreg, sz::dword, 127, r9); e.emitMR(op, noreg, rbp, sz::byte, 127, r9); e.emitMR(op, rsp, rbp, sz::qword, 0xF1, r13); e.emitMR(op, noreg, noreg, sz::byte, 0xF1F1, r12); e.emitMR(op, r14, rdi, sz::word, -128, rax); e.emitMR(op, r13, noreg, sz::dword, 127, rcx); e.emitMR(op, noreg, rbp, sz::byte, 127, rcx); e.emitMR(op, r12, rbp, sz::qword, 0xF1, rbp); e.emitMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp); e.emitMR(op, r14, rdi, sz::word, -128, r8); e.emitMR(op, r13, noreg, sz::dword, 127, r9); e.emitMR(op, noreg, rbp, sz::byte, 127, r9); e.emitMR(op, r12, rbp, sz::qword, 0xF1, r13); e.emitMR(op, noreg, noreg, sz::byte, 0xF1F1, r12); } if (supported_AM[i] & MASK_IRM) { printf(" Address mode: IRM\n"); e.emitIRM(op, rsi, rdi, sz::word, -128, rax, 0xF1F1F1F1); e.emitIRM(op, rbp, noreg, sz::dword, 127, rcx, 0xF1); e.emitIRM(op, noreg, rbp, sz::byte, 127, rcx, 0xF1); e.emitIRM(op, rsp, rbp, sz::qword, 0xF1, rbp, -128); e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 127); e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 1); e.emitIRM(op, rsi, rdi, sz::word, -128, r8, 0xF1F1F1F1); e.emitIRM(op, rbp, noreg, sz::dword, 127, r9, 0xF1); e.emitIRM(op, noreg, rbp, sz::byte, 127, r9, 0xF1); e.emitIRM(op, rsp, rbp, sz::qword, 0xF1, r13, -128); e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, r12, 127); e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, r12, 1); e.emitIRM(op, r14, rdi, sz::word, -128, rax, 0xF1F1F1F1); e.emitIRM(op, r13, noreg, sz::dword, 127, rcx, 0xF1); e.emitIRM(op, noreg, rbp, sz::byte, 127, rcx, 0xF1); e.emitIRM(op, r12, rbp, sz::qword, 0xF1, rbp, -128); e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 127); e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 1); e.emitIRM(op, r14, rdi, sz::word, -128, r8, 0xF1F1F1F1); e.emitIRM(op, r13, noreg, sz::dword, 127, r9, 0xF1); e.emitIRM(op, noreg, rbp, sz::byte, 127, r9, 0xF1); e.emitIRM(op, r12, rbp, sz::qword, 0xF1, r13, -128); e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, r12, 127); e.emitIRM(op, noreg, noreg, sz::byte, 0xF1F1, r12, 1); } if (supported_AM[i] & MASK_IMR) { printf(" Address mode: IMR\n"); e.emitIMR(op, rsi, rdi, sz::word, -128, rax, 0xF1F1F1F1); e.emitIMR(op, rbp, noreg, sz::dword, 127, rax, 0xF1); e.emitIMR(op, noreg, rbp, sz::byte, 127, rcx, 0xF1); e.emitIMR(op, rsp, rbp, sz::qword, 0xF1, rbp, -128); e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 127); e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 1); e.emitIMR(op, rsi, rdi, sz::word, -128, r8, 0xF1F1F1F1); e.emitIMR(op, rbp, noreg, sz::dword, 127, r8, 0xF1); e.emitIMR(op, noreg, rbp, sz::byte, 127, r9, 0xF1); e.emitIMR(op, rsp, rbp, sz::qword, 0xF1, r13, -128); e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, r12, 127); e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, r12, 1); e.emitIMR(op, r14, rdi, sz::word, -128, rax, 0xF1F1F1F1); e.emitIMR(op, r13, noreg, sz::dword, 127, rax, 0xF1); e.emitIMR(op, noreg, rbp, sz::byte, 127, rcx, 0xF1); e.emitIMR(op, r12, rbp, sz::qword, 0xF1, rbp, -128); e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 127); e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, rsp, 1); e.emitIMR(op, r14, rdi, sz::word, -128, r8, 0xF1F1F1F1); e.emitIMR(op, r13, noreg, sz::dword, 127, r8, 0xF1); e.emitIMR(op, noreg, rbp, sz::byte, 127, r9, 0xF1); e.emitIMR(op, r12, rbp, sz::qword, 0xF1, r13, -128); e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, r12, 127); e.emitIMR(op, noreg, noreg, sz::byte, 0xF1F1, r12, 1); } if (supported_AM[i] & MASK_IM) { printf(" Address mode: IM\n"); e.emitIM(op, rsi, rdi, sz::word, -128, 0xF1F1F1F1); e.emitIM(op, rbp, noreg, sz::dword, 127, 0xF1); e.emitIM(op, noreg, rbp, sz::byte, 127, 0xF1); e.emitIM(op, rsp, rbp, sz::qword, 0xF1, -128); e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 127); e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 1); e.emitIM(op, r14, rdi, sz::word, -128, 0xF1F1F1F1); e.emitIM(op, r13, noreg, sz::dword, 127, 0xF1); e.emitIM(op, noreg, rbp, sz::byte, 127, 0xF1); e.emitIM(op, r12, rbp, sz::qword, 0xF1, -128); e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 127); e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 1); e.emitIM(op, rsi, r15, sz::word, -128, 0xF1F1F1F1); e.emitIM(op, rbp, noreg, sz::dword, 127, 0xF1); e.emitIM(op, noreg, r13, sz::byte, 127, 0xF1); e.emitIM(op, rsp, r13, sz::qword, 0xF1, -128); e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 127); e.emitIM(op, noreg, noreg, sz::byte, 0xF1F1, 1); if (i == 13 /*instr_mov*/) { e.emitIM(op, rsi, rdi, sz::word, -128, 0x1234123412341234); e.emitIM(op, r14, rdi, sz::word, -128, 0x1234123412341234); e.emitIM(op, rsi, r15, sz::word, -128, 0x1234123412341234); } } if (supported_AM[i] & MASK_CI) { printf(" Address mode: CI\n"); e.emitCI(op, CC_NE, 0xF1F1F1F1); e.emitCI(op, CC_G, 0xF1); e.emitCI(op, CC_S, -128); e.emitCI(op, CC_O, 127); e.emitCI(op, CC_O, 1); } if (supported_AM[i] & MASK_CMR) { printf(" Address mode: CMR\n"); e.emitCMR(op, CC_NE, rsi, rdi, sz::word, -128, rax); e.emitCMR(op, CC_G, rbp, noreg, sz::dword, 127, rcx); e.emitCMR(op, CC_G, noreg, rbp, sz::byte, 127, rcx); e.emitCMR(op, CC_S, rsp, rbp, sz::qword, 0xF1, rbp); e.emitCMR(op, CC_O, noreg, noreg, sz::byte, 0xF1F1, rsp); e.emitCMR(op, CC_NE, rsi, rdi, sz::word, -128, r8); e.emitCMR(op, CC_G, rbp, noreg, sz::dword, 127, r9); e.emitCMR(op, CC_G, noreg, rbp, sz::byte, 127, r9); e.emitCMR(op, CC_S, rsp, rbp, sz::qword, 0xF1, r13); e.emitCMR(op, CC_O, noreg, noreg, sz::byte, 0xF1F1, r12); e.emitCMR(op, CC_NE, r14, rdi, sz::word, -128, rax); e.emitCMR(op, CC_G, r13, noreg, sz::dword, 127, rcx); e.emitCMR(op, CC_G, noreg, rbp, sz::byte, 127, rcx); e.emitCMR(op, CC_S, r12, rbp, sz::qword, 0xF1, rbp); e.emitCMR(op, CC_O, noreg, noreg, sz::byte, 0xF1F1, rsp); e.emitCMR(op, CC_NE, r14, rdi, sz::word, -128, r8); e.emitCMR(op, CC_G, r12, noreg, sz::dword, 127, r9); e.emitCMR(op, CC_G, noreg, rbp, sz::byte, 127, r9); e.emitCMR(op, CC_S, r12, rbp, sz::qword, 0xF1, r13); e.emitCMR(op, CC_O, noreg, noreg, sz::byte, 0xF1F1, r12); } if (supported_AM[i] & MASK_CR) { printf(" Address mode: CR\n"); e.emitCR(op, CC_NE, rax); e.emitCR(op, CC_G, rcx); e.emitCR(op, CC_S, rbp); e.emitCR(op, CC_O, rsp); e.emitCR(op, CC_NE, r8); e.emitCR(op, CC_G, r9); e.emitCR(op, CC_S, r13); e.emitCR(op, CC_O, r12); } if (supported_AM[i] & MASK_CM) { printf(" Address mode: CM\n"); e.emitCM(op, CC_NE, rsi, rdi, sz::word, -128); e.emitCM(op, CC_G, rbp, noreg, sz::dword, 127); e.emitCM(op, CC_G, noreg, rbp, sz::byte, 127); e.emitCM(op, CC_S, rsp, rbp, sz::qword, 0xF1); e.emitCM(op, CC_S, rbp, rbp, sz::qword, 0xF1); e.emitCM(op, CC_O, noreg, noreg, sz::byte, 0xF1F1); e.emitCM(op, CC_NE, rsi, r15, sz::word, -128); e.emitCM(op, CC_G, rbp, noreg, sz::dword, 127); e.emitCM(op, CC_G, noreg, r13, sz::byte, 127); e.emitCM(op, CC_S, rsp, r13, sz::qword, 0xF1); e.emitCM(op, CC_O, noreg, noreg, sz::byte, 0xF1F1); e.emitCM(op, CC_NE, r14, rdi, sz::word, -128); e.emitCM(op, CC_G, r13, noreg, sz::dword, 127); e.emitCM(op, CC_G, noreg, rbp, sz::byte, 127); e.emitCM(op, CC_S, r12, rbp, sz::qword, 0xF1); e.emitCM(op, CC_O, noreg, noreg, sz::byte, 0xF1F1); e.emitCM(op, CC_NE, r14, r15, sz::word, -128); e.emitCM(op, CC_G, r13, noreg, sz::dword, 127); e.emitCM(op, CC_G, noreg, r13, sz::byte, 127); e.emitCM(op, CC_S, r12, r13, sz::qword, 0xF1); e.emitCM(op, CC_O, noreg, noreg, sz::byte, 0xF1F1); } if (supported_AM[i] & MASK_CRR) { printf(" Address mode: CRR\n"); e.emitCRR(op, CC_NE, rsi, rax); e.emitCRR(op, CC_G, rax, rdi); e.emitCRR(op, CC_S, rsi, rdi); e.emitCRR(op, CC_O, rbp, rsp); e.emitCRR(op, CC_E, rsp, rbp); e.emitCRR(op, CC_NP, rsi, r8); e.emitCRR(op, CC_P, rax, r15); e.emitCRR(op, CC_L, rsi, r15); e.emitCRR(op, CC_LE, rbp, r12); e.emitCRR(op, CC_BE, rsp, r13); e.emitCRR(op, CC_NO, r14, rax); e.emitCRR(op, CC_NS, r8, rdi); e.emitCRR(op, CC_NE, r14, rdi); e.emitCRR(op, CC_G, r13, rsp); e.emitCRR(op, CC_S, r12, rbp); e.emitCRR(op, CC_O, r14, r8); e.emitCRR(op, CC_E, r8, r15); e.emitCRR(op, CC_NP, r14, r15); e.emitCRR(op, CC_P, r13, r12); e.emitCRR(op, CC_L, r12, r13); e.emitCRR(op, CC_LE, rax, rax); e.emitCRR(op, CC_BE, rax, r8); e.emitCRR(op, CC_NO, r8, rax); e.emitCRR(op, CC_NS, r8, r8); } printf("\n"); } }