Xbyak ver 3.50

This commit is contained in:
MITSUNARI Shigeo 2012-03-20 00:07:29 +09:00
parent f4f84a65aa
commit 683f7448ae
9 changed files with 717 additions and 215 deletions

View file

@ -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);
}
}

View file

@ -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(<default memory size>, 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 $

View file

@ -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(<default memory size>, 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)

View file

@ -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

View file

@ -1,11 +1,16 @@
#include <stdio.h>
#include <string.h>
#include "xbyak/xbyak.h"
#include <string>
#include <xbyak/xbyak.h>
#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 <res 0000007E> dummyX1 resb 126
6 00000080 EB80 jmp f1
7
8 f2:
9 00000082 <res 0000007F> dummyX2 resb 127
11 00000101 E97CFFFFFF jmp f2
12
13
14 00000106 EB7F jmp f3
15 00000108 <res 0000007F> dummyX3 resb 127
17 f3:
18
19 00000187 E980000000 jmp f4
20 0000018C <res 00000080> 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 (...) {

20
test/jmp.sln Normal file
View file

@ -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

195
test/jmp.vcproj Normal file
View file

@ -0,0 +1,195 @@
<?xml version="1.0" encoding="shift_jis"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="jmp"
ProjectGUID="{AC0B3317-E988-44F8-954A-BCBE4B3BB2BF}"
RootNamespace="jmp"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="$(SolutionDir)/../"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="$(SolutionDir)/../"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="ソース ファイル"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\jmp.cpp"
>
</File>
</Filter>
<Filter
Name="ヘッダー ファイル"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="リソース ファイル"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -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<const char *>(p1) - static_cast<const char *>(p2);
#ifdef XBYAK64
@ -168,8 +167,26 @@ static inline uint32 GetPtrDist(const void *p1, const void *p2)
return static_cast<uint32>(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<uint32>(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<uint32>(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<uint8*>(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<AddrInfo> 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<uint8*>(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<uint8>(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<void*>(addr), size, mode, &oldProtect) != 0;
DWORD oldProtect;
return VirtualProtect(const_cast<void*>(addr), size, canExec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldProtect) != 0;
#elif defined(__GNUC__)
size_t pageSize = sysconf(_SC_PAGESIZE);
size_t iaddr = reinterpret_cast<size_t>(addr);
size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(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<void*>(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<const std::string, const uint8*> DefinedList;
typedef std::map<const std::string, size_t> DefinedList;
typedef std::multimap<const std::string, const JmpLabel> 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<DefinedList::iterator, bool> 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
#else
snprintf
#endif
@ -929,63 +949,50 @@ private:
addr.updateRegField(static_cast<uint8>(reg.getIdx()));
db(addr.getCode(), static_cast<int>(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 shortJmpSize = 2;
const int longHeaderSize = longPref ? 2 : 1;
const int longJmpSize = longHeaderSize + 4; /* +4 means 32-bit displacement */
uint8 *top = const_cast<uint8*>(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<AddrInfo> 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 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); 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);
if (isAuto) {
addrInfoList_.push_back(AddrInfo(size_, reinterpret_cast<const uint8*>(addr) - longJmpSize + 1));
save(size_, size_t(addr) - (getSize() + 4), 4, false);
dd(0);
} else {
dd(disp - longJmpSize);
}
makeJmp(inner::VerifyInInt32(reinterpret_cast<const uint8*>(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)

View file

@ -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); }