From 683f7448ae0933a3a5142fb51eb01dbf280a01e1 Mon Sep 17 00:00:00 2001 From: MITSUNARI Shigeo Date: Tue, 20 Mar 2012 00:07:29 +0900 Subject: [PATCH] Xbyak ver 3.50 --- gen/gen_code.cpp | 2 +- readme.md | 27 +++- readme.txt | 31 ++++- test/Makefile | 15 ++- test/jmp.cpp | 293 +++++++++++++++++++++++++++++++++++++---- test/jmp.sln | 20 +++ test/jmp.vcproj | 195 +++++++++++++++++++++++++++ xbyak/xbyak.h | 287 ++++++++++++++++++++-------------------- xbyak/xbyak_mnemonic.h | 62 ++++----- 9 files changed, 717 insertions(+), 215 deletions(-) create mode 100644 test/jmp.sln create mode 100644 test/jmp.vcproj diff --git a/gen/gen_code.cpp b/gen/gen_code.cpp index fd1ff97..cb62be3 100644 --- a/gen/gen_code.cpp +++ b/gen/gen_code.cpp @@ -421,7 +421,7 @@ void put() for (int i = 0; i < NUM_OF_ARRAY(tbl); i++) { const Tbl *p = &tbl[i]; printf("void cmov%s(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | %d); }\n", p->name, p->ext); - printf("void j%s(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x%02X, 0x%02X, 0x%02X); }\n", p->name, p->ext | B01110000, p->ext | B10000000, 0x0F); + printf("void j%s(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x%02X, 0x%02X, 0x%02X); }\n", p->name, p->ext | B01110000, p->ext | B10000000, 0x0F); printf("void set%s(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | %d); }\n", p->name, p->ext); } } diff --git a/readme.md b/readme.md index 3b1d2c3..c17f01b 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,5 @@ -Xbyak 3.05 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++ +Xbyak 3.50 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++ ============= Abstract @@ -46,6 +46,26 @@ Linux: These files are copied into /usr/local/include/xbyak +New Feature +------------- + +AutoGrow mode is a mode that Xbyak grows memory automatically if necessary. +Call ready() before calling getCode() to calc address of jmp. + + struct Code : Xbyak::CodeGenerator { + Code() + : Xbyak::CodeGenerator(, Xbyak::AutoGrow) + { + ... + } + }; + Code c; + c.ready(); // Don't forget to call this function + +>Don't use the address returned by getCurr() before calling ready(). +>It may be invalid address. +>RESTRICTION : rip addressing is not supported in AutoGrow + Syntax ------------- @@ -202,6 +222,7 @@ http://opensource.org/licenses/BSD-3-Clause History ------------- +* 2012/Mar/19 ver 3.50 support AutoGrow mode * 2011/Nov/09 ver 3.05 fix bit property of rip addresing / support movsxd * 2011/Aug/15 ver 3.04 fix dealing with imm8 such as add(dword [ebp-8], 0xda); (thanks to lolcat) * 2011/Jun/16 ver 3.03 fix __GNUC_PREREQ macro for Mac gcc(thanks to t_teruya) @@ -252,5 +273,5 @@ Author MITSUNARI Shigeo(herumi at nifty dot com) --- -$Revision: 1.16 $ -$Date: 2011/12/22 01:43:13 $ +$Revision: 1.17 $ +$Date: 2012/03/19 14:28:46 $ diff --git a/readme.txt b/readme.txt index 44a3fff..6498e54 100644 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,5 @@ - C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak version 3.05 + C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak version 3.50 ----------------------------------------------------------------------------- ◎概要 @@ -34,6 +34,34 @@ xbyak_mnemonic.h これらを同一のパスに入れてインクルードパスに追加してください. Linuxではmake installで/usr/local/include/xbyakにコピーされます. +----------------------------------------------------------------------------- +◎新機能 + +AutoGrowモード追加 +これはメモリ伸長を動的に行うモードです. +今まではXbyak::CodeGenerator()に渡したメモリサイズを超えると例外が発生して +いましたが,このモードでは内部でメモリを再確保して伸長します. +ただし,getCode()を呼び出す前にジャンプ命令のアドレス解決をするためにready() +関数を呼ぶ必要があります. + +次のように使います. + + struct Code : Xbyak::CodeGenerator { + Code() + : Xbyak::CodeGenerator(, Xbyak::AutoGrow) + { + ... + } + }; + Code c; + c.ready(); // この呼び出しを忘れてはいけない + +注意1. ready()を呼んで確定するまではgetCurr()で得たポインタは無効化されている +可能性があります.getSize()でoffsetを保持しておきready()のあとにgetCode()を +呼び出してからgetCode() + offsetで新しいポインタを取得してください. + +注意2. AutoGrowモードでは64bitモードの相対アドレッシング[rip]は非サポートです. + ----------------------------------------------------------------------------- ◎文法 @@ -214,6 +242,7 @@ sample/{echo,hello}.bfは http://www.kmonos.net/alang/etc/brainfuck.php から ----------------------------------------------------------------------------- ◎履歴 +2012/03/19 ver 3.50 AutoGrowモードサポート 2011/11/09 ver 3.05 rip相対の64bitサイズ以外の扱いのバグ修正 / movsxdサポート 2011/08/15 ver 3.04 add(dword [ebp-8], 0xda);などにおけるimm8の扱いのバグ修正(thanks to lolcat) 2011/06/16 ver 3.03 Macのgcc上での__GNUC_PREREQがミスってたのを修正(thanks to t_teruya) diff --git a/test/Makefile b/test/Makefile index e1c9ffc..1a52476 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,11 +2,8 @@ TARGET = make_nm normalize_prefix XBYAK_INC=../xbyak/xbyak.h ifeq ($(MODE_BIT),64) - XBYAK_OPT=-m64 - XBYAK_COPT=-DXBYAK64 + RARGET += jmp64 else - XBYAK_OPT=-m32 - XBYAK_COPT=-DXBYAK32 endif all: $(TARGET) @@ -16,12 +13,16 @@ CFLAGS_WARN=-Wall -Wextra -Wformat=2 -Wcast-qual -Wcast-align -Wwrite-strings -W CFLAGS=-O2 -fomit-frame-pointer -Wall -fno-operator-names -I../ $(XBYAK_OPT) $(XBYAK_COPT) $(CFLAGS_WARN) make_nm: $(CXX) $(CFLAGS) make_nm.cpp -o $@ -normalize_prefix: normalize_prefix.cpp +normalize_prefix: normalize_prefix.cpp ../xbyak/xbyak.h $(CXX) $(CFLAGS) normalize_prefix.cpp -o $@ -test_mmx: test_mmx.cpp +test_mmx: test_mmx.cpp ../xbyak/xbyak.h $(CXX) $(CFLAGS) test_mmx.cpp -o $@ -lpthread -jmp: jmp.cpp +jmp: jmp.cpp ../xbyak/xbyak.h + $(CXX) $(CFLAGS) jmp.cpp -o $@ -m32 +jmp64: jmp.cpp ../xbyak/xbyak.h $(CXX) $(CFLAGS) jmp.cpp -o $@ +grow: grow.cpp ../xbyak/xbyak.h + $(CXX) $(CFLAGS) grow.cpp -o $@ test: normalize_prefix jmp ./test_nm.sh diff --git a/test/jmp.cpp b/test/jmp.cpp index 8380041..5642dff 100644 --- a/test/jmp.cpp +++ b/test/jmp.cpp @@ -1,11 +1,16 @@ #include #include -#include "xbyak/xbyak.h" +#include +#include #define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0])) +#if !defined(_WIN64) && !defined(__x86_64__) + #define ONLY_32BIT +#endif + using namespace Xbyak; -struct TestJmp : public CodeGenerator { +struct TestJmp : public Xbyak::CodeGenerator { void putNop(int n) { for (int i = 0; i < n; i++) { @@ -45,24 +50,19 @@ struct TestJmp : public CodeGenerator { */ TestJmp(int offset, bool isBack, bool isShort) { - char buf[32]; - static int count = 0; if (isBack) { - sprintf(buf, "L(\"X%d\");\n", count); - L(buf); + L("@@"); putNop(offset); - jmp(buf); + jmp("@b"); } else { - sprintf(buf, "L(\"Y%d\");\n", count); if (isShort) { - jmp(buf); + jmp("@f"); } else { - jmp(buf, T_NEAR); + jmp("@f", T_NEAR); } putNop(offset); - L(buf); + L("@@"); } - count++; } }; @@ -72,34 +72,125 @@ void test1() int offset; bool isBack; bool isShort; - const char *result; + uint8 result[6]; + int size; } tbl[] = { - { 0, true, true, "EBFE" }, - { 1, true, true, "EBFD" }, - { 126, true, true, "EB80" }, - { 127, true, false, "E97CFFFFFF" }, - { 0, false, true, "EB00" }, - { 1, false, true, "EB01" }, - { 127, false, true, "EB7F" }, - { 128, false, false, "E980000000" }, + { 0, true, true, { 0xeb, 0xfe }, 2 }, + { 1, true, true, { 0xeb, 0xfd }, 2 }, + { 126, true, true, { 0xeb, 0x80 }, 2 }, + { 127, true, false, {0xe9, 0x7c, 0xff, 0xff, 0xff }, 5 }, + { 0, false, true, { 0xeb, 0x00 }, 2 }, + { 1, false, true, { 0xeb, 0x01 }, 2 }, + { 127, false, true, { 0xeb, 0x7f }, 2 }, + { 128, false, false, { 0xe9, 0x80, 0x00, 0x00, 0x00 }, 5 }, }; for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) { const Tbl *p = &tbl[i]; TestJmp jmp(p->offset, p->isBack, p->isShort); const uint8 *q = (const uint8*)jmp.getCode(); - char buf[32]; if (p->isBack) q += p->offset; /* skip nop */ - for (size_t j = 0; j < jmp.getSize() - p->offset; j++) { - sprintf(&buf[j * 2], "%02X", q[j]); + for (int j = 0; j < p->size; j++) { + if (q[j] != p->result[j]) { + printf("err (%d,%d) %02x assume=%02x\n", (int)i, j, q[j], p->result[j]); + } } - if (strcmp(buf, p->result) != 0) { - printf("error %d assume:%s, err=%s\n", i, p->result, buf); + } + puts("ok"); +} + +struct TestJmp2 : public CodeGenerator { + void putNop(int n) + { + for (int i = 0; i < n; i++) { + nop(); + } + } +/* + 1 00000000 90 nop + 2 00000001 90 nop + 3 f1: + 4 00000002 dummyX1 resb 126 + 6 00000080 EB80 jmp f1 + 7 + 8 f2: + 9 00000082 dummyX2 resb 127 + 11 00000101 E97CFFFFFF jmp f2 + 12 + 13 + 14 00000106 EB7F jmp f3 + 15 00000108 dummyX3 resb 127 + 17 f3: + 18 + 19 00000187 E980000000 jmp f4 + 20 0000018C dummyX4 resb 128 + 22 f4: +*/ + explicit TestJmp2(void *p) + : Xbyak::CodeGenerator(8192, p) + { + inLocalLabel(); + nop(); + nop(); + L(".f1"); + putNop(126); + jmp(".f1"); + L(".f2"); + putNop(127); + jmp(".f2", T_NEAR); + + jmp(".f3"); + putNop(127); + L(".f3"); + jmp(".f4", T_NEAR); + putNop(128); + L(".f4"); + outLocalLabel(); + } +}; + +void test2() +{ + puts("test2"); + std::string ok; + ok.resize(0x18C + 128, (char)0x90); + ok[0x080] = (char)0xeb; + ok[0x081] = (char)0x80; + + ok[0x101] = (char)0xe9; + ok[0x102] = (char)0x7c; + ok[0x103] = (char)0xff; + ok[0x104] = (char)0xff; + ok[0x105] = (char)0xff; + + ok[0x106] = (char)0xeb; + ok[0x107] = (char)0x7f; + + ok[0x187] = (char)0xe9; + ok[0x188] = (char)0x80; + ok[0x189] = (char)0x00; + ok[0x18a] = (char)0x00; + ok[0x18b] = (char)0x00; + for (int j = 0; j < 2; j++) { + TestJmp2 c(j == 0 ? 0 : Xbyak::AutoGrow); + c.ready(); + std::string m((const char*)c.getCode(), c.getSize()); + if (m.size() != ok.size()) { + printf("test2 err %d %d\n", (int)m.size(), (int)ok.size()); } else { - printf("ok %d\n", i); + if (m != ok) { + for (size_t i = 0; i < m.size(); i++) { + if (m[i] != ok[i]) { + printf("diff 0x%03x %02x %02x\n", (int)i, (unsigned char)m[i], (unsigned char)ok[i]); + } + } + } else { + puts("ok"); + } } } } +#ifdef ONLY_32BIT int add5(int x) { return x + 5; } int add2(int x) { return x + 2; } @@ -121,7 +212,7 @@ struct Grow : Xbyak::CodeGenerator { } }; -void test2() +void test3() { for (int dummySize = 0; dummySize < 40000; dummySize += 10000) { printf("dummySize=%d\n", dummySize); @@ -137,12 +228,158 @@ void test2() } } } +#endif + +Xbyak::uint8 bufL[4096 * 32]; +Xbyak::uint8 bufS[4096 * 2]; + +struct MyAllocator : Xbyak::Allocator { + Xbyak::uint8 *alloc(size_t size) + { + if (size < sizeof(bufS)) { + printf("use bufS(%d)\n", (int)size); + return bufS; + } + if (size < sizeof(bufL)) { + printf("use bufL(%d)\n", (int)size); + return bufL; + } + fprintf(stderr, "no memory %d\n", (int)size); + exit(1); + } + void free(Xbyak::uint8 *) + { + } +} myAlloc; + +void dump(const std::string& m) +{ + printf("size=%d\n ", (int)m.size()); + for (int i = 0; i < 16; i++) { + printf("%02x ", i); + } + printf("\n "); + for (int i = 0; i < 16; i++) { + printf("---"); + } + printf("\n"); + for (size_t i = 0; i < m.size(); i++) { + if ((i % 16) == 0) printf("%04x ", (int)(i / 16)); + printf("%02x ", (unsigned char)m[i]); + if ((i % 16) == 15) putchar('\n'); + } + putchar('\n'); +} + +void diff(const std::string& a, const std::string& b) +{ + puts("diff"); + if (a.size() != b.size()) printf("size diff %d %d\n", (int)a.size(), (int)b.size()); + for (size_t i = 0; i < a.size(); i++) { + if (a[i] != b[i]) { + printf("diff %d(%04x) %02x %02x\n", (int)i, (int)i, (unsigned char)a[i], (unsigned char)b[i]); + } + } + puts("end"); +} + +struct Test4 : Xbyak::CodeGenerator { + explicit Test4(int size, void *mode) + : CodeGenerator(size, mode) + { + using namespace Xbyak; + inLocalLabel(); + outLocalLabel(); + jmp(".x"); + for (int i = 0; i < 10; i++) { + nop(); + } + L(".x"); + ret(); + } +}; +void test4() +{ + std::string fm, gm; + Test4 fc(1024, 0); + Test4 gc(5, Xbyak::AutoGrow); + gc.ready(); + fm.assign((const char*)fc.getCode(), fc.getSize()); + gm.assign((const char*)gc.getCode(), gc.getSize()); +// dump(fm); +// dump(gm); + diff(gm, gm); +} + +struct Test5 : Xbyak::CodeGenerator { + explicit Test5(int size, int count, void *mode) + : CodeGenerator(size, mode, &myAlloc) + { + using namespace Xbyak; + inLocalLabel(); + mov(ecx, count); + xor(eax, eax); + L(".lp"); + for (int i = 0; i < count; i++) { + L(Label::toStr(i).c_str()); + add(eax, 1); + int to = 0; + if (i < count / 2) { + to = count - 1 - i; + } else { + to = count - i; + } + if (i == count / 2) { + jmp(".exit", T_NEAR); + } else { + jmp(Label::toStr(to).c_str(), T_NEAR); + } + } + L(".exit"); + sub(ecx, 1); + jnz(".lp", T_NEAR); + ret(); + outLocalLabel(); + } +}; + +void test5() +{ + std::string fm, gm; + const int count = 50; + int ret; + Test5 fc(1024 * 64, count, 0); + ret = ((int (*)())fc.getCode())(); + if (ret != count * count) { + printf("err ret=%d, %d\n", ret, count * count); + } else { + puts("ok"); + } + fm.assign((const char*)fc.getCode(), fc.getSize()); + Test5 gc(10, count, Xbyak::AutoGrow); + gc.ready(); +#if 0 + ret = ((int (*)())gc.getCode())(); + if (ret != count * count) { + printf("err ret=%d, %d\n", ret, count * count); + } else { + puts("ok"); + } +#endif + gm.assign((const char*)gc.getCode(), gc.getSize()); + diff(fm, gm); +} int main() { try { test1(); test2(); +#ifdef ONLY_32BIT + test3(); +#endif + test4(); + test5(); } catch (Xbyak::Error err) { printf("ERR:%s(%d)\n", Xbyak::ConvertErrorToString(err), err); } catch (...) { diff --git a/test/jmp.sln b/test/jmp.sln new file mode 100644 index 0000000..f43e23b --- /dev/null +++ b/test/jmp.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jmp", "jmp.vcproj", "{AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}.Debug|Win32.ActiveCfg = Debug|Win32 + {AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}.Debug|Win32.Build.0 = Debug|Win32 + {AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}.Release|Win32.ActiveCfg = Release|Win32 + {AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/test/jmp.vcproj b/test/jmp.vcproj new file mode 100644 index 0000000..17118e0 --- /dev/null +++ b/test/jmp.vcproj @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h index 170c198..b10c91b 100644 --- a/xbyak/xbyak.h +++ b/xbyak/xbyak.h @@ -5,9 +5,7 @@ @file xbyak.h @brief Xbyak ; JIT assembler for x86(IA32)/x64 by C++ @author herumi - @version $Revision: 1.268 $ - @url http://homepage1.nifty.com/herumi/soft/xbyak.html - @date $Date: 2012/03/16 14:43:46 $ + @url http://homepage1.nifty.com/herumi/soft/xbyak_e.html @note modified new BSD license http://opensource.org/licenses/BSD-3-Clause */ @@ -55,7 +53,7 @@ namespace Xbyak { enum { DEFAULT_MAX_CODE_SIZE = 4096, - VERSION = 0x3060, /* 0xABCD = A.BC(D) */ + VERSION = 0x3500, /* 0xABCD = A.BC(D) */ }; #ifndef MIE_INTEGER_TYPE_DEFINED @@ -112,7 +110,7 @@ enum Error { ERR_INTERNAL }; -static inline const char *ConvertErrorToString(Error err) +inline const char *ConvertErrorToString(Error err) { static const char errTbl[][40] = { "none", @@ -159,7 +157,8 @@ namespace inner { enum { debug = 1 }; -static inline uint32 GetPtrDist(const void *p1, const void *p2) +#if 0 +inline uint32 GetPtrDist(const void *p1, const void *p2) { uint64 diff = static_cast(p1) - static_cast(p2); #ifdef XBYAK64 @@ -168,8 +167,26 @@ static inline uint32 GetPtrDist(const void *p1, const void *p2) return static_cast(diff); } -static inline bool IsInDisp8(uint32 x) { return 0xFFFFFF80 <= x || x <= 0x7F; } -static inline bool IsInInt32(uint64 x) { return 0xFFFFFFFF80000000ULL <= x || x <= 0x7FFFFFFFU; } +inline uint32 GetOffsetDist(size_t p1, size_t p2) +{ + uint64 diff = p1 - p2; +#ifdef XBYAK64 + if (0x7FFFFFFFULL < diff && diff < 0xFFFFFFFF80000000ULL) throw ERR_OFFSET_IS_TOO_BIG; +#endif + return static_cast(diff); +} +#endif + +inline bool IsInDisp8(uint32 x) { return 0xFFFFFF80 <= x || x <= 0x7F; } +inline bool IsInInt32(uint64 x) { return 0xFFFFFFFF80000000ULL <= x || x <= 0x7FFFFFFFU; } + +inline uint32 VerifyInInt32(uint64 x) +{ +#ifdef XBYAK64 + if (!IsInInt32(x)) throw ERR_OFFSET_IS_TOO_BIG; +#endif + return static_cast(x); +} } @@ -414,27 +431,13 @@ class CodeArray { ALIGN_PAGE_SIZE = 4096, MAX_FIXED_BUF_SIZE = 8 }; - void operator=(const CodeArray&); - void resize(size_t newSize) - { - uint8 *newAllocPtr = reinterpret_cast(alloc_->alloc(newSize + ALIGN_PAGE_SIZE)); - if (newAllocPtr == 0) throw ERR_CANT_ALLOC; - uint8 *newTop = getAlignedAddress(newAllocPtr, ALIGN_PAGE_SIZE); - for (size_t i = 0; i < size_; i++) newTop[i] = top_[i]; - alloc_->free(allocPtr_); - allocPtr_ = newAllocPtr; - top_ = newTop; - maxSize_ = newSize; - } -protected: enum Type { FIXED_BUF, // use buf_(non alignment, non protect) USER_BUF, // use userPtr(non alignment, non protect) ALLOC_BUF, // use new(alignment, protect) AUTO_GROW // automatically move and grow memory if necessary }; - bool isAutoGrow() const { return type_ == AUTO_GROW; } -private: + void operator=(const CodeArray&); bool isAllocType() const { return type_ == ALLOC_BUF || type_ == AUTO_GROW; } Type getType(size_t maxSize, void *userPtr) const { @@ -442,6 +445,16 @@ private: if (maxSize <= MAX_FIXED_BUF_SIZE) return FIXED_BUF; return ALLOC_BUF; } + struct AddrInfo { + size_t offset_; + size_t val_; + int size_; + bool isRelative_; + AddrInfo(size_t offset, size_t val, int size, bool isRelative) + : offset_(offset), val_(val), size_(size), isRelative_(isRelative) {} + }; + typedef std::list AddrInfoList; + AddrInfoList addrInfoList_; const Type type_; Allocator defaultAllocator_; Allocator *alloc_; @@ -451,6 +464,34 @@ protected: size_t maxSize_; uint8 *top_; size_t size_; + + /* + allocate new memory and copy old data to the new area + */ + void growMemory() + { + const size_t newSize = maxSize_ + ALIGN_PAGE_SIZE; + uint8 *newAllocPtr = reinterpret_cast(alloc_->alloc(newSize + ALIGN_PAGE_SIZE)); + if (newAllocPtr == 0) throw ERR_CANT_ALLOC; + uint8 *newTop = getAlignedAddress(newAllocPtr, ALIGN_PAGE_SIZE); + for (size_t i = 0; i < size_; i++) newTop[i] = top_[i]; + alloc_->free(allocPtr_); + allocPtr_ = newAllocPtr; + top_ = newTop; + maxSize_ = newSize; + } + /* + calc jmp address for AutoGrow mode + */ + void calcJmpAddress() + { + for (AddrInfoList::const_iterator i = addrInfoList_.begin(), ie = addrInfoList_.end(); i != ie; ++i) { +// uint32 disp = inner::GetOffsetDist(i->val_, i->isRelative_ ? 0 : size_t(top_)); + uint32 disp = inner::VerifyInInt32(i->isRelative_ ? i->val_ : i->val_ - size_t(top_)); + rewrite(i->offset_, disp, i->size_); + } + if (!protect(top_, size_, true)) throw ERR_CANT_PROTECT; + } public: CodeArray(size_t maxSize = MAX_FIXED_BUF_SIZE, void *userPtr = 0, Allocator *allocator = 0) : type_(getType(maxSize, userPtr)) @@ -461,7 +502,7 @@ public: , size_(0) { if (maxSize_ > 0 && top_ == 0) throw ERR_CANT_ALLOC; - if (type_ == ALLOC_BUF && !protect(top_, maxSize, ReadWriteExecMode)) { + if (type_ == ALLOC_BUF && !protect(top_, maxSize, true)) { alloc_->free(allocPtr_); throw ERR_CANT_PROTECT; } @@ -469,7 +510,7 @@ public: virtual ~CodeArray() { if (isAllocType()) { - protect(top_, maxSize_, ReadWriteMode); + protect(top_, maxSize_, false); alloc_->free(allocPtr_); } } @@ -488,7 +529,7 @@ public: { if (size_ >= maxSize_) { if (type_ == AUTO_GROW) { - resize(maxSize_ + ALIGN_PAGE_SIZE); + growMemory(); } else { throw ERR_CODE_IS_TOO_BIG; } @@ -532,17 +573,24 @@ public: } } /* - @param data [in] address of jmp data + @param offset [in] offset from top @param disp [in] offset from the next of jmp @param size [in] write size(1, 2, 4, 8) */ - void rewrite(uint8 *data, uint64 disp, size_t size) + void rewrite(size_t offset, uint64 disp, size_t size) { + assert(offset < maxSize_); if (size != 1 && size != 2 && size != 4 && size != 8) throw ERR_BAD_PARAMETER; + uint8 *const data = top_ + offset; for (size_t i = 0; i < size; i++) { data[i] = static_cast(disp >> (i * 8)); } } + void save(size_t offset, size_t val, int size, bool isRelative) + { + addrInfoList_.push_back(AddrInfo(offset, val, size, isRelative)); + } + bool isAutoGrow() const { return type_ == AUTO_GROW; } void updateRegField(uint8 regIdx) const { *top_ = (*top_ & B11000111) | ((regIdx << 3) & B00111000); @@ -551,48 +599,19 @@ public: change exec permission of memory @param addr [in] buffer address @param size [in] buffer size - @param protectMode [in] 0:(write) 1:(write+exec) 2:(exec) + @param canExec [in] true(enable to exec), false(disable to exec) @return true(success), false(failure) */ - static const int ReadWriteMode = 0; - static const int ReadWriteExecMode = 1; - static const int ReadExecMode = 2; - static inline bool protect(const void *addr, size_t size, int protectMode) + static inline bool protect(const void *addr, size_t size, bool canExec) { #if defined(_WIN32) - DWORD oldProtect, mode; - switch (protectMode) { - case ReadWriteMode: - mode = PAGE_READWRITE; - break; - case ReadWriteExecMode: - mode = PAGE_EXECUTE_READWRITE; - break; - case ReadExecMode: - mode = PAGE_EXECUTE_READ; - break; - default: - throw ERR_BAD_PROTECT_MODE; - } - return VirtualProtect(const_cast(addr), size, mode, &oldProtect) != 0; + DWORD oldProtect; + return VirtualProtect(const_cast(addr), size, canExec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldProtect) != 0; #elif defined(__GNUC__) size_t pageSize = sysconf(_SC_PAGESIZE); size_t iaddr = reinterpret_cast(addr); size_t roundAddr = iaddr & ~(pageSize - static_cast(1)); - int mode; - switch (protectMode) { - case ReadWriteMode: - mode = PROT_READ | PROT_WRITE; - break; - case ReadWriteExecMode: - mode = PROT_READ | PROT_WRITE | PROT_EXEC; - break; - case ReadExecMode: - mode = PROT_READ | PROT_EXEC; - break; - default: - throw ERR_BAD_PROTECT_MODE; - } + int mode = PROT_READ | PROT_WRITE | (canExec ? PROT_EXEC : 0); return mprotect(reinterpret_cast(roundAddr), size + (iaddr - roundAddr), mode) == 0; #else return true; @@ -705,7 +724,7 @@ public: }; struct JmpLabel { - uint8 *endOfJmp; /* end address of jmp */ + size_t endOfJmp; /* offset from top to the end address of jmp */ bool isShort; }; @@ -719,7 +738,7 @@ class Label { int stackPos_; int usedCount_; int localCount_; // for .*** - typedef std::map DefinedList; + typedef std::map DefinedList; typedef std::multimap UndefinedList; DefinedList definedList_; UndefinedList undefinedList_; @@ -762,7 +781,7 @@ public: localCount_ = stack_[--stackPos_ - 1]; } void set(CodeArray *base) { base_ = base; } - void define(const char *label, const uint8 *address) + void define(const char *label, size_t addr) { std::string newLabel(label); if (newLabel == "@@") { @@ -772,7 +791,7 @@ public: } label = newLabel.c_str(); // add label - DefinedList::value_type item(label, address); + DefinedList::value_type item(label, addr); std::pair ret = definedList_.insert(item); if (!ret.second) throw ERR_LABEL_IS_REDEFINED; // search undefined label @@ -780,22 +799,27 @@ public: UndefinedList::iterator itr = undefinedList_.find(label); if (itr == undefinedList_.end()) break; const JmpLabel *jmp = &itr->second; - uint32 disp = inner::GetPtrDist(address, jmp->endOfJmp); + uint32 disp = inner::VerifyInInt32(addr - jmp->endOfJmp); if (jmp->isShort && !inner::IsInDisp8(disp)) throw ERR_LABEL_IS_TOO_FAR; - size_t jmpSize = jmp->isShort ? 1 : 4; - uint8 *data = jmp->endOfJmp - jmpSize; - base_->rewrite(data, disp, jmpSize); + int jmpSize = jmp->isShort ? 1 : 4; + size_t offset = jmp->endOfJmp - jmpSize; + if (base_->isAutoGrow()) { + base_->save(offset, disp, jmpSize, true); + } else { + base_->rewrite(offset, disp, jmpSize); + } undefinedList_.erase(itr); } } - const uint8 *getAddress(const char *label) const + bool getOffset(size_t *offset, const char *label) const { std::string newLabel = convertLabel(label); DefinedList::const_iterator itr = definedList_.find(newLabel); if (itr != definedList_.end()) { - return itr->second; + *offset = itr->second; + return true; } else { - return 0; + return false; } } void addUndefinedLabel(const char *label, const JmpLabel& jmp) @@ -816,11 +840,7 @@ public: { char buf[16]; #ifdef _WIN32 - #if _MSC_VER < 1400 - _snprintf - #else - _snprintf_s - #endif + _snprintf_s #else snprintf #endif @@ -929,64 +949,51 @@ private: addr.updateRegField(static_cast(reg.getIdx())); db(addr.getCode(), static_cast(addr.getSize())); } - void opJmpL(const char *label, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref) + void makeJmp(uint32 disp, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref) { - const uint8 *address = label_.getAddress(label); - if (address) { /* label exists */ - opJmp(address, type, shortCode, longCode, longPref, true); - } else { - const int shortHeaderSize = 1; - const int shortJmpSize = shortHeaderSize + 1; /* +1 means 8-bit displacement */ - const int longHeaderSize = longPref ? 2 : 1; - const int longJmpSize = longHeaderSize + 4; /* +4 means 32-bit displacement */ - uint8 *top = const_cast(getCurr()); - bool isShort = (type != T_NEAR); - JmpLabel jmp; - jmp.endOfJmp = top + (isShort ? shortJmpSize : longJmpSize); - jmp.isShort = isShort; - if (isShort) { - db(shortCode); - db(0); - } else { - if (longPref) db(longPref); - db(longCode); - dd(0); - } - label_.addUndefinedLabel(label, jmp); - } - } - struct AddrInfo { - size_t offset_; - const uint8 *addr_; - AddrInfo(size_t offset, const uint8 *addr) : offset_(offset), addr_(addr) {} - }; - typedef std::list AddrInfoList; - AddrInfoList addrInfoList_; - void opJmp(const void *addr, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref, bool isLabel = false) - { - bool isAuto = !isLabel && isAutoGrow(); - if (isAuto && type != T_NEAR) throw ERR_ONLY_T_NEAR_IS_SUPPORTED_IN_AUTO_GROW; - const int shortHeaderSize = 1; - const int shortJmpSize = shortHeaderSize + 1; /* +1 means 8-bit displacement */ + const int shortJmpSize = 2; const int longHeaderSize = longPref ? 2 : 1; - const int longJmpSize = longHeaderSize + 4; /* +4 means 32-bit displacement */ - - uint32 disp = inner::GetPtrDist(addr, getCurr()); + const int longJmpSize = longHeaderSize + 4; if (type != T_NEAR && inner::IsInDisp8(disp - shortJmpSize)) { - db(shortCode); - db(disp - shortJmpSize); + db(shortCode); db(disp - shortJmpSize); } else { if (type == T_SHORT) throw ERR_LABEL_IS_TOO_FAR; if (longPref) db(longPref); - db(longCode); - if (isAuto) { - addrInfoList_.push_back(AddrInfo(size_, reinterpret_cast(addr) - longJmpSize + 1)); - dd(0); - } else { - dd(disp - longJmpSize); - } + db(longCode); dd(disp - longJmpSize); } } + void opJmp(const char *label, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref) + { + if (isAutoGrow() && size_ + 16 >= maxSize_) growMemory(); /* avoid splitting code of jmp */ + size_t offset = 0; + if (label_.getOffset(&offset, label)) { /* label exists */ + makeJmp(inner::VerifyInInt32(offset - getSize()), type, shortCode, longCode, longPref); + } else { + JmpLabel jmp; + jmp.isShort = (type != T_NEAR); + if (jmp.isShort) { + db(shortCode); db(0); + } else { + if (longPref) db(longPref); + db(longCode); dd(0); + } + jmp.endOfJmp = getSize(); + label_.addUndefinedLabel(label, jmp); + } + } + void opJmpAbs(const void *addr, LabelType type, uint8 shortCode, uint8 longCode) + { + if (isAutoGrow()) { + if (type != T_NEAR) throw ERR_ONLY_T_NEAR_IS_SUPPORTED_IN_AUTO_GROW; + if (size_ + 16 >= maxSize_) growMemory(); + db(longCode); + save(size_, size_t(addr) - (getSize() + 4), 4, false); + dd(0); + } else { + makeJmp(inner::VerifyInInt32(reinterpret_cast(addr) - getCurr()), type, shortCode, longCode, 0); + } + + } /* preCode is for SSSE3/SSE4 */ void opGen(const Operand& reg, const Operand& op, int code, int pref, bool isValid(const Operand&, const Operand&), int imm8 = NONE, int preCode = NONE) { @@ -1186,17 +1193,17 @@ public: void L(const char *label) { - label_.define(label, getCurr()); + label_.define(label, getSize()); } void inLocalLabel() { label_.enterLocal(); } void outLocalLabel() { label_.leaveLocal(); } void jmp(const char *label, LabelType type = T_AUTO) { - opJmpL(label, type, B11101011, B11101001, 0); + opJmp(label, type, B11101011, B11101001, 0); } void jmp(const void *addr, LabelType type = T_AUTO) { - opJmp(addr, type, B11101011, B11101001, 0); + opJmpAbs(addr, type, B11101011, B11101001); } void jmp(const Operand& op) { @@ -1371,11 +1378,11 @@ public: } void call(const char *label) { - opJmpL(label, T_NEAR, 0, B11101000, 0); + opJmp(label, T_NEAR, 0, B11101000, 0); } void call(const void *addr) { - opJmp(addr, T_NEAR, 0, B11101000, 0); + opJmpAbs(addr, T_NEAR, 0, B11101000); } // special case void movd(const Address& addr, const Mmx& mmx) @@ -1545,8 +1552,8 @@ public: } enum { NONE = 256 }; public: - CodeGenerator(size_t maxSize = DEFAULT_MAX_CODE_SIZE, void *userPtr = 0) - : CodeArray(maxSize, userPtr) + CodeGenerator(size_t maxSize = DEFAULT_MAX_CODE_SIZE, void *userPtr = 0, Allocator *allocator = 0) + : CodeArray(maxSize, userPtr, allocator) , mm0(0), mm1(1), mm2(2), mm3(3), mm4(4), mm5(5), mm6(6), mm7(7) , xmm0(0), xmm1(1), xmm2(2), xmm3(3), xmm4(4), xmm5(5), xmm6(6), xmm7(7) , ymm0(0), ymm1(1), ymm2(2), ymm3(3), ymm4(4), ymm5(5), ymm6(6), ymm7(7) @@ -1573,21 +1580,13 @@ public: label_.set(this); } bool hasUndefinedLabel() const { return label_.hasUndefinedLabel(); } - const uint8 *getCode() const - { - assert(!hasUndefinedLabel()); - return top_; - } /* call ready() to complete generating code on AutoGrow */ void ready() { if (hasUndefinedLabel()) throw ERR_LABEL_IS_NOT_FOUND; - for (AddrInfoList::const_iterator i = addrInfoList_.begin(), ie = addrInfoList_.end(); i != ie; ++i) { - rewrite(top_ + i->offset_, (uint32)(i->addr_ - (top_ + i->offset_)), 4); - } - if (!protect(top_, size_, ReadWriteExecMode)) throw ERR_CANT_PROTECT; + calcJmpAddress(); } #ifdef XBYAK_TEST void dump(bool doClear = true) diff --git a/xbyak/xbyak_mnemonic.h b/xbyak/xbyak_mnemonic.h index 153d7a3..9b4eccd 100644 --- a/xbyak/xbyak_mnemonic.h +++ b/xbyak/xbyak_mnemonic.h @@ -1,4 +1,4 @@ -const char *getVersionString() const { return "3.06"; } +const char *getVersionString() const { return "3.50"; } void packssdw(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x6B); } void packsswb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x63); } void packuswb(const Mmx& mmx, const Operand& op) { opMMX(mmx, op, 0x67); } @@ -183,94 +183,94 @@ void movlps(const Operand& op1, const Operand& op2) { opMovXMM(op1, op2, 0x12, 0 void movhpd(const Operand& op1, const Operand& op2) { opMovXMM(op1, op2, 0x16, 0x66); } void movlpd(const Operand& op1, const Operand& op2) { opMovXMM(op1, op2, 0x12, 0x66); } void cmovo(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 0); } -void jo(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x70, 0x80, 0x0F); } +void jo(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x70, 0x80, 0x0F); } void seto(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 0); } void cmovno(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 1); } -void jno(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x71, 0x81, 0x0F); } +void jno(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x71, 0x81, 0x0F); } void setno(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 1); } void cmovb(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 2); } -void jb(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x72, 0x82, 0x0F); } +void jb(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x72, 0x82, 0x0F); } void setb(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 2); } void cmovc(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 2); } -void jc(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x72, 0x82, 0x0F); } +void jc(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x72, 0x82, 0x0F); } void setc(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 2); } void cmovnae(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 2); } -void jnae(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x72, 0x82, 0x0F); } +void jnae(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x72, 0x82, 0x0F); } void setnae(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 2); } void cmovnb(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 3); } -void jnb(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x73, 0x83, 0x0F); } +void jnb(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x73, 0x83, 0x0F); } void setnb(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 3); } void cmovae(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 3); } -void jae(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x73, 0x83, 0x0F); } +void jae(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x73, 0x83, 0x0F); } void setae(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 3); } void cmovnc(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 3); } -void jnc(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x73, 0x83, 0x0F); } +void jnc(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x73, 0x83, 0x0F); } void setnc(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 3); } void cmove(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 4); } -void je(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x74, 0x84, 0x0F); } +void je(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x74, 0x84, 0x0F); } void sete(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 4); } void cmovz(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 4); } -void jz(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x74, 0x84, 0x0F); } +void jz(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x74, 0x84, 0x0F); } void setz(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 4); } void cmovne(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 5); } -void jne(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x75, 0x85, 0x0F); } +void jne(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x75, 0x85, 0x0F); } void setne(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 5); } void cmovnz(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 5); } -void jnz(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x75, 0x85, 0x0F); } +void jnz(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x75, 0x85, 0x0F); } void setnz(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 5); } void cmovbe(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 6); } -void jbe(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x76, 0x86, 0x0F); } +void jbe(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x76, 0x86, 0x0F); } void setbe(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 6); } void cmovna(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 6); } -void jna(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x76, 0x86, 0x0F); } +void jna(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x76, 0x86, 0x0F); } void setna(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 6); } void cmovnbe(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 7); } -void jnbe(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x77, 0x87, 0x0F); } +void jnbe(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x77, 0x87, 0x0F); } void setnbe(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 7); } void cmova(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 7); } -void ja(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x77, 0x87, 0x0F); } +void ja(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x77, 0x87, 0x0F); } void seta(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 7); } void cmovs(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 8); } -void js(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x78, 0x88, 0x0F); } +void js(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x78, 0x88, 0x0F); } void sets(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 8); } void cmovns(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 9); } -void jns(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x79, 0x89, 0x0F); } +void jns(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x79, 0x89, 0x0F); } void setns(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 9); } void cmovp(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 10); } -void jp(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7A, 0x8A, 0x0F); } +void jp(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7A, 0x8A, 0x0F); } void setp(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 10); } void cmovpe(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 10); } -void jpe(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7A, 0x8A, 0x0F); } +void jpe(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7A, 0x8A, 0x0F); } void setpe(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 10); } void cmovnp(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 11); } -void jnp(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7B, 0x8B, 0x0F); } +void jnp(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7B, 0x8B, 0x0F); } void setnp(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 11); } void cmovpo(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 11); } -void jpo(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7B, 0x8B, 0x0F); } +void jpo(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7B, 0x8B, 0x0F); } void setpo(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 11); } void cmovl(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 12); } -void jl(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7C, 0x8C, 0x0F); } +void jl(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7C, 0x8C, 0x0F); } void setl(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 12); } void cmovnge(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 12); } -void jnge(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7C, 0x8C, 0x0F); } +void jnge(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7C, 0x8C, 0x0F); } void setnge(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 12); } void cmovnl(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 13); } -void jnl(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7D, 0x8D, 0x0F); } +void jnl(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7D, 0x8D, 0x0F); } void setnl(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 13); } void cmovge(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 13); } -void jge(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7D, 0x8D, 0x0F); } +void jge(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7D, 0x8D, 0x0F); } void setge(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 13); } void cmovle(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 14); } -void jle(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7E, 0x8E, 0x0F); } +void jle(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7E, 0x8E, 0x0F); } void setle(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 14); } void cmovng(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 14); } -void jng(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7E, 0x8E, 0x0F); } +void jng(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7E, 0x8E, 0x0F); } void setng(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 14); } void cmovnle(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 15); } -void jnle(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7F, 0x8F, 0x0F); } +void jnle(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7F, 0x8F, 0x0F); } void setnle(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 15); } void cmovg(const Reg32e& reg, const Operand& op) { opModRM(reg, op, op.isREG(i32e), op.isMEM(), 0x0F, B01000000 | 15); } -void jg(const char *label, LabelType type = T_AUTO) { opJmpL(label, type, 0x7F, 0x8F, 0x0F); } +void jg(const char *label, LabelType type = T_AUTO) { opJmp(label, type, 0x7F, 0x8F, 0x0F); } void setg(const Operand& op) { opR_ModM(op, 8, 0, 0x0F, B10010000 | 15); } #ifdef XBYAK64 void cdqe() { db(0x48); db(0x98); }