diff options
-rw-r--r-- | gen/gen_code.cpp | 4 | ||||
-rw-r--r-- | readme.md | 3 | ||||
-rw-r--r-- | readme.txt | 3 | ||||
-rw-r--r-- | test/make_nm.cpp | 16 | ||||
-rw-r--r-- | test/nm_frame.cpp | 1 | ||||
-rw-r--r-- | test/test_address.bat | 2 | ||||
-rw-r--r-- | xbyak/xbyak.h | 123 | ||||
-rw-r--r-- | xbyak/xbyak_mnemonic.h | 6 |
8 files changed, 108 insertions, 50 deletions
diff --git a/gen/gen_code.cpp b/gen/gen_code.cpp index 734fd83..413e632 100644 --- a/gen/gen_code.cpp +++ b/gen/gen_code.cpp @@ -942,11 +942,11 @@ void put() puts("void bndcl(const BoundsReg& bnd, const Operand& op) { db(0xF3); opR_ModM(op, i32e, bnd.getIdx(), 0x0F, 0x1A, NONE, !op.isMEM()); }"); puts("void bndcu(const BoundsReg& bnd, const Operand& op) { db(0xF2); opR_ModM(op, i32e, bnd.getIdx(), 0x0F, 0x1A, NONE, !op.isMEM()); }"); puts("void bndcn(const BoundsReg& bnd, const Operand& op) { db(0xF2); opR_ModM(op, i32e, bnd.getIdx(), 0x0F, 0x1B, NONE, !op.isMEM()); }"); - puts("void bndldx(const BoundsReg& bnd, const Address& addr) { opModM(addr, bnd, 0x0F, 0x1A); }"); + puts("void bndldx(const BoundsReg& bnd, const Address& addr) { opMIB(addr, bnd, 0x0F, 0x1A); }"); puts("void bndmk(const BoundsReg& bnd, const Address& addr) { db(0xF3); opModM(addr, bnd, 0x0F, 0x1B); }"); puts("void bndmov(const BoundsReg& bnd, const Operand& op) { db(0x66); opModRM(bnd, op, op.isBNDREG(), op.isMEM(), 0x0F, 0x1A); }"); puts("void bndmov(const Address& addr, const BoundsReg& bnd) { db(0x66); opModM(addr, bnd, 0x0F, 0x1B); }"); - puts("void bndstx(const Address& addr, const BoundsReg& bnd) { opModM(addr, bnd, 0x0F, 0x1B); }"); + puts("void bndstx(const Address& addr, const BoundsReg& bnd) { opMIB(addr, bnd, 0x0F, 0x1B); }"); } // misc { @@ -1,5 +1,5 @@ -Xbyak 5.52 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++ +Xbyak 5.53 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++ ============= Abstract @@ -333,6 +333,7 @@ The header files under xbyak/ are independent of cybozulib. History ------------- +* 2017/Aug/22 ver 5.53 fix mpx encoding, add bnd() prefix * 2017/Aug/18 ver 5.52 fix align (thanks to MerryMage) * 2017/Aug/17 ver 5.51 add multi-byte nop and align() uses it(thanks to inolen) * 2017/Aug/08 ver 5.50 add mpx(thanks to magurosan) @@ -1,5 +1,5 @@ - C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.52
+ C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.53
-----------------------------------------------------------------------------
◎概要
@@ -343,6 +343,7 @@ cybozulibは単体テストでのみ利用されていて、xbyak/ディレク� -----------------------------------------------------------------------------
◎履歴
+2017/08/22 ver 5.53 mpxエンコーディングバグ修正, bnd()プレフィクス追加
2017/08/18 ver 5.52 align修正(thanks to MerryMage)
2017/08/17 ver 5.51 multi-byte nop追加 align()はそれを使用する(thanks to inolen)
2017/08/08 ver 5.50 mpx追加(thanks to magurosan)
diff --git a/test/make_nm.cpp b/test/make_nm.cpp index 6eff1e5..72c8247 100644 --- a/test/make_nm.cpp +++ b/test/make_nm.cpp @@ -1363,6 +1363,22 @@ class Test { put("bndmk", BNDREG, MEM); put("bndmov", BNDREG, BNDREG|MEM); put("bndstx", MEM, BNDREG); + put("bndstx", "ptr [eax]", "[eax]", BNDREG); + put("bndstx", "ptr [eax+5]", "[eax+5]", BNDREG); + put("bndstx", "ptr [eax+500]", "[eax+500]", BNDREG); + put("bndstx", "ptr [eax+ecx]", "[eax+ecx]", BNDREG); + put("bndstx", "ptr [ecx+eax]", "[ecx+eax]", BNDREG); + put("bndstx", "ptr [eax+esp]", "[eax+esp]", BNDREG); + put("bndstx", "ptr [esp+eax]", "[esp+eax]", BNDREG); + put("bndstx", "ptr [eax+ecx*2]", "[eax+ecx*2]", BNDREG); + put("bndstx", "ptr [ecx+ecx]", "[ecx+ecx]", BNDREG); + put("bndstx", "ptr [ecx*2]", "[ecx*2]", BNDREG); + put("bndstx", "ptr [eax+ecx*2+500]", "[eax+ecx*2+500]", BNDREG); +#ifdef XBYAK64 + put("bndstx", "ptr [rax+rcx*2]", "[rax+rcx*2]", BNDREG); + put("bndstx", "ptr [r9*2]", "[r9*2]", BNDREG); + put("bndstx", "ptr [r9*2+r15]", "[r9*2+r15]", BNDREG); +#endif } void putFpuMem16_32() const { diff --git a/test/nm_frame.cpp b/test/nm_frame.cpp index 95240c7..697c2c4 100644 --- a/test/nm_frame.cpp +++ b/test/nm_frame.cpp @@ -6,6 +6,7 @@ using namespace Xbyak; #ifdef _MSC_VER #pragma warning(disable : 4245) + #pragma warning(disable : 4312) #endif class Sample : public CodeGenerator { void operator=(const Sample&); diff --git a/test/test_address.bat b/test/test_address.bat index 030c04d..f96542f 100644 --- a/test/test_address.bat +++ b/test/test_address.bat @@ -1,5 +1,5 @@ @echo off -set FILTER=cat +set FILTER=grep -v warning if /i "%1"=="64" ( set OPT2=-DXBYAK64 set OPT3=win64 diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h index 3c91ec9..047e6b6 100644 --- a/xbyak/xbyak.h +++ b/xbyak/xbyak.h @@ -105,7 +105,7 @@ namespace Xbyak { enum { DEFAULT_MAX_CODE_SIZE = 4096, - VERSION = 0x5520 /* 0xABCD = A.BC(D) */ + VERSION = 0x5530 /* 0xABCD = A.BC(D) */ }; #ifndef MIE_INTEGER_TYPE_DEFINED @@ -177,6 +177,7 @@ enum { ERR_INVALID_OPMASK_WITH_MEMORY, ERR_INVALID_ZERO, ERR_INVALID_RIP_IN_AUTO_GROW, + ERR_INVALID_MIB_ADDRESS, ERR_INTERNAL }; @@ -237,6 +238,7 @@ public: "invalid opmask with memory", "invalid zero", "invalid rip in AutoGrow", + "invalid mib address", "internal error", }; assert((size_t)err_ < sizeof(errTbl) / sizeof(*errTbl)); @@ -345,6 +347,9 @@ public: }; #endif +class Address; +class Reg; + class Operand { static const uint8 EXT8BIT = 0x20; unsigned int idx_:6; // 0..31 + EXT8BIT = 1 if spl/bpl/sil/dil @@ -497,6 +502,8 @@ public: bool isEqualIfNotInherited(const Operand& rhs) const { return idx_ == rhs.idx_ && kind_ == rhs.kind_ && bit_ == rhs.bit_ && zero_ == rhs.zero_ && mask_ == rhs.mask_ && rounding_ == rhs.rounding_; } bool operator==(const Operand& rhs) const; bool operator!=(const Operand& rhs) const { return !operator==(rhs); } + const Address& getAddress() const; + const Reg& getReg() const; }; class Label; @@ -530,6 +537,12 @@ public: #endif }; +inline const Reg& Operand::getReg() const +{ + assert(!isMEM()); + return static_cast<const Reg&>(*this); +} + struct Reg8 : public Reg { explicit Reg8(int idx = 0, bool ext8bit = false) : Reg(idx, Operand::REG, 8, ext8bit) { } }; @@ -689,13 +702,15 @@ public: } } bool isVsib(int bit = 128 | 256 | 512) const { return index_.isBit(bit); } - void optimize() + RegExp optimize() const { + RegExp exp = *this; // [reg * 2] => [reg + reg] - if (index_.isBit(i32e) && !base_.getBit() && index_.getBit() && scale_ == 2) { - base_ = index_; - scale_ = 1; + if (index_.isBit(i32e) && !base_.getBit() && scale_ == 2) { + exp.base_ = index_; + exp.scale_ = 1; } + return exp; } bool operator==(const RegExp& rhs) const { @@ -715,6 +730,11 @@ public: } friend RegExp operator+(const RegExp& a, const RegExp& b); friend RegExp operator-(const RegExp& e, size_t disp); + uint8 getRex() const + { + uint8 rex = index_.getRexX() | base_.getRexB(); + return rex ? uint8(rex | 0x40) : 0; + } private: /* [base_ + index_ * scale_ + disp_] @@ -975,7 +995,6 @@ public: : Operand(0, MEM, sizeBit), e_(e), label_(0), mode_(M_ModRM), permitVsib_(false), broadcast_(broadcast) { e_.verify(); - e_.optimize(); } #ifdef XBYAK64 explicit Address(size_t disp) @@ -984,7 +1003,10 @@ public: : Operand(0, MEM, sizeBit), e_(addr.disp_), label_(addr.label_), mode_(addr.isAddr_ ? M_ripAddr : M_rip), permitVsib_(false), broadcast_(broadcast) { } #endif void permitVsib() const { permitVsib_ = true; } - const RegExp& getRegExp() const { return e_; } + RegExp getRegExp(bool optimize = true) const + { + return optimize ? e_.optimize() : e_; + } Mode getMode() const { return mode_; } bool is32bit() const { verify(); return e_.getBase().getBit() == 32 || e_.getIndex().getBit() == 32; } bool isOnlyDisp() const { verify(); return !e_.getBase().getBit() && !e_.getIndex().getBit(); } // for mov eax @@ -993,9 +1015,7 @@ public: { verify(); if (mode_ != M_ModRM) return 0; - uint8 rex = e_.getIndex().getRexX() | e_.getBase().getRexB(); - if (rex) rex |= 0x40; - return rex; + return getRegExp().getRex(); } bool is64bitDisp() const { verify(); return mode_ == M_64bitDisp; } // for moffset bool isBroadcast() const { return broadcast_; } @@ -1014,9 +1034,15 @@ private: void verify() const { if (e_.isVsib() && !permitVsib_) throw Error(ERR_BAD_VSIB_ADDRESSING); } }; +inline const Address& Operand::getAddress() const +{ + assert(isMEM()); + return static_cast<const Address&>(*this); +} + inline bool Operand::operator==(const Operand& rhs) const { - if (isMEM() && rhs.isMEM()) return static_cast<const Address&>(*this) == static_cast<const Address&>(rhs); + if (isMEM() && rhs.isMEM()) return this->getAddress() == rhs.getAddress(); return isEqualIfNotInherited(rhs); } @@ -1363,12 +1389,12 @@ private: if (p1->isMEM()) std::swap(p1, p2); if (p1->isMEM()) throw Error(ERR_BAD_COMBINATION); if (p2->isMEM()) { - const Address& addr = static_cast<const Address&>(*p2); + const Address& addr = p2->getAddress(); if (BIT == 64 && addr.is32bit()) db(0x67); - rex = addr.getRex() | static_cast<const Reg&>(*p1).getRex(); + rex = addr.getRex() | p1->getReg().getRex(); } else { // ModRM(reg, base); - rex = static_cast<const Reg&>(op2).getRex(static_cast<const Reg&>(op1)); + rex = op2.getReg().getRex(op1.getReg()); } // except movsx(16bit, 32/64bit) if ((op1.isBit(16) && !op2.isBit(i32e)) || (op2.isBit(16) && !op1.isBit(i32e))) db(0x66); @@ -1581,6 +1607,17 @@ private: db(code0 | (reg.isBit(8) ? 0 : 1)); if (code1 != NONE) db(code1); if (code2 != NONE) db(code2); opAddr(addr, reg.getIdx(), immSize); } + void opMIB(const Address& addr, const Reg& reg, int code0, int code1) + { + if (addr.is64bitDisp()) throw Error(ERR_CANT_USE_64BIT_DISP); + if (addr.getMode() != Address::M_ModRM) throw Error(ERR_INVALID_MIB_ADDRESS); + if (BIT == 64 && addr.is32bit()) db(0x67); + const RegExp& regExp = addr.getRegExp(false); + uint8 rex = regExp.getRex(); + if (rex) db(rex); + db(code0); db(code1); + setSIB(regExp, reg.getIdx()); + } void makeJmp(uint32 disp, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref) { const int shortJmpSize = 2; @@ -1656,9 +1693,9 @@ private: if (isValid && !isValid(reg, op)) throw Error(ERR_BAD_COMBINATION); if (pref != NONE) db(pref); if (op.isMEM()) { - opModM(static_cast<const Address&>(op), static_cast<const Reg&>(reg), 0x0F, preCode, code, (imm8 != NONE) ? 1 : 0); + opModM(op.getAddress(), reg.getReg(), 0x0F, preCode, code, (imm8 != NONE) ? 1 : 0); } else { - opModR(static_cast<const Reg&>(reg), static_cast<const Reg&>(op), 0x0F, preCode, code); + opModR(reg.getReg(), op.getReg(), 0x0F, preCode, code); } if (imm8 != NONE) db(imm8); } @@ -1676,9 +1713,9 @@ private: { if (pref != NONE) db(pref); if (op1.isXMM() && op2.isMEM()) { - opModM(static_cast<const Address&>(op2), static_cast<const Reg&>(op1), 0x0F, code); + opModM(op2.getAddress(), op1.getReg(), 0x0F, code); } else if (op1.isMEM() && op2.isXMM()) { - opModM(static_cast<const Address&>(op1), static_cast<const Reg&>(op2), 0x0F, code | 1); + opModM(op1.getAddress(), op2.getReg(), 0x0F, code | 1); } else { throw Error(ERR_BAD_COMBINATION); } @@ -1687,7 +1724,7 @@ private: { if (hasMMX2 && op.isREG(i32e)) { /* pextrw is special */ if (mmx.isXMM()) db(0x66); - opModR(static_cast<const Reg&>(op), mmx, 0x0F, 0xC5); db(imm); + opModR(op.getReg(), mmx, 0x0F, 0xC5); db(imm); } else { opGen(mmx, op, code, 0x66, isXMM_REG32orMEM, imm, 0x3A); } @@ -1697,9 +1734,9 @@ private: int opBit = op.getBit(); if (disableRex && opBit == 64) opBit = 32; if (op.isREG(bit)) { - opModR(Reg(ext, Operand::REG, opBit), static_cast<const Reg&>(op).changeBit(opBit), code0, code1, code2); + opModR(Reg(ext, Operand::REG, opBit), op.getReg().changeBit(opBit), code0, code1, code2); } else if (op.isMEM()) { - opModM(static_cast<const Address&>(op), Reg(ext, Operand::REG, opBit), code0, code1, code2, immSize); + opModM(op.getAddress(), Reg(ext, Operand::REG, opBit), code0, code1, code2, immSize); } else { throw Error(ERR_BAD_COMBINATION); } @@ -1718,9 +1755,9 @@ private: void opModRM(const Operand& op1, const Operand& op2, bool condR, bool condM, int code0, int code1 = NONE, int code2 = NONE, int immSize = 0) { if (condR) { - opModR(static_cast<const Reg&>(op1), static_cast<const Reg&>(op2), code0, code1, code2); + opModR(op1.getReg(), op2.getReg(), code0, code1, code2); } else if (condM) { - opModM(static_cast<const Address&>(op2), static_cast<const Reg&>(op1), code0, code1, code2, immSize); + opModM(op2.getAddress(), op1.getReg(), code0, code1, code2, immSize); } else { throw Error(ERR_BAD_COMBINATION); } @@ -1735,7 +1772,7 @@ private: void opRM_RM(const Operand& op1, const Operand& op2, int code) { if (op1.isREG() && op2.isMEM()) { - opModM(static_cast<const Address&>(op2), static_cast<const Reg&>(op1), code | 2); + opModM(op2.getAddress(), op1.getReg(), code | 2); } else { opModRM(op2, op1, op1.isREG() && op1.getKind() == op2.getKind(), op1.isMEM() && op2.isREG(), code); } @@ -1768,19 +1805,19 @@ private: #endif code = 0xFE; if (op.isREG()) { - opModR(Reg(ext, Operand::REG, op.getBit()), static_cast<const Reg&>(op), code); + opModR(Reg(ext, Operand::REG, op.getBit()), op.getReg(), code); } else { - opModM(static_cast<const Address&>(op), Reg(ext, Operand::REG, op.getBit()), code); + opModM(op.getAddress(), Reg(ext, Operand::REG, op.getBit()), code); } } void opPushPop(const Operand& op, int code, int ext, int alt) { if (op.isREG()) { if (op.isBit(16)) db(0x66); - if (static_cast<const Reg&>(op).getIdx() >= 8) db(0x41); + if (op.getReg().getIdx() >= 8) db(0x41); db(alt | (op.getIdx() & 7)); } else if (op.isMEM()) { - opModM(static_cast<const Address&>(op), Reg(ext, Operand::REG, op.getBit()), code); + opModM(op.getAddress(), Reg(ext, Operand::REG, op.getBit()), code); } else { throw Error(ERR_BAD_COMBINATION); } @@ -1869,11 +1906,12 @@ private: void opVex(const Reg& r, const Operand *p1, const Operand& op2, int type, int code, int imm8 = NONE) { if (op2.isMEM()) { - const Address& addr = static_cast<const Address&>(op2); - const Reg& base = addr.getRegExp().getBase(); + const Address& addr = op2.getAddress(); + const RegExp& regExp = addr.getRegExp(); + const Reg& base = regExp.getBase(); if (BIT == 64 && addr.is32bit()) db(0x67); int disp8N = 0; - bool x = addr.getRegExp().getIndex().isExtIdx(); + bool x = regExp.getIndex().isExtIdx(); if ((type & T_MUST_EVEX) || r.hasEvex() || (p1 && p1->hasEvex()) || addr.isBroadcast() || addr.getOpmaskIdx()) { int aaa = addr.getOpmaskIdx(); if (aaa && !(type & T_M_K)) throw Error(ERR_INVALID_OPMASK_WITH_MEMORY); @@ -1882,14 +1920,14 @@ private: if (!(type & (T_B32 | T_B64))) throw Error(ERR_INVALID_BROADCAST); b = true; } - int VL = addr.getRegExp().isVsib() ? addr.getRegExp().getIndex().getBit() : 0; + int VL = regExp.isVsib() ? regExp.getIndex().getBit() : 0; disp8N = evex(r, base, p1, type, code, x, b, aaa, VL); } else { vex(r, base, p1, type, code, x); } opAddr(addr, r.getIdx(), (imm8 != NONE) ? 1 : 0, disp8N); } else { - const Reg& base = static_cast<const Reg&>(op2); + const Reg& base = op2.getReg(); if ((type & T_MUST_EVEX) || r.hasEvex() || (p1 && p1->hasEvex()) || base.hasEvex()) { evex(r, base, p1, type, code); } else { @@ -1971,11 +2009,12 @@ private: } void opGather(const Xmm& x1, const Address& addr, const Xmm& x2, int type, uint8 code, int mode) { - if (!addr.getRegExp().isVsib(128 | 256)) throw Error(ERR_BAD_VSIB_ADDRESSING); + const RegExp& regExp = addr.getRegExp(); + if (!regExp.isVsib(128 | 256)) throw Error(ERR_BAD_VSIB_ADDRESSING); const int y_vx_y = 0; const int y_vy_y = 1; // const int x_vy_x = 2; - const bool isAddrYMM = addr.getRegExp().getIndex().getBit() == 256; + const bool isAddrYMM = regExp.getIndex().getBit() == 256; if (!x1.isXMM() || isAddrYMM || !x2.isXMM()) { bool isOK = false; if (mode == y_vx_y) { @@ -2174,13 +2213,13 @@ public: const Address *addr = 0; uint8 code = 0; if (reg1.isREG() && reg1.getIdx() == 0 && reg2.isMEM()) { // mov eax|ax|al, [disp] - reg = &static_cast<const Reg&>(reg1); - addr= &static_cast<const Address&>(reg2); + reg = ®1.getReg(); + addr= ®2.getAddress(); code = 0xA0; } else if (reg1.isMEM() && reg2.isREG() && reg2.getIdx() == 0) { // mov [disp], eax|ax|al - reg = &static_cast<const Reg&>(reg2); - addr= &static_cast<const Address&>(reg1); + reg = ®2.getReg(); + addr= ®1.getAddress(); code = 0xA2; } #ifdef XBYAK64 @@ -2207,7 +2246,7 @@ public: void mov(const Operand& op, size_t imm) { if (op.isREG()) { - const int size = mov_imm(static_cast<const Reg&>(op), imm); + const int size = mov_imm(op.getReg(), imm); db(imm, size); } else if (op.isMEM()) { verifyMemHasSize(op); @@ -2219,7 +2258,7 @@ public: if (!inner::IsInInt32(imm)) throw Error(ERR_IMM_IS_TOO_BIG); immSize = 4; } - opModM(static_cast<const Address&>(op), Reg(0, Operand::REG, op.getBit()), 0xC6, NONE, NONE, immSize); + opModM(op.getAddress(), Reg(0, Operand::REG, op.getBit()), 0xC6, NONE, NONE, immSize); db(static_cast<uint32>(imm), immSize); } else { throw Error(ERR_BAD_COMBINATION); @@ -2303,7 +2342,7 @@ public: } void mov(const Segment& seg, const Operand& op) { - opModRM(Reg8(seg.getIdx()), op.isREG(16|i32e) ? static_cast<const Operand&>(static_cast<const Reg&>(op).cvt32()) : op, op.isREG(16|i32e), op.isMEM(), 0x8E); + opModRM(Reg8(seg.getIdx()), op.isREG(16|i32e) ? static_cast<const Operand&>(op.getReg().cvt32()) : op, op.isREG(16|i32e), op.isMEM(), 0x8E); } #endif diff --git a/xbyak/xbyak_mnemonic.h b/xbyak/xbyak_mnemonic.h index 74e9759..ea306d2 100644 --- a/xbyak/xbyak_mnemonic.h +++ b/xbyak/xbyak_mnemonic.h @@ -1,4 +1,4 @@ -const char *getVersionString() const { return "5.52"; } +const char *getVersionString() const { return "5.53"; } void adc(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x10, 2); } void adc(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x10); } void adcx(const Reg32e& reg, const Operand& op) { opGen(reg, op, 0xF6, 0x66, isREG32_REG32orMEM, NONE, 0x38); } @@ -36,11 +36,11 @@ void bnd() { db(0xF2); } void bndcl(const BoundsReg& bnd, const Operand& op) { db(0xF3); opR_ModM(op, i32e, bnd.getIdx(), 0x0F, 0x1A, NONE, !op.isMEM()); } void bndcn(const BoundsReg& bnd, const Operand& op) { db(0xF2); opR_ModM(op, i32e, bnd.getIdx(), 0x0F, 0x1B, NONE, !op.isMEM()); } void bndcu(const BoundsReg& bnd, const Operand& op) { db(0xF2); opR_ModM(op, i32e, bnd.getIdx(), 0x0F, 0x1A, NONE, !op.isMEM()); } -void bndldx(const BoundsReg& bnd, const Address& addr) { opModM(addr, bnd, 0x0F, 0x1A); } +void bndldx(const BoundsReg& bnd, const Address& addr) { opMIB(addr, bnd, 0x0F, 0x1A); } void bndmk(const BoundsReg& bnd, const Address& addr) { db(0xF3); opModM(addr, bnd, 0x0F, 0x1B); } void bndmov(const Address& addr, const BoundsReg& bnd) { db(0x66); opModM(addr, bnd, 0x0F, 0x1B); } void bndmov(const BoundsReg& bnd, const Operand& op) { db(0x66); opModRM(bnd, op, op.isBNDREG(), op.isMEM(), 0x0F, 0x1A); } -void bndstx(const Address& addr, const BoundsReg& bnd) { opModM(addr, bnd, 0x0F, 0x1B); } +void bndstx(const Address& addr, const BoundsReg& bnd) { opMIB(addr, bnd, 0x0F, 0x1B); } void bsf(const Reg®, const Operand& op) { opModRM(reg, op, op.isREG(16 | i32e), op.isMEM(), 0x0F, 0xBC); } void bsr(const Reg®, const Operand& op) { opModRM(reg, op, op.isREG(16 | i32e), op.isMEM(), 0x0F, 0xBD); } void bswap(const Reg32e& reg) { opModR(Reg32(1), reg, 0x0F); } |