mirror of
https://github.com/herumi/xbyak
synced 2024-11-20 16:06:14 -07:00
Xbyak ver 3.50
This commit is contained in:
parent
f4f84a65aa
commit
683f7448ae
9 changed files with 717 additions and 215 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
27
readme.md
27
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(<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 $
|
||||
|
|
31
readme.txt
31
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(<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)
|
||||
|
|
|
@ -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
|
||||
|
|
293
test/jmp.cpp
293
test/jmp.cpp
|
@ -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
20
test/jmp.sln
Normal 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
195
test/jmp.vcproj
Normal 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>
|
279
xbyak/xbyak.h
279
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<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)
|
||||
|
|
|
@ -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); }
|
||||
|
|
Loading…
Reference in a new issue