1 #include <stdio.h>
2 #include <string.h>
3 #include <string>
4 #define XBYAK_NO_OP_NAMES
5 #include <xbyak/xbyak.h>
6 #include <cybozu/inttype.hpp>
7 #include <cybozu/test.hpp>
8 
9 using namespace Xbyak;
10 
putNop(Xbyak::CodeGenerator * gen,int n)11 void putNop(Xbyak::CodeGenerator *gen, int n)
12 {
13 	for (int i = 0; i < n; i++) {
14 		gen->nop();
15 	}
16 }
17 
diff(const std::string & a,const std::string & b)18 void diff(const std::string& a, const std::string& b)
19 {
20 	if (a == b) return;
21 	if (a.size() != b.size()) printf("size diff %d %d\n", (int)a.size(), (int)b.size());
22 	for (size_t i = 0; i < (std::min)(a.size(), b.size()); i++) {
23 		if (a[i] != b[i]) {
24 			printf("diff %d(%04x) %02x %02x\n", (int)i, (int)i, (unsigned char)a[i], (unsigned char)b[i]);
25 		}
26 	}
27 }
28 
dump(const std::string & m)29 void dump(const std::string& m)
30 {
31 	printf("size=%d\n     ", (int)m.size());
32 	for (int i = 0; i < 16; i++) {
33 		printf("%02x ", i);
34 	}
35 	printf("\n     ");
36 	for (int i = 0; i < 16; i++) {
37 		printf("---");
38 	}
39 	printf("\n");
40 	for (size_t i = 0; i < m.size(); i++) {
41 		if ((i % 16) == 0) printf("%04x ", (int)(i / 16));
42 		printf("%02x ", (unsigned char)m[i]);
43 		if ((i % 16) == 15) putchar('\n');
44 	}
45 	putchar('\n');
46 }
47 
CYBOZU_TEST_AUTO(test1)48 CYBOZU_TEST_AUTO(test1)
49 {
50 	struct TestJmp : public Xbyak::CodeGenerator {
51 	/*
52 	     4                                  X0:
53 	     5 00000004 EBFE                    jmp short X0
54 	     6
55 	     7                                  X1:
56 	     8 00000006 <res 00000001>          dummyX1 resb 1
57 	     9 00000007 EBFD                    jmp short X1
58 	    10
59 	    11                                  X126:
60 	    12 00000009 <res 0000007E>          dummyX126 resb 126
61 	    13 00000087 EB80                    jmp short X126
62 	    14
63 	    15                                  X127:
64 	    16 00000089 <res 0000007F>          dummyX127 resb 127
65 	    17 00000108 E97CFFFFFF              jmp near X127
66 	    18
67 	    19 0000010D EB00                    jmp short Y0
68 	    20                                  Y0:
69 	    21
70 	    22 0000010F EB01                    jmp short Y1
71 	    23 00000111 <res 00000001>          dummyY1 resb 1
72 	    24                                  Y1:
73 	    25
74 	    26 00000112 EB7F                    jmp short Y127
75 	    27 00000114 <res 0000007F>          dummyY127 resb 127
76 	    28                                  Y127:
77 	    29
78 	    30 00000193 E980000000              jmp near Y128
79 	    31 00000198 <res 00000080>          dummyY128 resb 128
80 	    32                                  Y128:
81 	*/
82 		TestJmp(int offset, bool isBack, bool isShort, bool useNewLabel)
83 		{
84 			if (useNewLabel) {
85 				Label label;
86 				if (isBack) {
87 					L(label);
88 					putNop(this, offset);
89 					jmp(label);
90 				} else {
91 					if (isShort) {
92 						jmp(label);
93 					} else {
94 						jmp(label, T_NEAR);
95 					}
96 					putNop(this, offset);
97 					L(label);
98 				}
99 			} else {
100 				if (isBack) {
101 					L("@@");
102 					putNop(this, offset);
103 					jmp("@b");
104 				} else {
105 					if (isShort) {
106 						jmp("@f");
107 					} else {
108 						jmp("@f", T_NEAR);
109 					}
110 					putNop(this, offset);
111 					L("@@");
112 				}
113 			}
114 		}
115 	};
116 	static const struct Tbl {
117 		int offset;
118 		bool isBack;
119 		bool isShort;
120 		uint8_t result[6];
121 		int size;
122 	} tbl[] = {
123 		{ 0, true, true, { 0xeb, 0xfe }, 2 },
124 		{ 1, true, true, { 0xeb, 0xfd }, 2 },
125 		{ 126, true, true, { 0xeb, 0x80 }, 2 },
126 		{ 127, true, false, {0xe9, 0x7c, 0xff, 0xff, 0xff }, 5 },
127 		{ 0, false, true, { 0xeb, 0x00 }, 2 },
128 		{ 1, false, true, { 0xeb, 0x01 }, 2 },
129 		{ 127, false, true, { 0xeb, 0x7f }, 2 },
130 		{ 128, false, false, { 0xe9, 0x80, 0x00, 0x00, 0x00 }, 5 },
131 	};
132 	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
133 		const Tbl *p = &tbl[i];
134 		for (int k = 0; k < 2; k++) {
135 			TestJmp jmp(p->offset, p->isBack, p->isShort, k == 0);
136 			const uint8_t *q = (const uint8_t*)jmp.getCode();
137 			if (p->isBack) q += p->offset; /* skip nop */
138 			for (int j = 0; j < p->size; j++) {
139 				CYBOZU_TEST_EQUAL(q[j], p->result[j]);
140 			}
141 		}
142 	}
143 }
144 
CYBOZU_TEST_AUTO(testJmpCx)145 CYBOZU_TEST_AUTO(testJmpCx)
146 {
147 	struct TestJmpCx : public CodeGenerator {
148 		explicit TestJmpCx(void *p, bool useNewLabel)
149 			: Xbyak::CodeGenerator(16, p)
150 		{
151 			if (useNewLabel) {
152 				Label lp;
153 			L(lp);
154 #ifdef XBYAK64
155 				/*
156 					67 E3 FD ; jecxz lp
157 					E3 FB    ; jrcxz lp
158 				*/
159 				jecxz(lp);
160 				jrcxz(lp);
161 #else
162 				/*
163 					E3FE   ; jecxz lp
164 					67E3FB ; jcxz lp
165 				*/
166 				jecxz(lp);
167 				jcxz(lp);
168 #endif
169 			} else {
170 				inLocalLabel();
171 			L(".lp");
172 #ifdef XBYAK64
173 				/*
174 					67 E3 FD ; jecxz lp
175 					E3 FB    ; jrcxz lp
176 				*/
177 				jecxz(".lp");
178 				jrcxz(".lp");
179 #else
180 				/*
181 					E3FE   ; jecxz lp
182 					67E3FB ; jcxz lp
183 				*/
184 				jecxz(".lp");
185 				jcxz(".lp");
186 #endif
187 				outLocalLabel();
188 			}
189 		}
190 	};
191 	const struct {
192 		const char *p;
193 		size_t len;
194 	} tbl = {
195 #ifdef XBYAK64
196 		"\x67\xe3\xfd\xe3\xfb", 5
197 #else
198 		"\xe3\xfe\x67\xe3\xfb", 5
199 #endif
200 	};
201 	for (int j = 0; j < 2; j++) {
202 		char buf[16] = {};
203 		TestJmpCx code(buf, j == 0);
204 		CYBOZU_TEST_EQUAL(memcmp(buf, tbl.p, tbl.len), 0);
205 	}
206 }
207 
CYBOZU_TEST_AUTO(loop)208 CYBOZU_TEST_AUTO(loop)
209 {
210 	const uint8_t ok[] = {
211 		// lp:
212 		0x31, 0xC0, // xor eax, eax
213 		0xE2, 0xFC, // loop lp
214 		0xE0, 0xFA, // loopne lp
215 		0xE1, 0xF8, // loope lp
216 	};
217 	struct Code : CodeGenerator {
218 		Code(bool useLabel)
219 		{
220 			if (useLabel) {
221 				Xbyak::Label lp = L();
222 				xor_(eax, eax);
223 				loop(lp);
224 				loopne(lp);
225 				loope(lp);
226 			} else {
227 				L("@@");
228 				xor_(eax, eax);
229 				loop("@b");
230 				loopne("@b");
231 				loope("@b");
232 			}
233 		}
234 	};
235 	Code code1(false);
236 	CYBOZU_TEST_EQUAL(code1.getSize(), sizeof(ok));
237 	CYBOZU_TEST_EQUAL_ARRAY(code1.getCode(), ok, sizeof(ok));
238 	Code code2(true);
239 	CYBOZU_TEST_EQUAL(code2.getSize(), sizeof(ok));
240 	CYBOZU_TEST_EQUAL_ARRAY(code2.getCode(), ok, sizeof(ok));
241 }
242 
243 #ifdef _MSC_VER
244 	#pragma warning(disable : 4310)
245 #endif
CYBOZU_TEST_AUTO(test2)246 CYBOZU_TEST_AUTO(test2)
247 {
248 	struct TestJmp2 : public CodeGenerator {
249 	/*
250 	  1 00000000 90                      nop
251 	  2 00000001 90                      nop
252 	  3                                  f1:
253 	  4 00000002 <res 0000007E>          dummyX1 resb 126
254 	  6 00000080 EB80                     jmp f1
255 	  7
256 	  8                                  f2:
257 	  9 00000082 <res 0000007F>          dummyX2 resb 127
258 	 11 00000101 E97CFFFFFF               jmp f2
259 	 12
260 	 13
261 	 14 00000106 EB7F                    jmp f3
262 	 15 00000108 <res 0000007F>          dummyX3 resb 127
263 	 17                                  f3:
264 	 18
265 	 19 00000187 E980000000              jmp f4
266 	 20 0000018C <res 00000080>          dummyX4 resb 128
267 	 22                                  f4:
268 	*/
269 		TestJmp2(void *p, bool useNewLabel)
270 			: Xbyak::CodeGenerator(8192, p)
271 		{
272 			if (useNewLabel) {
273 				inLocalLabel();
274 				nop();
275 				nop();
276 			L(".f1");
277 				putNop(this, 126);
278 				jmp(".f1");
279 			L(".f2");
280 				putNop(this, 127);
281 				jmp(".f2", T_NEAR);
282 
283 				jmp(".f3");
284 				putNop(this, 127);
285 			L(".f3");
286 				jmp(".f4", T_NEAR);
287 				putNop(this, 128);
288 			L(".f4");
289 				outLocalLabel();
290 			} else {
291 				nop();
292 				nop();
293 				Label f1, f2, f3, f4;
294 			L(f1);
295 				putNop(this, 126);
296 				jmp(f1);
297 			L(f2);
298 				putNop(this, 127);
299 				jmp(f2, T_NEAR);
300 
301 				jmp(f3);
302 				putNop(this, 127);
303 			L(f3);
304 				jmp(f4, T_NEAR);
305 				putNop(this, 128);
306 			L(f4);
307 			}
308 		}
309 	};
310 
311 	std::string ok;
312 	ok.resize(0x18C + 128, (char)0x90);
313 	ok[0x080] = (char)0xeb;
314 	ok[0x081] = (char)0x80;
315 
316 	ok[0x101] = (char)0xe9;
317 	ok[0x102] = (char)0x7c;
318 	ok[0x103] = (char)0xff;
319 	ok[0x104] = (char)0xff;
320 	ok[0x105] = (char)0xff;
321 
322 	ok[0x106] = (char)0xeb;
323 	ok[0x107] = (char)0x7f;
324 
325 	ok[0x187] = (char)0xe9;
326 	ok[0x188] = (char)0x80;
327 	ok[0x189] = (char)0x00;
328 	ok[0x18a] = (char)0x00;
329 	ok[0x18b] = (char)0x00;
330 	for (int i = 0; i < 2; i++) {
331 		for (int j = 0; j < 2; j++) {
332 			TestJmp2 c(i == 0 ? 0 : Xbyak::AutoGrow, j == 0);
333 			c.ready();
334 			std::string m((const char*)c.getCode(), c.getSize());
335 			CYBOZU_TEST_EQUAL(m, ok);
336 		}
337 	}
338 }
339 
340 #ifdef XBYAK32
add5(int x)341 int add5(int x) { return x + 5; }
add2(int x)342 int add2(int x) { return x + 2; }
343 
CYBOZU_TEST_AUTO(test3)344 CYBOZU_TEST_AUTO(test3)
345 {
346 	struct Grow : Xbyak::CodeGenerator {
347 		Grow(int dummySize)
348 			: Xbyak::CodeGenerator(128, Xbyak::AutoGrow)
349 		{
350 			mov(eax, 100);
351 			push(eax);
352 			call((void*)add5);
353 			add(esp, 4);
354 			push(eax);
355 			call((void*)add2);
356 			add(esp, 4);
357 			ret();
358 			for (int i = 0; i < dummySize; i++) {
359 				db(0);
360 			}
361 		}
362 	};
363 	for (int dummySize = 0; dummySize < 40000; dummySize += 10000) {
364 		printf("dummySize=%d\n", dummySize);
365 		Grow g(dummySize);
366 		g.ready();
367 		int (*f)() = (int (*)())g.getCode();
368 		int x = f();
369 		const int ok = 107;
370 		CYBOZU_TEST_EQUAL(x, ok);
371 	}
372 }
373 #endif
374 
375 uint8_t bufL[4096 * 32];
376 uint8_t bufS[4096 * 2];
377 
378 struct MyAllocator : Xbyak::Allocator {
allocMyAllocator379 	uint8_t *alloc(size_t size)
380 	{
381 		if (size < sizeof(bufS)) {
382 			printf("test use bufS(%d)\n", (int)size);
383 			return bufS;
384 		}
385 		if (size < sizeof(bufL)) {
386 			printf("test use bufL(%d)\n", (int)size);
387 			return bufL;
388 		}
389 		fprintf(stderr, "no memory %d\n", (int)size);
390 		exit(1);
391 	}
freeMyAllocator392 	void free(uint8_t *)
393 	{
394 	}
395 } myAlloc;
396 
CYBOZU_TEST_AUTO(test4)397 CYBOZU_TEST_AUTO(test4)
398 {
399 	struct Test4 : Xbyak::CodeGenerator {
400 		Test4(int size, void *mode, bool useNewLabel)
401 			: CodeGenerator(size, mode)
402 		{
403 			if (useNewLabel) {
404 				Label x;
405 				jmp(x);
406 				putNop(this, 10);
407 			L(x);
408 				ret();
409 			} else {
410 				inLocalLabel();
411 				jmp(".x");
412 				putNop(this, 10);
413 			L(".x");
414 				ret();
415 				outLocalLabel();
416 			}
417 		}
418 	};
419 	for (int i = 0; i < 2; i++) {
420 		const bool useNewLabel = i == 0;
421 		std::string fm, gm;
422 		Test4 fc(1024, 0, useNewLabel);
423 		Test4 gc(5, Xbyak::AutoGrow, !useNewLabel);
424 		gc.ready();
425 		fm.assign((const char*)fc.getCode(), fc.getSize());
426 		gm.assign((const char*)gc.getCode(), gc.getSize());
427 		CYBOZU_TEST_EQUAL(fm, gm);
428 	}
429 }
430 
431 #ifndef __APPLE__
CYBOZU_TEST_AUTO(test5)432 CYBOZU_TEST_AUTO(test5)
433 {
434 	struct Test5 : Xbyak::CodeGenerator {
435 		explicit Test5(int size, int count, void *mode)
436 			: CodeGenerator(size, mode, &myAlloc)
437 		{
438 			using namespace Xbyak;
439 			inLocalLabel();
440 			mov(ecx, count);
441 			xor_(eax, eax);
442 		L(".lp");
443 			for (int i = 0; i < count; i++) {
444 				L(Label::toStr(i));
445 				add(eax, 1);
446 				int to = 0;
447 				if (i < count / 2) {
448 					to = count - 1 - i;
449 				} else {
450 					to = count  - i;
451 				}
452 				if (i == count / 2) {
453 					jmp(".exit", T_NEAR);
454 				} else {
455 					jmp(Label::toStr(to), T_NEAR);
456 				}
457 			}
458 		L(".exit");
459 			sub(ecx, 1);
460 			jnz(".lp", T_NEAR);
461 			ret();
462 			outLocalLabel();
463 		}
464 	};
465 	std::string fm, gm;
466 	const int count = 50;
467 	int ret;
468 	Test5 fc(1024 * 64, count, 0);
469 	ret = ((int (*)())fc.getCode())();
470 	CYBOZU_TEST_EQUAL(ret, count * count);
471 	fm.assign((const char*)fc.getCode(), fc.getSize());
472 	Test5 gc(10, count, Xbyak::AutoGrow);
473 	gc.ready();
474 	ret = ((int (*)())gc.getCode())();
475 	CYBOZU_TEST_EQUAL(ret, count * count);
476 	gm.assign((const char*)gc.getCode(), gc.getSize());
477 	CYBOZU_TEST_EQUAL(fm, gm);
478 }
479 #endif
480 
getValue(const uint8_t * p)481 size_t getValue(const uint8_t* p)
482 {
483 	size_t v = 0;
484 	for (size_t i = 0; i < sizeof(size_t); i++) {
485 		v |= size_t(p[i]) << (i * 8);
486 	}
487 	return v;
488 }
489 
checkAddr(const uint8_t * p,size_t offset,size_t expect)490 void checkAddr(const uint8_t *p, size_t offset, size_t expect)
491 {
492 	size_t v = getValue(p + offset);
493 	CYBOZU_TEST_EQUAL(v, size_t(p) + expect);
494 }
495 
CYBOZU_TEST_AUTO(MovLabel)496 CYBOZU_TEST_AUTO(MovLabel)
497 {
498 	struct MovLabelCode : Xbyak::CodeGenerator {
499 		MovLabelCode(bool grow, bool useNewLabel)
500 			: Xbyak::CodeGenerator(grow ? 128 : 4096, grow ? Xbyak::AutoGrow : 0)
501 		{
502 #ifdef XBYAK64
503 			const Reg64& a = rax;
504 #else
505 			const Reg32& a = eax;
506 #endif
507 			if (useNewLabel) {
508 				nop(); // 0x90
509 				Label lp1, lp2;
510 			L(lp1);
511 				nop();
512 				mov(a, lp1); // 0xb8 + <4byte> / 0x48bb + <8byte>
513 				nop();
514 				mov(a, lp2); // 0xb8
515 				// force realloc if AutoGrow
516 				putNop(this, 256);
517 				nop();
518 			L(lp2);
519 			} else {
520 				inLocalLabel();
521 				nop(); // 0x90
522 			L(".lp1");
523 				nop();
524 				mov(a, ".lp1"); // 0xb8 + <4byte> / 0x48bb + <8byte>
525 				nop();
526 				mov(a, ".lp2"); // 0xb8
527 				// force realloc if AutoGrow
528 				putNop(this, 256);
529 				nop();
530 			L(".lp2");
531 				outLocalLabel();
532 			}
533 		}
534 	};
535 
536 	const struct {
537 		int pos;
538 		uint8_t ok;
539 	} tbl[] = {
540 #ifdef XBYAK32
541 		{ 0x00, 0x90 },
542 		// lp1:0x001
543 		{ 0x001, 0x90 },
544 		{ 0x002, 0xb8 },
545 		// 0x003
546 		{ 0x007, 0x90 },
547 		{ 0x008, 0xb8 },
548 		// 0x009
549 		{ 0x10d, 0x90 },
550 		// lp2:0x10e
551 #else
552 		{ 0x000, 0x90 },
553 		// lp1:0x001
554 		{ 0x001, 0x90 },
555 		{ 0x002, 0x48 },
556 		{ 0x003, 0xb8 },
557 		// 0x004
558 		{ 0x00c, 0x90 },
559 		{ 0x00d, 0x48 },
560 		{ 0x00e, 0xb8 },
561 		// 0x00f
562 		{ 0x117, 0x90 },
563 		// lp2:0x118
564 #endif
565 	};
566 	for (int j = 0; j < 2; j++) {
567 		const bool grow = j == 0;
568 		for (int k = 0; k < 2; k++) {
569 			const bool useNewLabel = k == 0;
570 			MovLabelCode code(grow, useNewLabel);
571 			if (grow) code.ready();
572 			const uint8_t* const p = code.getCode();
573 			for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
574 				int pos = tbl[i].pos;
575 				uint8_t x = p[pos];
576 				uint8_t ok = tbl[i].ok;
577 				CYBOZU_TEST_EQUAL(x, ok);
578 			}
579 #ifdef XBYAK32
580 			checkAddr(p, 0x03, 0x001);
581 			checkAddr(p, 0x09, 0x10e);
582 #else
583 			checkAddr(p, 0x04, 0x001);
584 			checkAddr(p, 0x0f, 0x118);
585 #endif
586 		}
587 	}
588 }
589 
CYBOZU_TEST_AUTO(testMovLabel2)590 CYBOZU_TEST_AUTO(testMovLabel2)
591 {
592 	struct MovLabel2Code : Xbyak::CodeGenerator {
593 		MovLabel2Code()
594 		{
595 #ifdef XBYAK64
596 			const Reg64& a = rax;
597 			const Reg64& c = rcx;
598 #else
599 			const Reg32& a = eax;
600 			const Reg32& c = ecx;
601 #endif
602 			xor_(a, a);
603 			xor_(c, c);
604 			jmp("in");
605 			ud2();
606 		L("@@"); // L1
607 			add(a, 2);
608 			mov(c, "@f");
609 			jmp(c); // goto L2
610 			ud2();
611 		L("in");
612 			mov(c, "@b");
613 			add(a, 1);
614 			jmp(c); // goto L1
615 			ud2();
616 		L("@@"); // L2
617 			add(a, 4);
618 			ret();
619 		}
620 	};
621 	MovLabel2Code code;
622 	int ret = code.getCode<int (*)()>()();
623 	CYBOZU_TEST_EQUAL(ret, 7);
624 }
625 
CYBOZU_TEST_AUTO(testF_B)626 CYBOZU_TEST_AUTO(testF_B)
627 {
628 	struct Code : Xbyak::CodeGenerator {
629 		Code(int type)
630 		{
631 			inLocalLabel();
632 			xor_(eax, eax);
633 			switch (type) {
634 			case 0:
635 			L("@@");
636 				inc(eax);
637 				cmp(eax, 1);
638 				je("@b");
639 				break;
640 			case 1:
641 				test(eax, eax);
642 				jz("@f");
643 				ud2();
644 			L("@@");
645 				break;
646 			case 2:
647 			L("@@");
648 				inc(eax);
649 				cmp(eax, 1); // 1, 2
650 				je("@b");
651 				cmp(eax, 2); // 2, 3
652 				je("@b");
653 				break;
654 			case 3:
655 			L("@@");
656 				inc(eax);
657 				cmp(eax, 1); // 1, 2
658 				je("@b");
659 				cmp(eax, 2); // 2, 3
660 				je("@b");
661 				jmp("@f");
662 				ud2();
663 			L("@@");
664 				break;
665 			case 4:
666 			L("@@");
667 				inc(eax);
668 				cmp(eax, 1); // 1, 2
669 				je("@b");
670 				cmp(eax, 2); // 2, 3
671 				je("@b");
672 				jmp("@f");
673 				ud2();
674 			L("@@");
675 				inc(eax); // 4, 5
676 				cmp(eax, 4);
677 				je("@b");
678 				break;
679 			case 5:
680 			L("@@");
681 			L("@@");
682 				inc(eax);
683 				cmp(eax, 1);
684 				je("@b");
685 				break;
686 			case 6:
687 			L("@@");
688 			L("@@");
689 			L("@@");
690 				inc(eax);
691 				cmp(eax, 1);
692 				je("@b");
693 				break;
694 			case 7:
695 				jmp("@f");
696 			L("@@");
697 				inc(eax); // 1, 2
698 				cmp(eax, 1);
699 				je("@b");
700 				cmp(eax, 2);
701 				jne("@f"); // not jmp
702 				inc(eax); // 3
703 			L("@@");
704 				inc(eax); // 4, 5, 6
705 				cmp(eax, 4);
706 				je("@b");
707 				cmp(eax, 5);
708 				je("@b");
709 				jmp("@f");
710 				jmp("@f");
711 				jmp("@b");
712 			L("@@");
713 				break;
714 			}
715 			ret();
716 			outLocalLabel();
717 		}
718 	};
719 	const int expectedTbl[] = {
720 		2, 0, 3, 3, 5, 2, 2, 6
721 	};
722 	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(expectedTbl); i++) {
723 		Code code((int)i);
724 		int ret = code.getCode<int (*)()>()();
725 		CYBOZU_TEST_EQUAL(ret, expectedTbl[i]);
726 	}
727 }
728 
CYBOZU_TEST_AUTO(test6)729 CYBOZU_TEST_AUTO(test6)
730 {
731 	struct TestLocal : public Xbyak::CodeGenerator {
732 		TestLocal(bool grow)
733 			: Xbyak::CodeGenerator(grow ? 128 : 4096, grow ? Xbyak::AutoGrow : 0)
734 		{
735 			xor_(eax, eax);
736 			inLocalLabel();
737 			jmp("start0", T_NEAR);
738 			L(".back");
739 			inc(eax); // 8
740 			jmp(".next", T_NEAR);
741 			L("start2");
742 			inc(eax); // 7
743 			jmp(".back", T_NEAR);
744 				inLocalLabel();
745 				L(".back");
746 				inc(eax); // 5
747 				putNop(this, 128);
748 				jmp(".next", T_NEAR);
749 				L("start1");
750 				inc(eax); // 4
751 				jmp(".back", T_NEAR);
752 					inLocalLabel();
753 					L(".back");
754 					inc(eax); // 2
755 					jmp(".next", T_NEAR);
756 					L("start0");
757 					inc(eax); // 1
758 					jmp(".back", T_NEAR);
759 					L(".next");
760 					inc(eax); // 3
761 					jmp("start1", T_NEAR);
762 					outLocalLabel();
763 				L(".next");
764 				inc(eax); // 6
765 				jmp("start2", T_NEAR);
766 				outLocalLabel();
767 			L(".next");
768 			inc(eax); // 9
769 			jmp("start3", T_NEAR);
770 				inLocalLabel();
771 				L(".back");
772 				inc(eax); // 14
773 				jmp("exit", T_NEAR);
774 			L("start4");
775 				inc(eax); // 13
776 				jmp(".back", T_NEAR);
777 				outLocalLabel();
778 			L("start3");
779 				inc(eax); // 10
780 				inLocalLabel();
781 				jmp(".next", T_NEAR);
782 				L(".back");
783 				inc(eax); // 12
784 				jmp("start4", T_NEAR);
785 				L(".next");
786 				inc(eax); // 11
787 				jmp(".back", T_NEAR);
788 				outLocalLabel();
789 			outLocalLabel();
790 			L("exit");
791 			inc(eax); // 15
792 			ret();
793 		}
794 	};
795 
796 	for (int i = 0; i < 2; i++) {
797 		const bool grow = i == 1;
798 		printf("test6 grow=%d\n", i);
799 		TestLocal code(grow);
800 		if (grow) code.ready();
801 		int (*f)() = code.getCode<int (*)()>();
802 		int a = f();
803 		CYBOZU_TEST_EQUAL(a, 15);
804 	}
805 }
806 
CYBOZU_TEST_AUTO(test_jcc)807 CYBOZU_TEST_AUTO(test_jcc)
808 {
809 	struct A : Xbyak::CodeGenerator {
810 		A()
811 		{
812 			add(eax, 5);
813 			ret();
814 		}
815 	};
816 	struct B : Xbyak::CodeGenerator {
817 		B(bool grow, const void *p) : Xbyak::CodeGenerator(grow ? 0 : 4096, grow ? Xbyak::AutoGrow : 0)
818 		{
819 			mov(eax, 1);
820 			add(eax, 2);
821 			jnz(p);
822 		}
823 	};
824 	A a;
825 	const void *p = a.getCode<const void*>();
826 	for (int i = 0; i < 2; i++) {
827 		bool grow = i == 1;
828 		B b(grow, p);
829 		if (grow) {
830 			b.ready();
831 		}
832 		int (*f)() = b.getCode<int (*)()>();
833 		CYBOZU_TEST_EQUAL(f(), 8);
834 	}
835 }
836 
CYBOZU_TEST_AUTO(testNewLabel)837 CYBOZU_TEST_AUTO(testNewLabel)
838 {
839 	struct Code : Xbyak::CodeGenerator {
840 		Code(bool grow)
841 			: Xbyak::CodeGenerator(grow ? 128 : 4096, grow ? Xbyak::AutoGrow : 0)
842 		{
843 			xor_(eax, eax);
844 			{
845 				Label label1;
846 				Label label2;
847 				Label label3;
848 				Label label4;
849 				Label exit;
850 				jmp(label1, T_NEAR);
851 			L(label2);
852 				inc(eax); // 2
853 				jmp(label3, T_NEAR);
854 			L(label4);
855 				inc(eax); // 4
856 				jmp(exit, T_NEAR);
857 				putNop(this, 128);
858 			L(label3);
859 				inc(eax); // 3
860 				jmp(label4, T_NEAR);
861 			L(label1);
862 				inc(eax); // 1
863 				jmp(label2, T_NEAR);
864 			L(exit);
865 			}
866 			{
867 				Label label1;
868 				Label label2;
869 				Label label3;
870 				Label label4;
871 				Label exit;
872 				jmp(label1);
873 			L(label2);
874 				inc(eax); // 6
875 				jmp(label3);
876 			L(label4);
877 				inc(eax); // 8
878 				jmp(exit);
879 			L(label3);
880 				inc(eax); // 7
881 				jmp(label4);
882 			L(label1);
883 				inc(eax); // 5
884 				jmp(label2);
885 			L(exit);
886 			}
887 			Label callLabel;
888 			{	// eax == 8
889 				Label label1;
890 				Label label2;
891 			L(label1);
892 				inc(eax); // 9, 10, 11, 13
893 				cmp(eax, 9);
894 				je(label1);
895 				// 10, 11, 13
896 				inc(eax); // 11, 12, 13
897 				cmp(eax, 11);
898 				je(label1);
899 				// 12, 13
900 				cmp(eax, 12);
901 				je(label2);
902 				inc(eax); // 14
903 				cmp(eax, 14);
904 				je(label2);
905 				ud2();
906 			L(label2); // 14
907 				inc(eax); // 13, 15
908 				cmp(eax, 13);
909 				je(label1);
910 			}
911 			call(callLabel);
912 			ret();
913 		L(callLabel);
914 			inc(eax); // 16
915 			ret();
916 		}
917 	};
918 	for (int i = 0; i < 2; i++) {
919 		const bool grow = i == 1;
920 		printf("testNewLabel grow=%d\n", grow);
921 		Code code(grow);
922 		if (grow) code.ready();
923 		int (*f)() = code.getCode<int (*)()>();
924 		int r = f();
925 		CYBOZU_TEST_EQUAL(r, 16);
926 	}
927 }
928 
CYBOZU_TEST_AUTO(returnLabel)929 CYBOZU_TEST_AUTO(returnLabel)
930 {
931 	struct Code : Xbyak::CodeGenerator {
932 		Code()
933 		{
934 			xor_(eax, eax);
935 		Label L1 = L();
936 			test(eax, eax);
937 			Label exit;
938 			jnz(exit);
939 			inc(eax); // 1
940 			Label L2;
941 			call(L2);
942 			jmp(L1);
943 		L(L2);
944 			inc(eax); // 2
945 			ret();
946 		L(exit);
947 			inc(eax); // 3
948 			ret();
949 		}
950 	};
951 	Code code;
952 	int (*f)() = code.getCode<int (*)()>();
953 	int r = f();
954 	CYBOZU_TEST_EQUAL(r, 3);
955 }
956 
CYBOZU_TEST_AUTO(testAssign)957 CYBOZU_TEST_AUTO(testAssign)
958 {
959 	struct Code : Xbyak::CodeGenerator {
960 		Code(bool grow)
961 			: Xbyak::CodeGenerator(grow ? 128 : 4096, grow ? Xbyak::AutoGrow : 0)
962 		{
963 			xor_(eax, eax);
964 			Label dst, src;
965 		L(src);
966 			inc(eax);
967 			cmp(eax, 1);
968 			je(dst);
969 			inc(eax); // 2, 3, 5
970 			cmp(eax, 5);
971 			putNop(this, 128);
972 			jne(dst, T_NEAR);
973 			ret();
974 		assignL(dst, src);
975 			// test of copy  label
976 			{
977 				Label sss(dst);
978 				{
979 					Label ttt;
980 					ttt = src;
981 				}
982 			}
983 		}
984 	};
985 	for (int i = 0; i < 2; i++) {
986 		const bool grow = i == 0;
987 		printf("testAssign grow=%d\n", grow);
988 		Code code(grow);
989 		if (grow) code.ready();
990 		int (*f)() = code.getCode<int (*)()>();
991 		int ret = f();
992 		CYBOZU_TEST_EQUAL(ret, 5);
993     }
994 }
995 
CYBOZU_TEST_AUTO(doubleDefine)996 CYBOZU_TEST_AUTO(doubleDefine)
997 {
998 	struct Code : Xbyak::CodeGenerator {
999 		Code()
1000 		{
1001 			{
1002 				Label label;
1003 			L(label);
1004 				// forbitten double L()
1005 				CYBOZU_TEST_EXCEPTION(L(label), Xbyak::Error);
1006 			}
1007 			{
1008 				Label label;
1009 				jmp(label);
1010 				CYBOZU_TEST_ASSERT(hasUndefinedLabel());
1011 			}
1012 			{
1013 				Label label1, label2;
1014 			L(label1);
1015 				jmp(label2);
1016 				assignL(label2, label1);
1017 				// forbitten double assignL
1018 				CYBOZU_TEST_EXCEPTION(assignL(label2, label1), Xbyak::Error);
1019 			}
1020 			{
1021 				Label label1, label2;
1022 			L(label1);
1023 				jmp(label2);
1024 				// forbitten assignment to label1 set by L()
1025 				CYBOZU_TEST_EXCEPTION(assignL(label1, label2), Xbyak::Error);
1026 			}
1027 		}
1028 	} code;
1029 }
1030 
1031 struct GetAddressCode1 : Xbyak::CodeGenerator {
testGetAddressCode11032 	void test()
1033 	{
1034 		Xbyak::Label L1, L2, L3;
1035 		nop();
1036 	L(L1);
1037 		const uint8_t *p1 = getCurr();
1038 		CYBOZU_TEST_EQUAL_POINTER(L1.getAddress(), p1);
1039 
1040 		nop();
1041 		jmp(L2);
1042 		nop();
1043 		jmp(L3);
1044 	L(L2);
1045 		CYBOZU_TEST_EQUAL_POINTER(L2.getAddress(), getCurr());
1046 		// L3 is not defined
1047 		CYBOZU_TEST_EQUAL_POINTER(L3.getAddress(), 0);
1048 
1049 		// L3 is set by L1
1050 		assignL(L3, L1);
1051 		CYBOZU_TEST_EQUAL_POINTER(L3.getAddress(), p1);
1052 	}
1053 };
1054 
1055 struct CodeLabelTable : Xbyak::CodeGenerator {
1056 	enum { ret0 = 3 };
1057 	enum { ret1 = 5 };
1058 	enum { ret2 = 8 };
CodeLabelTableCodeLabelTable1059 	CodeLabelTable()
1060 	{
1061 		using namespace Xbyak;
1062 #ifdef XBYAK64_WIN
1063 		const Reg64& p0 = rcx;
1064 		const Reg64& a = rax;
1065 #elif defined (XBYAK64_GCC)
1066 		const Reg64& p0 = rdi;
1067 		const Reg64& a = rax;
1068 #else
1069 		const Reg32& p0 = edx;
1070 		const Reg32& a = eax;
1071 		mov(edx, ptr [esp + 4]);
1072 #endif
1073 		Label labelTbl, L0, L1, L2;
1074 		mov(a, labelTbl);
1075 		jmp(ptr [a + p0 * sizeof(void*)]);
1076 	L(labelTbl);
1077 		putL(L0);
1078 		putL(L1);
1079 		putL(L2);
1080 	L(L0);
1081 		mov(a, ret0);
1082 		ret();
1083 	L(L1);
1084 		mov(a, ret1);
1085 		ret();
1086 	L(L2);
1087 		mov(a, ret2);
1088 		ret();
1089 	}
1090 };
1091 
CYBOZU_TEST_AUTO(LabelTable)1092 CYBOZU_TEST_AUTO(LabelTable)
1093 {
1094 	CodeLabelTable c;
1095 	int (*f)(int) = c.getCode<int (*)(int)>();
1096 	CYBOZU_TEST_EQUAL(f(0), c.ret0);
1097 	CYBOZU_TEST_EQUAL(f(1), c.ret1);
1098 	CYBOZU_TEST_EQUAL(f(2), c.ret2);
1099 }
1100 
CYBOZU_TEST_AUTO(getAddress1)1101 CYBOZU_TEST_AUTO(getAddress1)
1102 {
1103 	GetAddressCode1 c;
1104 	c.test();
1105 }
1106 
1107 struct GetAddressCode2 : Xbyak::CodeGenerator {
1108 	Xbyak::Label L1, L2, L3;
1109 	size_t a1;
1110 	size_t a3;
GetAddressCode2GetAddressCode21111 	explicit GetAddressCode2(int size)
1112 		: Xbyak::CodeGenerator(size, size == 4096 ? 0 : Xbyak::AutoGrow)
1113 		, a1(0)
1114 		, a3(0)
1115 	{
1116 		bool autoGrow = size != 4096;
1117 		nop();
1118 	L(L1);
1119 		if (autoGrow) {
1120 			CYBOZU_TEST_EQUAL_POINTER(L1.getAddress(), 0);
1121 		}
1122 		a1 = getSize();
1123 		nop();
1124 		jmp(L2);
1125 		if (autoGrow) {
1126 			CYBOZU_TEST_EQUAL_POINTER(L2.getAddress(), 0);
1127 		}
1128 	L(L3);
1129 		a3 = getSize();
1130 		if (autoGrow) {
1131 			CYBOZU_TEST_EQUAL_POINTER(L3.getAddress(), 0);
1132 		}
1133 		nop();
1134 		assignL(L2, L1);
1135 		if (autoGrow) {
1136 			CYBOZU_TEST_EQUAL_POINTER(L2.getAddress(), 0);
1137 		}
1138 	}
1139 };
1140 
CYBOZU_TEST_AUTO(getAddress2)1141 CYBOZU_TEST_AUTO(getAddress2)
1142 {
1143 	const int sizeTbl[] = {
1144 		2, 128, // grow
1145 		4096 // not grow
1146 	};
1147 	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(sizeTbl); i++) {
1148 		int size = sizeTbl[i];
1149 		GetAddressCode2 c(size);
1150 		c.ready();
1151 		const uint8_t *p = c.getCode();
1152 		CYBOZU_TEST_EQUAL(c.L1.getAddress(), p + c.a1);
1153 		CYBOZU_TEST_EQUAL(c.L3.getAddress(), p + c.a3);
1154 		CYBOZU_TEST_EQUAL(c.L2.getAddress(), p + c.a1);
1155 	}
1156 }
1157 
1158 #ifdef XBYAK64
CYBOZU_TEST_AUTO(rip)1159 CYBOZU_TEST_AUTO(rip)
1160 {
1161 	int a[] = { 1, 10 };
1162 	int b[] = { 100, 1000 };
1163 	struct Code : Xbyak::CodeGenerator {
1164 		Code(const int *a, const int *b)
1165 		{
1166 			Label label1, label2;
1167 			jmp("@f");
1168 		L(label1);
1169 			db(a[0], 4);
1170 			db(a[1], 4);
1171 		L("@@");
1172 			mov(eax, ptr [rip + label1]);       // a[0]
1173 			mov(ecx, ptr [rip + label1+4]);     // a[1]
1174 			mov(edx, ptr [rip + label2-8+2+6]); // b[0]
1175 			add(ecx, ptr [rip + 16+label2-12]); // b[1]
1176 			add(eax, ecx);
1177 			add(eax, edx);
1178 			ret();
1179 		L(label2);
1180 			db(b[0], 4);
1181 			db(b[1], 4);
1182 
1183 			// error
1184 			CYBOZU_TEST_EXCEPTION(rip + label1 + label2, Xbyak::Error);
1185 		}
1186 	} code(a, b);
1187 	int ret = code.getCode<int (*)()>()();
1188 	CYBOZU_TEST_EQUAL(ret, a[0] + a[1] + b[0] + b[1]);
1189 }
1190 
ret1234()1191 int ret1234()
1192 {
1193 	return 1234;
1194 }
1195 
ret9999()1196 int ret9999()
1197 {
1198 	return 9999;
1199 }
1200 
CYBOZU_TEST_AUTO(rip_jmp)1201 CYBOZU_TEST_AUTO(rip_jmp)
1202 {
1203 	struct Code : Xbyak::CodeGenerator {
1204 		Code()
1205 		{
1206 			Label label;
1207 			xor_(eax, eax);
1208 			call(ptr [rip + label]);
1209 			mov(ecx, eax);
1210 			call(ptr [rip + label + 8]);
1211 			add(eax, ecx);
1212 			ret();
1213 		L(label);
1214 			db((size_t)ret1234, 8);
1215 			db((size_t)ret9999, 8);
1216 		}
1217 	} code;
1218 	int ret = code.getCode<int (*)()>()();
1219 	CYBOZU_TEST_EQUAL(ret, ret1234() + ret9999());
1220 }
1221 
1222 #if 0
1223 CYBOZU_TEST_AUTO(rip_addr)
1224 {
1225 	/*
1226 		we can't assume |&x - &code| < 2GiB anymore
1227 	*/
1228 	static int x = 5;
1229 	struct Code : Xbyak::CodeGenerator {
1230 		Code()
1231 		{
1232 			mov(eax, 123);
1233 			mov(ptr[rip + &x], eax);
1234 			ret();
1235 		}
1236 	} code;
1237 	code.getCode<void (*)()>()();
1238 	CYBOZU_TEST_EQUAL(x, 123);
1239 }
1240 #endif
1241 
1242 #ifndef __APPLE__
CYBOZU_TEST_AUTO(rip_addr_with_fixed_buf)1243 CYBOZU_TEST_AUTO(rip_addr_with_fixed_buf)
1244 {
1245 	MIE_ALIGN(4096) static char buf[8192];
1246 	static char *p = buf + 4096;
1247 	static int *x0 = (int*)buf;
1248 	static int *x1 = x0 + 1;
1249 	struct Code : Xbyak::CodeGenerator {
1250 		Code() : Xbyak::CodeGenerator(4096, p)
1251 		{
1252 			mov(eax, 123);
1253 			mov(ptr[rip + x0], eax);
1254 			mov(dword[rip + x1], 456);
1255 			mov(byte[rip + 1 + x1 + 3], 99);
1256 			ret();
1257 		}
1258 	} code;
1259 	code.setProtectModeRE();
1260 	code.getCode<void (*)()>()();
1261 	CYBOZU_TEST_EQUAL(*x0, 123);
1262 	CYBOZU_TEST_EQUAL(*x1, 456);
1263 	CYBOZU_TEST_EQUAL(buf[8], 99);
1264 	code.setProtectModeRW();
1265 }
1266 #endif
1267 #endif
1268 
1269 struct ReleaseTestCode : Xbyak::CodeGenerator {
ReleaseTestCodeReleaseTestCode1270 	ReleaseTestCode(Label& L1, Label& L2, Label& L3)
1271 	{
1272 		L(L1);
1273 		jmp(L1);
1274 		L(L2);
1275 		jmp(L3); // not assigned
1276 	}
1277 };
1278 
1279 /*
1280 	code must unlink label if code is destroyed
1281 */
CYBOZU_TEST_AUTO(release_label_after_code)1282 CYBOZU_TEST_AUTO(release_label_after_code)
1283 {
1284 	puts("---");
1285 	{
1286 		Label L1, L2, L3, L4, L5;
1287 		{
1288 			ReleaseTestCode code(L1, L2, L3);
1289 			CYBOZU_TEST_ASSERT(L1.getId() > 0);
1290 			CYBOZU_TEST_ASSERT(L1.getAddress() != 0);
1291 			CYBOZU_TEST_ASSERT(L2.getId() > 0);
1292 			CYBOZU_TEST_ASSERT(L2.getAddress() != 0);
1293 			CYBOZU_TEST_ASSERT(L3.getId() > 0);
1294 			CYBOZU_TEST_ASSERT(L3.getAddress() == 0); // L3 is not assigned
1295 			code.assignL(L4, L1);
1296 			L5 = L1;
1297 			printf("id=%d %d %d %d %d\n", L1.getId(), L2.getId(), L3.getId(), L4.getId(), L5.getId());
1298 		}
1299 		puts("code is released");
1300 		CYBOZU_TEST_ASSERT(L1.getId() == 0);
1301 		CYBOZU_TEST_ASSERT(L1.getAddress() == 0);
1302 		CYBOZU_TEST_ASSERT(L2.getId() == 0);
1303 		CYBOZU_TEST_ASSERT(L2.getAddress() == 0);
1304 //		CYBOZU_TEST_ASSERT(L3.getId() == 0); // L3 is not assigned so not cleared
1305 		CYBOZU_TEST_ASSERT(L3.getAddress() == 0);
1306 		CYBOZU_TEST_ASSERT(L4.getId() == 0);
1307 		CYBOZU_TEST_ASSERT(L4.getAddress() == 0);
1308 		CYBOZU_TEST_ASSERT(L5.getId() == 0);
1309 		CYBOZU_TEST_ASSERT(L5.getAddress() == 0);
1310 		printf("id=%d %d %d %d %d\n", L1.getId(), L2.getId(), L3.getId(), L4.getId(), L5.getId());
1311 	}
1312 }
1313 
1314 struct JmpTypeCode : Xbyak::CodeGenerator {
nopsJmpTypeCode1315 	void nops()
1316 	{
1317 		for (int i = 0; i < 130; i++) {
1318 			nop();
1319 		}
1320 	}
1321 	// return jmp code size
genJmpTypeCode1322 	size_t gen(bool pre, bool large, Xbyak::CodeGenerator::LabelType type)
1323 	{
1324 		Label label;
1325 		if (pre) {
1326 			L(label);
1327 			if (large) nops();
1328 			size_t pos = getSize();
1329 			jmp(label, type);
1330 			return getSize() - pos;
1331 		} else {
1332 			size_t pos = getSize();
1333 			jmp(label, type);
1334 			size_t size = getSize() - pos;
1335 			if (large) nops();
1336 			L(label);
1337 			return size;
1338 		}
1339 	}
1340 };
1341 
CYBOZU_TEST_AUTO(setDefaultJmpNEAR)1342 CYBOZU_TEST_AUTO(setDefaultJmpNEAR)
1343 {
1344 	const Xbyak::CodeGenerator::LabelType T_SHORT = Xbyak::CodeGenerator::T_SHORT;
1345 	const Xbyak::CodeGenerator::LabelType T_NEAR = Xbyak::CodeGenerator::T_NEAR;
1346 	const Xbyak::CodeGenerator::LabelType T_AUTO = Xbyak::CodeGenerator::T_AUTO;
1347 	const struct {
1348 		bool pre;
1349 		bool large;
1350 		Xbyak::CodeGenerator::LabelType type;
1351 		size_t expect1; // 0 means exception
1352 		size_t expect2;
1353 	} tbl[] = {
1354 		{ false, false, T_SHORT, 2, 2 },
1355 		{ false, false, T_NEAR, 5, 5 },
1356 		{ false, true, T_SHORT, 0, 0 },
1357 		{ false, true, T_NEAR, 5, 5 },
1358 
1359 		{ true, false, T_SHORT, 2, 2 },
1360 		{ true, false, T_NEAR, 5, 5 },
1361 		{ true, true, T_SHORT, 0, 0 },
1362 		{ true, true, T_NEAR, 5, 5 },
1363 
1364 		{ false, false, T_AUTO, 2, 5 },
1365 		{ false, true, T_AUTO, 0, 5 },
1366 		{ true, false, T_AUTO, 2, 2 },
1367 		{ true, true, T_AUTO, 5, 5 },
1368 	};
1369 	JmpTypeCode code1, code2;
1370 	code2.setDefaultJmpNEAR(true);
1371 	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
1372 		if (tbl[i].expect1) {
1373 			size_t size = code1.gen(tbl[i].pre, tbl[i].large, tbl[i].type);
1374 			CYBOZU_TEST_EQUAL(size, tbl[i].expect1);
1375 		} else {
1376 			CYBOZU_TEST_EXCEPTION(code1.gen(tbl[i].pre, tbl[i].large, tbl[i].type), std::exception);
1377 		}
1378 		if (tbl[i].expect2) {
1379 			size_t size = code2.gen(tbl[i].pre, tbl[i].large, tbl[i].type);
1380 			CYBOZU_TEST_EQUAL(size, tbl[i].expect2);
1381 		} else {
1382 			CYBOZU_TEST_EXCEPTION(code2.gen(tbl[i].pre, tbl[i].large, tbl[i].type), std::exception);
1383 		}
1384 	}
1385 }
1386 
CYBOZU_TEST_AUTO(ambiguousFarJmp)1387 CYBOZU_TEST_AUTO(ambiguousFarJmp)
1388 {
1389 	struct Code : Xbyak::CodeGenerator {
1390 #ifdef XBYAK32
1391 		void genJmp() { jmp(ptr[eax], T_FAR); }
1392 		void genCall() { call(ptr[eax], T_FAR); }
1393 #else
1394 		void genJmp() { jmp(ptr[rax], T_FAR); }
1395 		void genCall() { call(ptr[rax], T_FAR); }
1396 #endif
1397 	} code;
1398 	CYBOZU_TEST_EXCEPTION(code.genJmp(), std::exception);
1399 	CYBOZU_TEST_EXCEPTION(code.genCall(), std::exception);
1400 }
1401