diff options
-rw-r--r-- | readme.md | 29 | ||||
-rw-r--r-- | readme.txt | 3 | ||||
-rw-r--r-- | test/jmp.cpp | 73 | ||||
-rw-r--r-- | xbyak/xbyak.h | 13 | ||||
-rw-r--r-- | xbyak/xbyak_mnemonic.h | 2 |
5 files changed, 114 insertions, 6 deletions
@@ -1,5 +1,5 @@ -# Xbyak 5.86 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++ +# Xbyak 5.87 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++ ## Abstract @@ -216,6 +216,32 @@ void func1() } ``` +### short and long jump +Xbyak deals with jump mnemonics of an undefined label as short jump if no type is specified. +So if the size between jmp and label is larger than 127 byte, then xbyak will cause an error. + +``` +jmp("short-jmp"); // short jmp +// small code +L("short-jmp"); + +jmp("long-jmp"); +// long code +L("long-jmp"); // throw exception +``` +Then specify T_NEAR for jmp. +``` +jmp("long-jmp", T_NEAR); // long jmp +// long code +L("long-jmp"); +``` +Or call `setDefaultJmpNEAR(true);` once, then the default type is set to T_NEAR. +``` +jmp("long-jmp"); // long jmp +// long code +L("long-jmp"); +``` + ### Label class `L()` and `jxx()` support Label class. @@ -396,6 +422,7 @@ modified new BSD License http://opensource.org/licenses/BSD-3-Clause ## History +* 2019/Dec/19 ver 5.87 add setDefaultJmpNEAR(), which deals with `jmp` of an undefined label as T_NEAR if no type is specified. * 2019/Dec/13 ver 5.86 [changed] revert to the behavior before v5.84 if -fno-operator-names is defined (and() is available) * 2019/Dec/07 ver 5.85 append MAP_JIT flag to mmap for macOS mojave or later * 2019/Nov/29 ver 5.84 [changed] XBYAK_NO_OP_NAMES is defined unless XBYAK_USE_OP_NAMES is defined @@ -1,5 +1,5 @@ - C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.86
+ C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.87
-----------------------------------------------------------------------------
◎概要
@@ -371,6 +371,7 @@ sample/{echo,hello}.bfは http://www.kmonos.net/alang/etc/brainfuck.php から -----------------------------------------------------------------------------
◎履歴
+2019/12/19 ver 5.87 未定義ラベルへのjmp命令のデフォルト挙動をT_NEARにするsetDefaultJmpNEAR()を追加
2019/12/13 ver 5.86 [変更] -fno-operator-namesが指定されたときは5.84以前の挙動に戻す
2019/12/07 ver 5.85 mmapにMAP_JITフラグを追加(macOS mojave以上)
2019/11/29 ver 5.84 [変更] XBYAK_USE_OP_NAMESが定義されていない限りXBYAK_NO_OP_NAMESが定義されるように変更
diff --git a/test/jmp.cpp b/test/jmp.cpp index 4921a5a..3afc773 100644 --- a/test/jmp.cpp +++ b/test/jmp.cpp @@ -1305,3 +1305,76 @@ CYBOZU_TEST_AUTO(release_label_after_code) printf("id=%d %d %d %d %d\n", L1.getId(), L2.getId(), L3.getId(), L4.getId(), L5.getId()); } } + +struct JmpTypeCode : Xbyak::CodeGenerator { + void nops() + { + for (int i = 0; i < 130; i++) { + nop(); + } + } + // return jmp code size + size_t gen(bool pre, bool large, Xbyak::CodeGenerator::LabelType type) + { + Label label; + if (pre) { + L(label); + if (large) nops(); + size_t pos = getSize(); + jmp(label, type); + return getSize() - pos; + } else { + size_t pos = getSize(); + jmp(label, type); + size_t size = getSize() - pos; + if (large) nops(); + L(label); + return size; + } + } +}; + +CYBOZU_TEST_AUTO(setDefaultJmpNEAR) +{ + const Xbyak::CodeGenerator::LabelType T_SHORT = Xbyak::CodeGenerator::T_SHORT; + const Xbyak::CodeGenerator::LabelType T_NEAR = Xbyak::CodeGenerator::T_NEAR; + const Xbyak::CodeGenerator::LabelType T_AUTO = Xbyak::CodeGenerator::T_AUTO; + const struct { + bool pre; + bool large; + Xbyak::CodeGenerator::LabelType type; + size_t expect1; // 0 means exception + size_t expect2; + } tbl[] = { + { false, false, T_SHORT, 2, 2 }, + { false, false, T_NEAR, 5, 5 }, + { false, true, T_SHORT, 0, 0 }, + { false, true, T_NEAR, 5, 5 }, + + { true, false, T_SHORT, 2, 2 }, + { true, false, T_NEAR, 5, 5 }, + { true, true, T_SHORT, 0, 0 }, + { true, true, T_NEAR, 5, 5 }, + + { false, false, T_AUTO, 2, 5 }, + { false, true, T_AUTO, 0, 5 }, + { true, false, T_AUTO, 2, 2 }, + { true, true, T_AUTO, 5, 5 }, + }; + JmpTypeCode code1, code2; + code2.setDefaultJmpNEAR(true); + for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) { + if (tbl[i].expect1) { + size_t size = code1.gen(tbl[i].pre, tbl[i].large, tbl[i].type); + CYBOZU_TEST_EQUAL(size, tbl[i].expect1); + } else { + CYBOZU_TEST_EXCEPTION(code1.gen(tbl[i].pre, tbl[i].large, tbl[i].type), std::exception); + } + if (tbl[i].expect2) { + size_t size = code2.gen(tbl[i].pre, tbl[i].large, tbl[i].type); + CYBOZU_TEST_EQUAL(size, tbl[i].expect2); + } else { + CYBOZU_TEST_EXCEPTION(code2.gen(tbl[i].pre, tbl[i].large, tbl[i].type), std::exception); + } + } +} diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h index 5c29899..a41503c 100644 --- a/xbyak/xbyak.h +++ b/xbyak/xbyak.h @@ -115,7 +115,7 @@ namespace Xbyak { enum { DEFAULT_MAX_CODE_SIZE = 4096, - VERSION = 0x5860 /* 0xABCD = A.BC(D) */ + VERSION = 0x5870 /* 0xABCD = A.BC(D) */ }; #ifndef MIE_INTEGER_TYPE_DEFINED @@ -1775,6 +1775,7 @@ private: db(longCode); dd(disp - longJmpSize); } } + bool isNEAR(LabelType type) const { return type == T_NEAR || (type == T_AUTO && isDefaultJmpNEAR_); } template<class T> void opJmp(T& label, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref) { @@ -1784,7 +1785,7 @@ private: makeJmp(inner::VerifyInInt32(offset - size_), type, shortCode, longCode, longPref); } else { int jmpSize = 0; - if (type == T_NEAR) { + if (isNEAR(type)) { jmpSize = 4; if (longPref) db(longPref); db(longCode); dd(0); @@ -1799,7 +1800,7 @@ private: void opJmpAbs(const void *addr, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref = 0) { if (isAutoGrow()) { - if (type != T_NEAR) throw Error(ERR_ONLY_T_NEAR_IS_SUPPORTED_IN_AUTO_GROW); + if (!isNEAR(type)) throw Error(ERR_ONLY_T_NEAR_IS_SUPPORTED_IN_AUTO_GROW); if (size_ + 16 >= maxSize_) growMemory(); if (longPref) db(longPref); db(longCode); @@ -2293,6 +2294,9 @@ public: #ifndef XBYAK_DISABLE_SEGMENT const Segment es, cs, ss, ds, fs, gs; #endif +private: + bool isDefaultJmpNEAR_; +public: void L(const std::string& label) { labelMgr_.defineSlabel(label); } void L(Label& label) { labelMgr_.defineClabel(label); } Label L() { Label label; L(label); return label; } @@ -2312,6 +2316,8 @@ public: void putL(std::string label) { putL_inner(label); } void putL(const Label& label) { putL_inner(label); } + // set default type of `jmp` of undefined label to T_NEAR + void setDefaultJmpNEAR(bool near) { isDefaultJmpNEAR_ = near; } void jmp(const Operand& op) { opR_ModM(op, BIT, 4, 0xFF, NONE, NONE, true); } void jmp(std::string label, LabelType type = T_AUTO) { opJmp(label, type, 0xEB, 0xE9, 0); } void jmp(const char *label, LabelType type = T_AUTO) { jmp(std::string(label), type); } @@ -2570,6 +2576,7 @@ public: #ifndef XBYAK_DISABLE_SEGMENT , es(Segment::es), cs(Segment::cs), ss(Segment::ss), ds(Segment::ds), fs(Segment::fs), gs(Segment::gs) #endif + , isDefaultJmpNEAR_(false) { labelMgr_.set(this); } diff --git a/xbyak/xbyak_mnemonic.h b/xbyak/xbyak_mnemonic.h index c398db2..ff1ee07 100644 --- a/xbyak/xbyak_mnemonic.h +++ b/xbyak/xbyak_mnemonic.h @@ -1,4 +1,4 @@ -const char *getVersionString() const { return "5.86"; } +const char *getVersionString() const { return "5.87"; } 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); } |