add setDefaultJmpNEAR

This commit is contained in:
MITSUNARI Shigeo 2019-12-18 19:15:34 +09:00
parent da7f731707
commit 4da8fd4e6d
5 changed files with 114 additions and 6 deletions

View file

@ -1,5 +1,5 @@
# Xbyak 5.86 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++
# Xbyak 5.87 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++
## Abstract
@ -216,6 +216,32 @@ void func1()
}
```
### short and long jump
Xbyak deals with jump mnemonics of an undefined label as short jump if no type is specified.
So if the size between jmp and label is larger than 127 byte, then xbyak will cause an error.
```
jmp("short-jmp"); // short jmp
// small code
L("short-jmp");
jmp("long-jmp");
// long code
L("long-jmp"); // throw exception
```
Then specify T_NEAR for jmp.
```
jmp("long-jmp", T_NEAR); // long jmp
// long code
L("long-jmp");
```
Or call `setDefaultJmpNEAR(true);` once, then the default type is set to T_NEAR.
```
jmp("long-jmp"); // long jmp
// long code
L("long-jmp");
```
### Label class
`L()` and `jxx()` support Label class.
@ -396,6 +422,7 @@ modified new BSD License
http://opensource.org/licenses/BSD-3-Clause
## History
* 2019/Dec/19 ver 5.87 add setDefaultJmpNEAR(), which deals with `jmp` of an undefined label as T_NEAR if no type is specified.
* 2019/Dec/13 ver 5.86 [changed] revert to the behavior before v5.84 if -fno-operator-names is defined (and() is available)
* 2019/Dec/07 ver 5.85 append MAP_JIT flag to mmap for macOS mojave or later
* 2019/Nov/29 ver 5.84 [changed] XBYAK_NO_OP_NAMES is defined unless XBYAK_USE_OP_NAMES is defined

View file

@ -1,5 +1,5 @@
C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.86
C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.87
-----------------------------------------------------------------------------
◎概要
@ -371,6 +371,7 @@ sample/{echo,hello}.bfは http://www.kmonos.net/alang/etc/brainfuck.php から
-----------------------------------------------------------------------------
◎履歴
2019/12/19 ver 5.87 未定義ラベルへのjmp命令のデフォルト挙動をT_NEARにするsetDefaultJmpNEAR()を追加
2019/12/13 ver 5.86 [変更] -fno-operator-namesが指定されたときは5.84以前の挙動に戻す
2019/12/07 ver 5.85 mmapにMAP_JITフラグを追加(macOS mojave以上)
2019/11/29 ver 5.84 [変更] XBYAK_USE_OP_NAMESが定義されていない限りXBYAK_NO_OP_NAMESが定義されるように変更

View file

@ -1305,3 +1305,76 @@ CYBOZU_TEST_AUTO(release_label_after_code)
printf("id=%d %d %d %d %d\n", L1.getId(), L2.getId(), L3.getId(), L4.getId(), L5.getId());
}
}
struct JmpTypeCode : Xbyak::CodeGenerator {
void nops()
{
for (int i = 0; i < 130; i++) {
nop();
}
}
// return jmp code size
size_t gen(bool pre, bool large, Xbyak::CodeGenerator::LabelType type)
{
Label label;
if (pre) {
L(label);
if (large) nops();
size_t pos = getSize();
jmp(label, type);
return getSize() - pos;
} else {
size_t pos = getSize();
jmp(label, type);
size_t size = getSize() - pos;
if (large) nops();
L(label);
return size;
}
}
};
CYBOZU_TEST_AUTO(setDefaultJmpNEAR)
{
const Xbyak::CodeGenerator::LabelType T_SHORT = Xbyak::CodeGenerator::T_SHORT;
const Xbyak::CodeGenerator::LabelType T_NEAR = Xbyak::CodeGenerator::T_NEAR;
const Xbyak::CodeGenerator::LabelType T_AUTO = Xbyak::CodeGenerator::T_AUTO;
const struct {
bool pre;
bool large;
Xbyak::CodeGenerator::LabelType type;
size_t expect1; // 0 means exception
size_t expect2;
} tbl[] = {
{ false, false, T_SHORT, 2, 2 },
{ false, false, T_NEAR, 5, 5 },
{ false, true, T_SHORT, 0, 0 },
{ false, true, T_NEAR, 5, 5 },
{ true, false, T_SHORT, 2, 2 },
{ true, false, T_NEAR, 5, 5 },
{ true, true, T_SHORT, 0, 0 },
{ true, true, T_NEAR, 5, 5 },
{ false, false, T_AUTO, 2, 5 },
{ false, true, T_AUTO, 0, 5 },
{ true, false, T_AUTO, 2, 2 },
{ true, true, T_AUTO, 5, 5 },
};
JmpTypeCode code1, code2;
code2.setDefaultJmpNEAR(true);
for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
if (tbl[i].expect1) {
size_t size = code1.gen(tbl[i].pre, tbl[i].large, tbl[i].type);
CYBOZU_TEST_EQUAL(size, tbl[i].expect1);
} else {
CYBOZU_TEST_EXCEPTION(code1.gen(tbl[i].pre, tbl[i].large, tbl[i].type), std::exception);
}
if (tbl[i].expect2) {
size_t size = code2.gen(tbl[i].pre, tbl[i].large, tbl[i].type);
CYBOZU_TEST_EQUAL(size, tbl[i].expect2);
} else {
CYBOZU_TEST_EXCEPTION(code2.gen(tbl[i].pre, tbl[i].large, tbl[i].type), std::exception);
}
}
}

View file

@ -115,7 +115,7 @@ namespace Xbyak {
enum {
DEFAULT_MAX_CODE_SIZE = 4096,
VERSION = 0x5860 /* 0xABCD = A.BC(D) */
VERSION = 0x5870 /* 0xABCD = A.BC(D) */
};
#ifndef MIE_INTEGER_TYPE_DEFINED
@ -1775,6 +1775,7 @@ private:
db(longCode); dd(disp - longJmpSize);
}
}
bool isNEAR(LabelType type) const { return type == T_NEAR || (type == T_AUTO && isDefaultJmpNEAR_); }
template<class T>
void opJmp(T& label, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref)
{
@ -1784,7 +1785,7 @@ private:
makeJmp(inner::VerifyInInt32(offset - size_), type, shortCode, longCode, longPref);
} else {
int jmpSize = 0;
if (type == T_NEAR) {
if (isNEAR(type)) {
jmpSize = 4;
if (longPref) db(longPref);
db(longCode); dd(0);
@ -1799,7 +1800,7 @@ private:
void opJmpAbs(const void *addr, LabelType type, uint8 shortCode, uint8 longCode, uint8 longPref = 0)
{
if (isAutoGrow()) {
if (type != T_NEAR) throw Error(ERR_ONLY_T_NEAR_IS_SUPPORTED_IN_AUTO_GROW);
if (!isNEAR(type)) throw Error(ERR_ONLY_T_NEAR_IS_SUPPORTED_IN_AUTO_GROW);
if (size_ + 16 >= maxSize_) growMemory();
if (longPref) db(longPref);
db(longCode);
@ -2293,6 +2294,9 @@ public:
#ifndef XBYAK_DISABLE_SEGMENT
const Segment es, cs, ss, ds, fs, gs;
#endif
private:
bool isDefaultJmpNEAR_;
public:
void L(const std::string& label) { labelMgr_.defineSlabel(label); }
void L(Label& label) { labelMgr_.defineClabel(label); }
Label L() { Label label; L(label); return label; }
@ -2312,6 +2316,8 @@ public:
void putL(std::string label) { putL_inner(label); }
void putL(const Label& label) { putL_inner(label); }
// set default type of `jmp` of undefined label to T_NEAR
void setDefaultJmpNEAR(bool near) { isDefaultJmpNEAR_ = near; }
void jmp(const Operand& op) { opR_ModM(op, BIT, 4, 0xFF, NONE, NONE, true); }
void jmp(std::string label, LabelType type = T_AUTO) { opJmp(label, type, 0xEB, 0xE9, 0); }
void jmp(const char *label, LabelType type = T_AUTO) { jmp(std::string(label), type); }
@ -2570,6 +2576,7 @@ public:
#ifndef XBYAK_DISABLE_SEGMENT
, es(Segment::es), cs(Segment::cs), ss(Segment::ss), ds(Segment::ds), fs(Segment::fs), gs(Segment::gs)
#endif
, isDefaultJmpNEAR_(false)
{
labelMgr_.set(this);
}

View file

@ -1,4 +1,4 @@
const char *getVersionString() const { return "5.86"; }
const char *getVersionString() const { return "5.87"; }
void adc(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x10, 2); }
void adc(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x10); }
void adcx(const Reg32e& reg, const Operand& op) { opGen(reg, op, 0xF6, 0x66, isREG32_REG32orMEM, NONE, 0x38); }