diff --git a/readme.md b/readme.md index 8a7f0a3..c4d8871 100644 --- a/readme.md +++ b/readme.md @@ -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. diff --git a/test/jmp.cpp b/test/jmp.cpp index a9076c3..67882c7 100644 --- a/test/jmp.cpp +++ b/test/jmp.cpp @@ -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); } diff --git a/test/make_nm.cpp b/test/make_nm.cpp index f0503e6..2dda03e 100644 --- a/test/make_nm.cpp +++ b/test/make_nm.cpp @@ -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 diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h index 03be278..51c54f2 100644 --- a/xbyak/xbyak.h +++ b/xbyak/xbyak.h @@ -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)); }