#include #include #include #include #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 Xbyak::CodeGenerator { void putNop(int n) { for (int i = 0; i < n; i++) { nop(); } } /* 4 X0: 5 00000004 EBFE jmp short X0 6 7 X1: 8 00000006 dummyX1 resb 1 9 00000007 EBFD jmp short X1 10 11 X126: 12 00000009 dummyX126 resb 126 13 00000087 EB80 jmp short X126 14 15 X127: 16 00000089 dummyX127 resb 127 17 00000108 E97CFFFFFF jmp near X127 18 19 0000010D EB00 jmp short Y0 20 Y0: 21 22 0000010F EB01 jmp short Y1 23 00000111 dummyY1 resb 1 24 Y1: 25 26 00000112 EB7F jmp short Y127 27 00000114 dummyY127 resb 127 28 Y127: 29 30 00000193 E980000000 jmp near Y128 31 00000198 dummyY128 resb 128 32 Y128: */ TestJmp(int offset, bool isBack, bool isShort) { if (isBack) { L("@@"); putNop(offset); jmp("@b"); } else { if (isShort) { jmp("@f"); } else { jmp("@f", T_NEAR); } putNop(offset); L("@@"); } } }; void test1() { static const struct Tbl { int offset; bool isBack; bool isShort; uint8 result[6]; int size; } tbl[] = { { 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(); if (p->isBack) q += p->offset; /* skip nop */ 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]); } } } 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 dummyX1 resb 126 6 00000080 EB80 jmp f1 7 8 f2: 9 00000082 dummyX2 resb 127 11 00000101 E97CFFFFFF jmp f2 12 13 14 00000106 EB7F jmp f3 15 00000108 dummyX3 resb 127 17 f3: 18 19 00000187 E980000000 jmp f4 20 0000018C 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 { 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; } struct Grow : Xbyak::CodeGenerator { Grow(int dummySize) : Xbyak::CodeGenerator(128, Xbyak::AutoGrow) { mov(eax, 100); push(eax); call((void*)add5); add(esp, 4); push(eax); call((void*)add2); add(esp, 4); ret(); for (int i = 0; i < dummySize; i++) { db(0); } } }; void test3() { for (int dummySize = 0; dummySize < 40000; dummySize += 10000) { printf("dummySize=%d\n", dummySize); Grow g(dummySize); g.ready(); int (*f)() = (int (*)())g.getCode(); int x = f(); const int ok = 107; if (x != ok) { printf("err %d assume %d\n", x, ok); } else { printf("ok\n"); } } } #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 (...) { printf("unknown error\n"); } }