support call(mem, T_FAR)

This commit is contained in:
MITSUNARI Shigeo 2021-12-14 12:22:56 +09:00
parent fb158f9014
commit 1abfc3465f
4 changed files with 28 additions and 19 deletions

View file

@ -347,6 +347,7 @@ jmp(word[eax], T_FAR); // jmp m16:16(FF /5)
jmp(dword[rax], T_FAR); // jmp m16:32(FF /5)
jmp(qword[rax], T_FAR); // jmp m16:64(REX.W FF /5)
```
The same applies to `call`.
## Code size
The default max code size is 4096 bytes.

View file

@ -1384,17 +1384,17 @@ CYBOZU_TEST_AUTO(setDefaultJmpNEAR)
}
}
CYBOZU_TEST_AUTO(farJmp)
CYBOZU_TEST_AUTO(ambiguousFarJmp)
{
struct Code : Xbyak::CodeGenerator {
Code()
{
#ifdef XBYAK32
jmp(ptr[eax], T_FAR);
void genJmp() { jmp(ptr[eax], T_FAR); }
void genCall() { call(ptr[eax], T_FAR); }
#else
jmp(ptr[rax], T_FAR);
void genJmp() { jmp(ptr[rax], T_FAR); }
void genCall() { call(ptr[rax], T_FAR); }
#endif
}
};
CYBOZU_TEST_EXCEPTION(Code code, std::exception);
} code;
CYBOZU_TEST_EXCEPTION(code.genJmp(), std::exception);
CYBOZU_TEST_EXCEPTION(code.genCall(), std::exception);
}

View file

@ -707,9 +707,16 @@ class Test {
put("jmp", "word[rax],T_FAR", "far word [rax]");
put("jmp", "dword[rax],T_FAR", "far dword [rax]");
put("jmp", "qword[rax],T_FAR", "far qword [rax]");
put("call", "word[rax],T_FAR", "far word [rax]");
put("call", "dword[rax],T_FAR", "far dword [rax]");
put("call", "qword[rax],T_FAR", "far qword [rax]");
#else
put("jmp", "dword[eax],T_FAR", "far dword [eax]");
put("jmp", "word[eax],T_FAR", "far word [eax]");
put("call", "dword[eax],T_FAR", "far dword [eax]");
put("call", "word[eax],T_FAR", "far word [eax]");
#endif
}
void putMMX1() const

View file

@ -1922,6 +1922,16 @@ private:
}
}
void opJmpOp(const Operand& op, LabelType type, int ext)
{
const int bit = 16|i32e;
if (type == T_FAR) {
if (!op.isMEM(bit)) XBYAK_THROW(ERR_NOT_SUPPORTED)
opR_ModM(op, bit, ext + 1, 0xFF, NONE, NONE, false);
} else {
opR_ModM(op, bit, ext, 0xFF, NONE, NONE, true);
}
}
// reg is reg field of ModRM
// immSize is the size for immediate value
// disp8N = 0(normal), disp8N = 1(force disp32), disp8N = {2, 4, 8} ; compressed displacement
@ -2477,22 +2487,13 @@ public:
// set default type of `jmp` of undefined label to T_NEAR
void setDefaultJmpNEAR(bool isNear) { isDefaultJmpNEAR_ = isNear; }
void jmp(const Operand& op, LabelType type = T_AUTO)
{
if (type == T_FAR) {
const int bit = (BIT == 32) ? (16|32) : (16|32|64);
if (!op.isMEM(bit)) XBYAK_THROW(ERR_NOT_SUPPORTED)
opR_ModM(op, BIT, 5, 0xFF, NONE, NONE, false);
} else {
opR_ModM(op, BIT, 4, 0xFF, NONE, NONE, true);
}
}
void jmp(const Operand& op, LabelType type = T_AUTO) { opJmpOp(op, type, 4); }
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); }
void jmp(const Label& label, LabelType type = T_AUTO) { opJmp(label, type, 0xEB, 0xE9, 0); }
void jmp(const void *addr, LabelType type = T_AUTO) { opJmpAbs(addr, type, 0xEB, 0xE9); }
void call(const Operand& op) { opR_ModM(op, 16 | i32e, 2, 0xFF, NONE, NONE, true); }
void call(const Operand& op, LabelType type = T_AUTO) { opJmpOp(op, type, 2); }
// call(string label), not const std::string&
void call(std::string label) { opJmp(label, T_NEAR, 0, 0xE8, 0); }
void call(const char *label) { call(std::string(label)); }