main
gen_x86.c
1/*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5*/
6#include "gen_x86.h"
7#include "mem.h"
8#include "util.h"
9#include <stddef.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <stdarg.h>
13#include <string.h>
14
15#define REX_RM_FIELD 0x1
16#define REX_SIB_FIELD 0x2
17#define REX_REG_FIELD 0x4
18#define REX_QUAD 0x8
19
20#define OP_ADD 0x00
21#define OP_OR 0x08
22#define PRE_2BYTE 0x0F
23#define OP_ADC 0x10
24#define OP_SBB 0x18
25#define OP_AND 0x20
26#define OP_SUB 0x28
27#define OP_XOR 0x30
28#define OP_CMP 0x38
29#define PRE_REX 0x40
30#define OP_PUSH 0x50
31#define OP_POP 0x58
32#define OP_MOVSXD 0x63
33#define PRE_SIZE 0x66
34#define OP_IMUL 0x69
35#define OP_JCC 0x70
36#define OP_IMMED_ARITH 0x80
37#define OP_TEST 0x84
38#define OP_XCHG 0x86
39#define OP_MOV 0x88
40#define PRE_XOP 0x8F
41#define OP_XCHG_AX 0x90
42#define OP_CDQ 0x99
43#define OP_PUSHF 0x9C
44#define OP_POPF 0x9D
45#define OP_MOV_I8R 0xB0
46#define OP_MOV_IR 0xB8
47#define OP_SHIFTROT_IR 0xC0
48#define OP_RETN 0xC3
49#define OP_MOV_IEA 0xC6
50#define OP_SHIFTROT_1 0xD0
51#define OP_SHIFTROT_CL 0xD2
52#define OP_LOOP 0xE2
53#define OP_CALL 0xE8
54#define OP_JMP 0xE9
55#define OP_JMP_BYTE 0xEB
56#define OP_NOT_NEG 0xF6
57#define OP_SINGLE_EA 0xFF
58
59#define OP2_JCC 0x80
60#define OP2_SETCC 0x90
61#define OP2_BT 0xA3
62#define OP2_BTS 0xAB
63#define OP2_IMUL 0xAF
64#define OP2_BTR 0xB3
65#define OP2_BTX_I 0xBA
66#define OP2_BTC 0xBB
67#define OP2_MOVSX 0xBE
68#define OP2_MOVZX 0xB6
69
70#define OP_EX_ADDI 0x0
71#define OP_EX_ORI 0x1
72#define OP_EX_ADCI 0x2
73#define OP_EX_SBBI 0x3
74#define OP_EX_ANDI 0x4
75#define OP_EX_SUBI 0x5
76#define OP_EX_XORI 0x6
77#define OP_EX_CMPI 0x7
78
79#define OP_EX_ROL 0x0
80#define OP_EX_ROR 0x1
81#define OP_EX_RCL 0x2
82#define OP_EX_RCR 0x3
83#define OP_EX_SHL 0x4
84#define OP_EX_SHR 0x5
85#define OP_EX_SAL 0x6 //identical to SHL
86#define OP_EX_SAR 0x7
87
88#define OP_EX_BT 0x4
89#define OP_EX_BTS 0x5
90#define OP_EX_BTR 0x6
91#define OP_EX_BTC 0x7
92
93#define OP_EX_TEST_I 0x0
94#define OP_EX_NOT 0x2
95#define OP_EX_NEG 0x3
96#define OP_EX_MUL 0x4
97#define OP_EX_IMUL 0x5
98#define OP_EX_DIV 0x6
99#define OP_EX_IDIV 0x7
100
101#define OP_EX_INC 0x0
102#define OP_EX_DEC 0x1
103#define OP_EX_CALL_EA 0x2
104#define OP_EX_JMP_EA 0x4
105#define OP_EX_PUSH_EA 0x6
106
107#define BIT_IMMED_RAX 0x4
108#define BIT_DIR 0x2
109#define BIT_SIZE 0x1
110
111
112enum {
113 X86_RAX = 0,
114 X86_RCX,
115 X86_RDX,
116 X86_RBX,
117 X86_RSP,
118 X86_RBP,
119 X86_RSI,
120 X86_RDI,
121 X86_AH=4,
122 X86_CH,
123 X86_DH,
124 X86_BH,
125 X86_R8=0,
126 X86_R9,
127 X86_R10,
128 X86_R11,
129 X86_R12,
130 X86_R13,
131 X86_R14,
132 X86_R15
133} x86_regs_enc;
134
135char * x86_reg_names[] = {
136#ifdef X86_64
137 "rax",
138 "rcx",
139 "rdx",
140 "rbx",
141 "rsp",
142 "rbp",
143 "rsi",
144 "rdi",
145#else
146 "eax",
147 "ecx",
148 "edx",
149 "ebx",
150 "esp",
151 "ebp",
152 "esi",
153 "edi",
154#endif
155 "ah",
156 "ch",
157 "dh",
158 "bh",
159 "r8",
160 "r9",
161 "r10",
162 "r11",
163 "r12",
164 "r13",
165 "r14",
166 "r15",
167};
168
169char * x86_sizes[] = {
170 "b", "w", "d", "q"
171};
172
173#ifdef X86_64
174#define CHECK_DISP(disp) (disp <= 0x7FFFFFFF && disp >= -2147483648)
175#else
176#define CHECK_DISP(disp) 1
177#endif
178
179void jmp_nocheck(code_info *code, code_ptr dest)
180{
181 code_ptr out = code->cur;
182 ptrdiff_t disp = dest-(out+2);
183 if (disp <= 0x7F && disp >= -0x80) {
184 *(out++) = OP_JMP_BYTE;
185 *(out++) = disp;
186 } else {
187 disp = dest-(out+5);
188 if (CHECK_DISP(disp)) {
189 *(out++) = OP_JMP;
190 *(out++) = disp;
191 disp >>= 8;
192 *(out++) = disp;
193 disp >>= 8;
194 *(out++) = disp;
195 disp >>= 8;
196 *(out++) = disp;
197 } else {
198 fatal_error("jmp: %p - %p = %l which is out of range of a 32-bit displacementX\n", dest, out + 6, (long)disp);
199 }
200 }
201 code->cur = out;
202}
203
204void check_alloc_code(code_info *code, uint32_t inst_size)
205{
206 if (code->cur + inst_size > code->last) {
207 size_t size = CODE_ALLOC_SIZE;
208 code_ptr next_code = alloc_code(&size);
209 if (!next_code) {
210 fatal_error("Failed to allocate memory for generated code\n");
211 }
212 if (next_code != code->last + RESERVE_WORDS) {
213 //new chunk is not contiguous with the current one
214 jmp_nocheck(code, next_code);
215 code->cur = next_code;
216 }
217 code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS;
218 }
219}
220
221void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst, uint8_t size)
222{
223 check_alloc_code(code, 5);
224 code_ptr out = code->cur;
225 uint8_t tmp;
226 if (size == SZ_W) {
227 *(out++) = PRE_SIZE;
228 }
229 if (size == SZ_B && dst >= RSP && dst <= RDI) {
230 opcode |= BIT_DIR;
231 tmp = dst;
232 dst = src;
233 src = tmp;
234 }
235 if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) {
236#ifdef X86_64
237 *out = PRE_REX;
238 if (src >= AH && src <= BH || dst >= AH && dst <= BH) {
239 fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
240 }
241 if (size == SZ_Q) {
242 *out |= REX_QUAD;
243 }
244 if (src >= R8) {
245 *out |= REX_REG_FIELD;
246 src -= (R8 - X86_R8);
247 }
248 if (dst >= R8) {
249 *out |= REX_RM_FIELD;
250 dst -= (R8 - X86_R8);
251 }
252 out++;
253#else
254 fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, src: %s, dst: %s, size: %s\n", opcode, x86_reg_names[src], x86_reg_names[dst], x86_sizes[size]);
255#endif
256 }
257 if (size == SZ_B) {
258 if (src >= AH && src <= BH) {
259 src -= (AH-X86_AH);
260 }
261 if (dst >= AH && dst <= BH) {
262 dst -= (AH-X86_AH);
263 }
264 } else {
265 opcode |= BIT_SIZE;
266 }
267 if (opcode >= 0x100) {
268 *(out++) = opcode >> 8;
269 *(out++) = opcode;
270 } else {
271 *(out++) = opcode;
272 }
273 *(out++) = MODE_REG_DIRECT | dst | (src << 3);
274 code->cur = out;
275}
276
277void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t base, int32_t disp, uint8_t size, uint8_t dir)
278{
279 check_alloc_code(code, 10);
280 code_ptr out = code->cur;
281 //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
282 uint8_t tmp;
283 if (size == SZ_W) {
284 *(out++) = PRE_SIZE;
285 }
286 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
287#ifdef X86_64
288 *out = PRE_REX;
289 if (reg >= AH && reg <= BH) {
290 fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
291 }
292 if (size == SZ_Q) {
293 *out |= REX_QUAD;
294 }
295 if (reg >= R8) {
296 *out |= REX_REG_FIELD;
297 reg -= (R8 - X86_R8);
298 }
299 if (base >= R8) {
300 *out |= REX_RM_FIELD;
301 base -= (R8 - X86_R8);
302 }
303 out++;
304#else
305 fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
306#endif
307 }
308 if (size == SZ_B) {
309 if (reg >= AH && reg <= BH) {
310 reg -= (AH-X86_AH);
311 }
312 } else {
313 opcode |= BIT_SIZE;
314 }
315 opcode |= dir;
316 if (opcode >= 0x100) {
317 *(out++) = opcode >> 8;
318 *(out++) = opcode;
319 } else {
320 *(out++) = opcode;
321 }
322 if (disp < 128 && disp >= -128) {
323 *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
324 } else {
325 *(out++) = MODE_REG_DISPLACE32 | base | (reg << 3);
326 }
327 if (base == RSP) {
328 //add SIB byte, with no index and RSP as base
329 *(out++) = (RSP << 3) | RSP;
330 }
331 *(out++) = disp;
332 if (disp >= 128 || disp < -128) {
333 *(out++) = disp >> 8;
334 *(out++) = disp >> 16;
335 *(out++) = disp >> 24;
336 }
337 code->cur = out;
338}
339
340void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir)
341{
342 check_alloc_code(code, 5);
343 code_ptr out = code->cur;
344 //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
345 uint8_t tmp;
346 if (size == SZ_W) {
347 *(out++) = PRE_SIZE;
348 }
349 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
350#ifdef X86_64
351 *out = PRE_REX;
352 if (reg >= AH && reg <= BH) {
353 fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
354 }
355 if (size == SZ_Q) {
356 *out |= REX_QUAD;
357 }
358 if (reg >= R8) {
359 *out |= REX_REG_FIELD;
360 reg -= (R8 - X86_R8);
361 }
362 if (base >= R8) {
363 *out |= REX_RM_FIELD;
364 base -= (R8 - X86_R8);
365 }
366 out++;
367#else
368 fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
369#endif
370 }
371 if (size == SZ_B) {
372 if (reg >= AH && reg <= BH) {
373 reg -= (AH-X86_AH);
374 }
375 } else {
376 opcode |= BIT_SIZE;
377 }
378 *(out++) = opcode | dir;
379 if (base == RBP) {
380 //add a dummy 8-bit displacement since MODE_REG_INDIRECT with
381 //an R/M field of RBP selects RIP, relative addressing
382 *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
383 *(out++) = 0;
384 } else {
385 *(out++) = MODE_REG_INDIRECT | base | (reg << 3);
386 if (base == RSP) {
387 //add SIB byte, with no index and RSP as base
388 *(out++) = (RSP << 3) | RSP;
389 }
390 }
391 code->cur = out;
392}
393
394void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t index, uint8_t scale, uint8_t size, uint8_t dir)
395{
396 check_alloc_code(code, 5);
397 code_ptr out = code->cur;
398 //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
399 uint8_t tmp;
400 if (size == SZ_W) {
401 *(out++) = PRE_SIZE;
402 }
403 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
404#ifdef X86_64
405 *out = PRE_REX;
406 if (reg >= AH && reg <= BH) {
407 fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
408 }
409 if (size == SZ_Q) {
410 *out |= REX_QUAD;
411 }
412 if (reg >= R8) {
413 *out |= REX_REG_FIELD;
414 reg -= (R8 - X86_R8);
415 }
416 if (base >= R8) {
417 *out |= REX_RM_FIELD;
418 base -= (R8 - X86_R8);
419 }
420 if (index >= R8) {
421 *out |= REX_SIB_FIELD;
422 index -= (R8 - X86_R8);
423 }
424 out++;
425#else
426 fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
427#endif
428 }
429 if (size == SZ_B) {
430 if (reg >= AH && reg <= BH) {
431 reg -= (AH-X86_AH);
432 }
433 } else {
434 opcode |= BIT_SIZE;
435 }
436 *(out++) = opcode | dir;
437 *(out++) = MODE_REG_INDIRECT | RSP | (reg << 3);
438 if (scale == 4) {
439 scale = 2;
440 } else if(scale == 8) {
441 scale = 3;
442 } else {
443 scale--;
444 }
445 *(out++) = scale << 6 | (index << 3) | base;
446 code->cur = out;
447}
448
449void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size)
450{
451 check_alloc_code(code, 4);
452 code_ptr out = code->cur;
453 uint8_t tmp;
454 if (size == SZ_W) {
455 *(out++) = PRE_SIZE;
456 }
457 if (size == SZ_Q || dst >= R8) {
458#ifdef X86_64
459 *out = PRE_REX;
460 if (dst >= AH && dst <= BH) {
461 fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
462 }
463 if (size == SZ_Q) {
464 *out |= REX_QUAD;
465 }
466 if (dst >= R8) {
467 *out |= REX_RM_FIELD;
468 dst -= (R8 - X86_R8);
469 }
470 out++;
471#else
472 fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]);
473#endif
474 }
475 if (size == SZ_B) {
476 if (dst >= AH && dst <= BH) {
477 dst -= (AH-X86_AH);
478 }
479 } else {
480 opcode |= BIT_SIZE;
481 }
482 *(out++) = opcode;
483 *(out++) = MODE_REG_DIRECT | dst | (opex << 3);
484 code->cur = out;
485}
486
487void x86_rdisp_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, int32_t disp, uint8_t size)
488{
489 check_alloc_code(code, 7);
490 code_ptr out = code->cur;
491 uint8_t tmp;
492 if (size == SZ_W) {
493 *(out++) = PRE_SIZE;
494 }
495 if (size == SZ_Q || dst >= R8) {
496#ifdef X86_64
497 *out = PRE_REX;
498 if (size == SZ_Q) {
499 *out |= REX_QUAD;
500 }
501 if (dst >= R8) {
502 *out |= REX_RM_FIELD;
503 dst -= (R8 - X86_R8);
504 }
505 out++;
506#else
507 fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]);
508#endif
509 }
510 if (size != SZ_B) {
511 opcode |= BIT_SIZE;
512 }
513 *(out++) = opcode;
514 if (disp < 128 && disp >= -128) {
515 *(out++) = MODE_REG_DISPLACE8 | dst | (opex << 3);
516 *(out++) = disp;
517 } else {
518 *(out++) = MODE_REG_DISPLACE32 | dst | (opex << 3);
519 *(out++) = disp;
520 *(out++) = disp >> 8;
521 *(out++) = disp >> 16;
522 *(out++) = disp >> 24;
523 }
524 code->cur = out;
525}
526
527void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size)
528{
529 check_alloc_code(code, 8);
530 code_ptr out = code->cur;
531 uint8_t sign_extend = 0;
532 if (opcode != OP_NOT_NEG && (size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) {
533 sign_extend = 1;
534 opcode |= BIT_DIR;
535 }
536 if (size == SZ_W) {
537 *(out++) = PRE_SIZE;
538 }
539 if (dst == RAX && !sign_extend && al_opcode) {
540 if (size != SZ_B) {
541 al_opcode |= BIT_SIZE;
542 if (size == SZ_Q) {
543#ifdef X86_64
544 *out = PRE_REX | REX_QUAD;
545#else
546 fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, size: %s\n", al_opcode, x86_reg_names[dst], x86_sizes[size]);
547#endif
548 }
549 }
550 *(out++) = al_opcode | BIT_IMMED_RAX;
551 } else {
552 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
553#ifdef X86_64
554 *out = PRE_REX;
555 if (size == SZ_Q) {
556 *out |= REX_QUAD;
557 }
558 if (dst >= R8) {
559 *out |= REX_RM_FIELD;
560 dst -= (R8 - X86_R8);
561 }
562 out++;
563#else
564 fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]);
565#endif
566 }
567 if (dst >= AH && dst <= BH) {
568 dst -= (AH-X86_AH);
569 }
570 if (size != SZ_B) {
571 opcode |= BIT_SIZE;
572 }
573 *(out++) = opcode;
574 *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
575 }
576 *(out++) = val;
577 if (size != SZ_B && !sign_extend) {
578 val >>= 8;
579 *(out++) = val;
580 if (size != SZ_W) {
581 val >>= 8;
582 *(out++) = val;
583 val >>= 8;
584 *(out++) = val;
585 }
586 }
587 code->cur = out;
588}
589
590void x86_irdisp(code_info *code, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
591{
592 check_alloc_code(code, 12);
593 code_ptr out = code->cur;
594 uint8_t sign_extend = 0;
595 if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) {
596 sign_extend = 1;
597 opcode |= BIT_DIR;
598 }
599 if (size == SZ_W) {
600 *(out++) = PRE_SIZE;
601 }
602
603 if (size == SZ_Q || dst >= R8) {
604#ifdef X86_64
605 *out = PRE_REX;
606 if (size == SZ_Q) {
607 *out |= REX_QUAD;
608 }
609 if (dst >= R8) {
610 *out |= REX_RM_FIELD;
611 dst -= (R8 - X86_R8);
612 }
613 out++;
614#else
615 fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]);
616#endif
617 }
618 if (size != SZ_B) {
619 opcode |= BIT_SIZE;
620 }
621 *(out++) = opcode;
622 if (disp < 128 && disp >= -128) {
623 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
624 *(out++) = disp;
625 } else {
626 *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
627 *(out++) = disp;
628 disp >>= 8;
629 *(out++) = disp;
630 disp >>= 8;
631 *(out++) = disp;
632 disp >>= 8;
633 *(out++) = disp;
634 }
635 *(out++) = val;
636 if (size != SZ_B && !sign_extend) {
637 val >>= 8;
638 *(out++) = val;
639 if (size != SZ_W) {
640 val >>= 8;
641 *(out++) = val;
642 val >>= 8;
643 *(out++) = val;
644 }
645 }
646 code->cur = out;
647}
648
649void x86_shiftrot_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
650{
651 check_alloc_code(code, 5);
652 code_ptr out = code->cur;
653 if (size == SZ_W) {
654 *(out++) = PRE_SIZE;
655 }
656 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
657 *out = PRE_REX;
658 if (size == SZ_Q) {
659 *out |= REX_QUAD;
660 }
661 if (dst >= R8) {
662 *out |= REX_RM_FIELD;
663 dst -= (R8 - X86_R8);
664 }
665 out++;
666 }
667 if (dst >= AH && dst <= BH) {
668 dst -= (AH-X86_AH);
669 }
670
671 *(out++) = (val == 1 ? OP_SHIFTROT_1: OP_SHIFTROT_IR) | (size == SZ_B ? 0 : BIT_SIZE);
672 *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
673 if (val != 1) {
674 *(out++) = val;
675 }
676 code->cur = out;
677}
678
679void x86_shiftrot_irdisp(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, int32_t disp, uint8_t size)
680{
681 check_alloc_code(code, 9);
682 code_ptr out = code->cur;
683 if (size == SZ_W) {
684 *(out++) = PRE_SIZE;
685 }
686 if (size == SZ_Q || dst >= R8) {
687 *out = PRE_REX;
688 if (size == SZ_Q) {
689 *out |= REX_QUAD;
690 }
691 if (dst >= R8) {
692 *out |= REX_RM_FIELD;
693 dst -= (R8 - X86_R8);
694 }
695 out++;
696 }
697 if (dst >= AH && dst <= BH) {
698 dst -= (AH-X86_AH);
699 }
700
701 *(out++) = (val == 1 ? OP_SHIFTROT_1: OP_SHIFTROT_IR) | (size == SZ_B ? 0 : BIT_SIZE);
702 if (disp < 128 && disp >= -128) {
703 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
704 *(out++) = disp;
705 } else {
706 *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
707 *(out++) = disp;
708 *(out++) = disp >> 8;
709 *(out++) = disp >> 16;
710 *(out++) = disp >> 24;
711 }
712 if (val != 1) {
713 *(out++) = val;
714 }
715 code->cur = out;
716}
717
718void x86_shiftrot_clr(code_info *code, uint8_t op_ex, uint8_t dst, uint8_t size)
719{
720 check_alloc_code(code, 4);
721 code_ptr out = code->cur;
722 if (size == SZ_W) {
723 *(out++) = PRE_SIZE;
724 }
725 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
726 *out = PRE_REX;
727 if (size == SZ_Q) {
728 *out |= REX_QUAD;
729 }
730 if (dst >= R8) {
731 *out |= REX_RM_FIELD;
732 dst -= (R8 - X86_R8);
733 }
734 out++;
735 }
736 if (dst >= AH && dst <= BH) {
737 dst -= (AH-X86_AH);
738 }
739
740 *(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE);
741 *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
742 code->cur = out;
743}
744
745void x86_shiftrot_clrdisp(code_info *code, uint8_t op_ex, uint8_t dst, int32_t disp, uint8_t size)
746{
747 check_alloc_code(code, 8);
748 code_ptr out = code->cur;
749 if (size == SZ_W) {
750 *(out++) = PRE_SIZE;
751 }
752 if (size == SZ_Q || dst >= R8) {
753 *out = PRE_REX;
754 if (size == SZ_Q) {
755 *out |= REX_QUAD;
756 }
757 if (dst >= R8) {
758 *out |= REX_RM_FIELD;
759 dst -= (R8 - X86_R8);
760 }
761 out++;
762 }
763 if (dst >= AH && dst <= BH) {
764 dst -= (AH-X86_AH);
765 }
766
767 *(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE);
768 if (disp < 128 && disp >= -128) {
769 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
770 *(out++) = disp;
771 } else {
772 *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
773 *(out++) = disp;
774 *(out++) = disp >> 8;
775 *(out++) = disp >> 16;
776 *(out++) = disp >> 24;
777}
778 code->cur = out;
779}
780
781void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
782{
783 x86_shiftrot_ir(code, OP_EX_ROL, val, dst, size);
784}
785
786void ror_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
787{
788 x86_shiftrot_ir(code, OP_EX_ROR, val, dst, size);
789}
790
791void rcl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
792{
793 x86_shiftrot_ir(code, OP_EX_RCL, val, dst, size);
794}
795
796void rcr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
797{
798 x86_shiftrot_ir(code, OP_EX_RCR, val, dst, size);
799}
800
801void shl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
802{
803 x86_shiftrot_ir(code, OP_EX_SHL, val, dst, size);
804}
805
806void shr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
807{
808 x86_shiftrot_ir(code, OP_EX_SHR, val, dst, size);
809}
810
811void sar_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
812{
813 x86_shiftrot_ir(code, OP_EX_SAR, val, dst, size);
814}
815
816void rol_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
817{
818 x86_shiftrot_irdisp(code, OP_EX_ROL, val, dst_base, disp, size);
819}
820
821void ror_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
822{
823 x86_shiftrot_irdisp(code, OP_EX_ROR, val, dst_base, disp, size);
824}
825
826void rcl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
827{
828 x86_shiftrot_irdisp(code, OP_EX_RCL, val, dst_base, disp, size);
829}
830
831void rcr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
832{
833 x86_shiftrot_irdisp(code, OP_EX_RCR, val, dst_base, disp, size);
834}
835
836void shl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
837{
838 x86_shiftrot_irdisp(code, OP_EX_SHL, val, dst_base, disp, size);
839}
840
841void shr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
842{
843 x86_shiftrot_irdisp(code, OP_EX_SHR, val, dst_base, disp, size);
844}
845
846void sar_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
847{
848 x86_shiftrot_irdisp(code, OP_EX_SAR, val, dst_base, disp, size);
849}
850
851void rol_clr(code_info *code, uint8_t dst, uint8_t size)
852{
853 x86_shiftrot_clr(code, OP_EX_ROL, dst, size);
854}
855
856void ror_clr(code_info *code, uint8_t dst, uint8_t size)
857{
858 x86_shiftrot_clr(code, OP_EX_ROR, dst, size);
859}
860
861void rcl_clr(code_info *code, uint8_t dst, uint8_t size)
862{
863 x86_shiftrot_clr(code, OP_EX_RCL, dst, size);
864}
865
866void rcr_clr(code_info *code, uint8_t dst, uint8_t size)
867{
868 x86_shiftrot_clr(code, OP_EX_RCR, dst, size);
869}
870
871void shl_clr(code_info *code, uint8_t dst, uint8_t size)
872{
873 x86_shiftrot_clr(code, OP_EX_SHL, dst, size);
874}
875
876void shr_clr(code_info *code, uint8_t dst, uint8_t size)
877{
878 x86_shiftrot_clr(code, OP_EX_SHR, dst, size);
879}
880
881void sar_clr(code_info *code, uint8_t dst, uint8_t size)
882{
883 x86_shiftrot_clr(code, OP_EX_SAR, dst, size);
884}
885
886void rol_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
887{
888 x86_shiftrot_clrdisp(code, OP_EX_ROL, dst_base, disp, size);
889}
890
891void ror_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
892{
893 x86_shiftrot_clrdisp(code, OP_EX_ROR, dst_base, disp, size);
894}
895
896void rcl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
897{
898 x86_shiftrot_clrdisp(code, OP_EX_RCL, dst_base, disp, size);
899}
900
901void rcr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
902{
903 x86_shiftrot_clrdisp(code, OP_EX_RCR, dst_base, disp, size);
904}
905
906void shl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
907{
908 x86_shiftrot_clrdisp(code, OP_EX_SHL, dst_base, disp, size);
909}
910
911void shr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
912{
913 x86_shiftrot_clrdisp(code, OP_EX_SHR, dst_base, disp, size);
914}
915
916void sar_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
917{
918 x86_shiftrot_clrdisp(code, OP_EX_SAR, dst_base, disp, size);
919}
920
921void add_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
922{
923 x86_rr_sizedir(code, OP_ADD, src, dst, size);
924}
925
926void add_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
927{
928 x86_ir(code, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size);
929}
930
931void add_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
932{
933 x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size);
934}
935
936void add_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
937{
938 x86_rrdisp_sizedir(code, OP_ADD, src, dst_base, disp, size, 0);
939}
940
941void add_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
942{
943 x86_rrdisp_sizedir(code, OP_ADD, dst, src_base, disp, size, BIT_DIR);
944}
945
946void adc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
947{
948 x86_rr_sizedir(code, OP_ADC, src, dst, size);
949}
950
951void adc_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
952{
953 x86_ir(code, OP_IMMED_ARITH, OP_EX_ADCI, OP_ADC, val, dst, size);
954}
955
956void adc_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
957{
958 x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ADCI, val, dst_base, disp, size);
959}
960
961void adc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
962{
963 x86_rrdisp_sizedir(code, OP_ADC, src, dst_base, disp, size, 0);
964}
965
966void adc_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
967{
968 x86_rrdisp_sizedir(code, OP_ADC, dst, src_base, disp, size, BIT_DIR);
969}
970
971void or_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
972{
973 x86_rr_sizedir(code, OP_OR, src, dst, size);
974}
975void or_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
976{
977 x86_ir(code, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size);
978}
979
980void or_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
981{
982 x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size);
983}
984
985void or_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
986{
987 x86_rrdisp_sizedir(code, OP_OR, src, dst_base, disp, size, 0);
988}
989
990void or_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
991{
992 x86_rrdisp_sizedir(code, OP_OR, dst, src_base, disp, size, BIT_DIR);
993}
994
995void and_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
996{
997 x86_rr_sizedir(code, OP_AND, src, dst, size);
998}
999
1000void and_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1001{
1002 x86_ir(code, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size);
1003}
1004
1005void and_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1006{
1007 x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size);
1008}
1009
1010void and_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1011{
1012 x86_rrdisp_sizedir(code, OP_AND, src, dst_base, disp, size, 0);
1013}
1014
1015void and_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1016{
1017 x86_rrdisp_sizedir(code, OP_AND, dst, src_base, disp, size, BIT_DIR);
1018}
1019
1020void xor_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1021{
1022 x86_rr_sizedir(code, OP_XOR, src, dst, size);
1023}
1024
1025void xor_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1026{
1027 x86_ir(code, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size);
1028}
1029
1030void xor_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1031{
1032 x86_irdisp(code, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size);
1033}
1034
1035void xor_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1036{
1037 x86_rrdisp_sizedir(code, OP_XOR, src, dst_base, disp, size, 0);
1038}
1039
1040void xor_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1041{
1042 x86_rrdisp_sizedir(code, OP_XOR, dst, src_base, disp, size, BIT_DIR);
1043}
1044
1045void sub_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1046{
1047 x86_rr_sizedir(code, OP_SUB, src, dst, size);
1048}
1049
1050void sub_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1051{
1052 x86_ir(code, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size);
1053}
1054
1055void sub_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1056{
1057 x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size);
1058}
1059
1060void sub_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1061{
1062 x86_rrdisp_sizedir(code, OP_SUB, src, dst_base, disp, size, 0);
1063}
1064
1065void sub_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1066{
1067 x86_rrdisp_sizedir(code, OP_SUB, dst, src_base, disp, size, BIT_DIR);
1068}
1069
1070void sbb_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1071{
1072 x86_rr_sizedir(code, OP_SBB, src, dst, size);
1073}
1074
1075void sbb_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1076{
1077 x86_ir(code, OP_IMMED_ARITH, OP_EX_SBBI, OP_SBB, val, dst, size);
1078}
1079
1080void sbb_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1081{
1082 x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SBBI, val, dst_base, disp, size);
1083}
1084
1085void sbb_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1086{
1087 x86_rrdisp_sizedir(code, OP_SBB, src, dst_base, disp, size, 0);
1088}
1089
1090void sbb_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1091{
1092 x86_rrdisp_sizedir(code, OP_SBB, dst, src_base, disp, size, BIT_DIR);
1093}
1094
1095void cmp_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1096{
1097 x86_rr_sizedir(code, OP_CMP, src, dst, size);
1098}
1099
1100void cmp_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1101{
1102 x86_ir(code, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size);
1103}
1104
1105void cmp_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1106{
1107 x86_irdisp(code, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size);
1108}
1109
1110void cmp_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1111{
1112 x86_rrdisp_sizedir(code, OP_CMP, src, dst_base, disp, size, 0);
1113}
1114
1115void cmp_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1116{
1117 x86_rrdisp_sizedir(code, OP_CMP, dst, src_base, disp, size, BIT_DIR);
1118}
1119
1120void test_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1121{
1122 x86_rr_sizedir(code, OP_TEST, src, dst, size);
1123}
1124
1125void test_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1126{
1127 x86_ir(code, OP_NOT_NEG, OP_EX_TEST_I, OP_TEST, val, dst, size);
1128}
1129
1130void test_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1131{
1132 x86_irdisp(code, OP_NOT_NEG, OP_EX_TEST_I, val, dst_base, disp, size);
1133}
1134
1135void test_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1136{
1137 x86_rrdisp_sizedir(code, OP_TEST, src, dst_base, disp, size, 0);
1138}
1139
1140void test_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1141{
1142 x86_rrdisp_sizedir(code, OP_TEST, dst, src_base, disp, size, BIT_DIR);
1143}
1144
1145void imul_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1146{
1147 x86_rr_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src, size);
1148}
1149
1150void imul_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1151{
1152 x86_rrdisp_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src_base, disp, size, 0);
1153}
1154
1155void imul_irr(code_info *code, int32_t val, uint8_t src, uint8_t dst, uint8_t size)
1156{
1157 if (size == SZ_B) {
1158 fatal_error("imul immediate only supports 16-bit sizes and up");
1159 }
1160
1161 x86_ir(code, OP_IMUL, dst, 0, val, src, size);
1162}
1163
1164void not_r(code_info *code, uint8_t dst, uint8_t size)
1165{
1166 x86_r_size(code, OP_NOT_NEG, OP_EX_NOT, dst, size);
1167}
1168
1169void neg_r(code_info *code, uint8_t dst, uint8_t size)
1170{
1171 x86_r_size(code, OP_NOT_NEG, OP_EX_NEG, dst, size);
1172}
1173
1174void not_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1175{
1176 x86_rdisp_size(code, OP_NOT_NEG, OP_EX_NOT, dst_base, disp, size);
1177}
1178
1179void neg_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1180{
1181 x86_rdisp_size(code, OP_NOT_NEG, OP_EX_NEG, dst_base, disp, size);
1182}
1183
1184void mul_r(code_info *code, uint8_t dst, uint8_t size)
1185{
1186 x86_r_size(code, OP_NOT_NEG, OP_EX_MUL, dst, size);
1187}
1188
1189void imul_r(code_info *code, uint8_t dst, uint8_t size)
1190{
1191 x86_r_size(code, OP_NOT_NEG, OP_EX_IMUL, dst, size);
1192}
1193
1194void div_r(code_info *code, uint8_t dst, uint8_t size)
1195{
1196 x86_r_size(code, OP_NOT_NEG, OP_EX_DIV, dst, size);
1197}
1198
1199void idiv_r(code_info *code, uint8_t dst, uint8_t size)
1200{
1201 x86_r_size(code, OP_NOT_NEG, OP_EX_IDIV, dst, size);
1202}
1203
1204void mul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1205{
1206 x86_rdisp_size(code, OP_NOT_NEG, OP_EX_MUL, dst_base, disp, size);
1207}
1208
1209void imul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1210{
1211 x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IMUL, dst_base, disp, size);
1212}
1213
1214void div_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1215{
1216 x86_rdisp_size(code, OP_NOT_NEG, OP_EX_DIV, dst_base, disp, size);
1217}
1218
1219void idiv_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1220{
1221 x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IDIV, dst_base, disp, size);
1222}
1223
1224void mov_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1225{
1226 x86_rr_sizedir(code, OP_MOV, src, dst, size);
1227}
1228
1229void mov_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1230{
1231 x86_rrdisp_sizedir(code, OP_MOV, src, dst_base, disp, size, 0);
1232}
1233
1234void mov_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1235{
1236 x86_rrdisp_sizedir(code, OP_MOV, dst, src_base, disp, size, BIT_DIR);
1237}
1238
1239void mov_rrind(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1240{
1241 x86_rrind_sizedir(code, OP_MOV, src, dst, size, 0);
1242}
1243
1244void mov_rindr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1245{
1246 x86_rrind_sizedir(code, OP_MOV, dst, src, size, BIT_DIR);
1247}
1248
1249void mov_rrindex(code_info *code, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size)
1250{
1251 x86_rrindex_sizedir(code, OP_MOV, src, dst_base, dst_index, scale, size, 0);
1252}
1253
1254void mov_rindexr(code_info *code, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size)
1255{
1256 x86_rrindex_sizedir(code, OP_MOV, dst, src_base, src_index, scale, size, BIT_DIR);
1257}
1258
1259void mov_ir(code_info *code, int64_t val, uint8_t dst, uint8_t size)
1260{
1261 check_alloc_code(code, 14);
1262 code_ptr out = code->cur;
1263 uint8_t sign_extend = 0;
1264 if (size == SZ_Q && val <= 0x7FFFFFFF && val >= -2147483648) {
1265 sign_extend = 1;
1266 }
1267 if (size == SZ_W) {
1268 *(out++) = PRE_SIZE;
1269 }
1270 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
1271 *out = PRE_REX;
1272 if (size == SZ_Q) {
1273 *out |= REX_QUAD;
1274 }
1275 if (dst >= R8) {
1276 *out |= REX_RM_FIELD;
1277 dst -= (R8 - X86_R8);
1278 }
1279 out++;
1280 }
1281 if (dst >= AH && dst <= BH) {
1282 dst -= (AH-X86_AH);
1283 }
1284 if (size == SZ_B) {
1285 *(out++) = OP_MOV_I8R | dst;
1286 } else if (size == SZ_Q && sign_extend) {
1287 *(out++) = OP_MOV_IEA | BIT_SIZE;
1288 *(out++) = MODE_REG_DIRECT | dst;
1289 } else {
1290 *(out++) = OP_MOV_IR | dst;
1291 }
1292 *(out++) = val;
1293 if (size != SZ_B) {
1294 val >>= 8;
1295 *(out++) = val;
1296 if (size != SZ_W) {
1297 val >>= 8;
1298 *(out++) = val;
1299 val >>= 8;
1300 *(out++) = val;
1301 if (size == SZ_Q && !sign_extend) {
1302 val >>= 8;
1303 *(out++) = val;
1304 val >>= 8;
1305 *(out++) = val;
1306 val >>= 8;
1307 *(out++) = val;
1308 val >>= 8;
1309 *(out++) = val;
1310 }
1311 }
1312 }
1313 code->cur = out;
1314}
1315
1316uint8_t is_mov_ir(code_ptr inst)
1317{
1318 while (*inst == PRE_SIZE || *inst == PRE_REX)
1319 {
1320 inst++;
1321 }
1322 return (*inst & 0xF8) == OP_MOV_I8R || (*inst & 0xF8) == OP_MOV_IR || (*inst & 0xFE) == OP_MOV_IEA;
1323}
1324
1325void mov_irdisp(code_info *code, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
1326{
1327 check_alloc_code(code, 12);
1328 code_ptr out = code->cur;
1329 if (size == SZ_W) {
1330 *(out++) = PRE_SIZE;
1331 }
1332 if (size == SZ_Q || dst >= R8) {
1333 *out = PRE_REX;
1334 if (size == SZ_Q) {
1335 *out |= REX_QUAD;
1336 }
1337 if (dst >= R8) {
1338 *out |= REX_RM_FIELD;
1339 dst -= (R8 - X86_R8);
1340 }
1341 out++;
1342 }
1343 if (dst >= AH && dst <= BH) {
1344 dst -= (AH-X86_AH);
1345 }
1346 *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE);
1347 if (disp < 128 && disp >= -128) {
1348 *(out++) = MODE_REG_DISPLACE8 | dst;
1349 *(out++) = disp;
1350 } else {
1351 *(out++) = MODE_REG_DISPLACE32 | dst;
1352 *(out++) = disp;
1353 *(out++) = disp >> 8;
1354 *(out++) = disp >> 16;
1355 *(out++) = disp >> 24;
1356 }
1357
1358 *(out++) = val;
1359 if (size != SZ_B) {
1360 val >>= 8;
1361 *(out++) = val;
1362 if (size != SZ_W) {
1363 val >>= 8;
1364 *(out++) = val;
1365 val >>= 8;
1366 *(out++) = val;
1367 }
1368 }
1369 code->cur = out;
1370}
1371
1372void mov_irind(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1373{
1374 check_alloc_code(code, 8);
1375 code_ptr out = code->cur;
1376 if (size == SZ_W) {
1377 *(out++) = PRE_SIZE;
1378 }
1379 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
1380 *out = PRE_REX;
1381 if (size == SZ_Q) {
1382 *out |= REX_QUAD;
1383 }
1384 if (dst >= R8) {
1385 *out |= REX_RM_FIELD;
1386 dst -= (R8 - X86_R8);
1387 }
1388 out++;
1389 }
1390 if (dst >= AH && dst <= BH) {
1391 dst -= (AH-X86_AH);
1392 }
1393 *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE);
1394 *(out++) = MODE_REG_INDIRECT | dst;
1395
1396 *(out++) = val;
1397 if (size != SZ_B) {
1398 val >>= 8;
1399 *(out++) = val;
1400 if (size != SZ_W) {
1401 val >>= 8;
1402 *(out++) = val;
1403 val >>= 8;
1404 *(out++) = val;
1405 }
1406 }
1407 code->cur = out;
1408}
1409
1410void movsx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size)
1411{
1412 check_alloc_code(code, 5);
1413 code_ptr out = code->cur;
1414 if (size == SZ_W) {
1415 *(out++) = PRE_SIZE;
1416 }
1417 if (size == SZ_Q || dst >= R8 || src >= R8) {
1418 *out = PRE_REX;
1419 if (size == SZ_Q) {
1420 *out |= REX_QUAD;
1421 }
1422 if (src >= R8) {
1423 *out |= REX_RM_FIELD;
1424 src -= (R8 - X86_R8);
1425 }
1426 if (dst >= R8) {
1427 *out |= REX_REG_FIELD;
1428 dst -= (R8 - X86_R8);
1429 }
1430 out++;
1431 }
1432 if (src_size == SZ_D) {
1433 *(out++) = OP_MOVSXD;
1434 } else {
1435 *(out++) = PRE_2BYTE;
1436 *(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE);
1437 }
1438 *(out++) = MODE_REG_DIRECT | src | (dst << 3);
1439 code->cur = out;
1440}
1441
1442void movsx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size)
1443{
1444 check_alloc_code(code, 12);
1445 code_ptr out = code->cur;
1446 if (size == SZ_W) {
1447 *(out++) = PRE_SIZE;
1448 }
1449 if (size == SZ_Q || dst >= R8 || src >= R8) {
1450 *out = PRE_REX;
1451 if (size == SZ_Q) {
1452 *out |= REX_QUAD;
1453 }
1454 if (src >= R8) {
1455 *out |= REX_RM_FIELD;
1456 src -= (R8 - X86_R8);
1457 }
1458 if (dst >= R8) {
1459 *out |= REX_REG_FIELD;
1460 dst -= (R8 - X86_R8);
1461 }
1462 out++;
1463 }
1464 if (src_size == SZ_D) {
1465 *(out++) = OP_MOVSXD;
1466 } else {
1467 *(out++) = PRE_2BYTE;
1468 *(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE);
1469 }
1470 if (disp < 128 && disp >= -128) {
1471 *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
1472 *(out++) = disp;
1473 } else {
1474 *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3);
1475 *(out++) = disp;
1476 *(out++) = disp >> 8;
1477 *(out++) = disp >> 16;
1478 *(out++) = disp >> 24;
1479 }
1480 code->cur = out;
1481}
1482
1483void movzx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size)
1484{
1485 check_alloc_code(code, 5);
1486 code_ptr out = code->cur;
1487 if (size == SZ_W) {
1488 *(out++) = PRE_SIZE;
1489 }
1490 if (size == SZ_Q || dst >= R8 || src >= R8) {
1491 *out = PRE_REX;
1492 if (size == SZ_Q) {
1493 *out |= REX_QUAD;
1494 }
1495 if (src >= R8) {
1496 *out |= REX_RM_FIELD;
1497 src -= (R8 - X86_R8);
1498 }
1499 if (dst >= R8) {
1500 *out |= REX_REG_FIELD;
1501 dst -= (R8 - X86_R8);
1502 }
1503 out++;
1504 }
1505 *(out++) = PRE_2BYTE;
1506 *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE);
1507 *(out++) = MODE_REG_DIRECT | src | (dst << 3);
1508 code->cur = out;
1509}
1510
1511void movzx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size)
1512{
1513 check_alloc_code(code, 9);
1514 code_ptr out = code->cur;
1515 if (size == SZ_W) {
1516 *(out++) = PRE_SIZE;
1517 }
1518 if (size == SZ_Q || dst >= R8 || src >= R8) {
1519 *out = PRE_REX;
1520 if (size == SZ_Q) {
1521 *out |= REX_QUAD;
1522 }
1523 if (src >= R8) {
1524 *out |= REX_RM_FIELD;
1525 src -= (R8 - X86_R8);
1526 }
1527 if (dst >= R8) {
1528 *out |= REX_REG_FIELD;
1529 dst -= (R8 - X86_R8);
1530 }
1531 out++;
1532 }
1533 *(out++) = PRE_2BYTE;
1534 *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE);
1535 if (disp < 128 && disp >= -128) {
1536 *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
1537 *(out++) = disp;
1538 } else {
1539 *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3);
1540 *(out++) = disp;
1541 *(out++) = disp >> 8;
1542 *(out++) = disp >> 16;
1543 *(out++) = disp >> 24;
1544 }
1545 code->cur = out;
1546}
1547
1548void xchg_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1549{
1550 check_alloc_code(code, 4);
1551 code_ptr out = code->cur;
1552 //TODO: Use OP_XCHG_AX when one of the registers is AX, EAX or RAX
1553 uint8_t tmp;
1554 if (size == SZ_W) {
1555 *(out++) = PRE_SIZE;
1556 }
1557 if (size == SZ_B && dst >= RSP && dst <= RDI) {
1558 tmp = dst;
1559 dst = src;
1560 src = tmp;
1561 }
1562 if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) {
1563 *out = PRE_REX;
1564 if (size == SZ_Q) {
1565 *out |= REX_QUAD;
1566 }
1567 if (src >= R8) {
1568 *out |= REX_REG_FIELD;
1569 src -= (R8 - X86_R8);
1570 }
1571 if (dst >= R8) {
1572 *out |= REX_RM_FIELD;
1573 dst -= (R8 - X86_R8);
1574 }
1575 out++;
1576 }
1577 uint8_t opcode = OP_XCHG;
1578 if (size == SZ_B) {
1579 if (src >= AH && src <= BH) {
1580 src -= (AH-X86_AH);
1581 }
1582 if (dst >= AH && dst <= BH) {
1583 dst -= (AH-X86_AH);
1584 }
1585 } else {
1586 opcode |= BIT_SIZE;
1587 }
1588 *(out++) = opcode;
1589 *(out++) = MODE_REG_DIRECT | dst | (src << 3);
1590 code->cur = out;
1591}
1592
1593void pushf(code_info *code)
1594{
1595 check_alloc_code(code, 1);
1596 code_ptr out = code->cur;
1597 *(out++) = OP_PUSHF;
1598 code->cur = out;
1599}
1600
1601void popf(code_info *code)
1602{
1603 check_alloc_code(code, 1);
1604 code_ptr out = code->cur;
1605 *(out++) = OP_POPF;
1606 code->cur = out;
1607}
1608
1609void push_r(code_info *code, uint8_t reg)
1610{
1611 check_alloc_code(code, 2);
1612 code_ptr out = code->cur;
1613 if (reg >= R8) {
1614 *(out++) = PRE_REX | REX_RM_FIELD;
1615 reg -= R8 - X86_R8;
1616 }
1617 *(out++) = OP_PUSH | reg;
1618 code->cur = out;
1619 code->stack_off += sizeof(void *);
1620}
1621
1622void push_rdisp(code_info *code, uint8_t base, int32_t disp)
1623{
1624 //This instruction has no explicit size, so we pass SZ_B
1625 //to avoid any prefixes or bits being set
1626 x86_rdisp_size(code, OP_SINGLE_EA, OP_EX_PUSH_EA, base, disp, SZ_B);
1627 code->stack_off += sizeof(void *);
1628}
1629
1630void pop_r(code_info *code, uint8_t reg)
1631{
1632 check_alloc_code(code, 2);
1633 code_ptr out = code->cur;
1634 if (reg >= R8) {
1635 *(out++) = PRE_REX | REX_RM_FIELD;
1636 reg -= R8 - X86_R8;
1637 }
1638 *(out++) = OP_POP | reg;
1639 code->cur = out;
1640 code->stack_off -= sizeof(void *);
1641}
1642
1643void pop_rind(code_info *code, uint8_t reg)
1644{
1645 check_alloc_code(code, 3);
1646 code_ptr out = code->cur;
1647 if (reg >= R8) {
1648 *(out++) = PRE_REX | REX_RM_FIELD;
1649 reg -= R8 - X86_R8;
1650 }
1651 *(out++) = PRE_XOP;
1652 *(out++) = MODE_REG_INDIRECT | reg;
1653 code->cur = out;
1654 code->stack_off -= sizeof(void *);
1655}
1656
1657void setcc_r(code_info *code, uint8_t cc, uint8_t dst)
1658{
1659 check_alloc_code(code, 4);
1660 code_ptr out = code->cur;
1661 if (dst >= R8) {
1662 *(out++) = PRE_REX | REX_RM_FIELD;
1663 dst -= R8 - X86_R8;
1664 } else if (dst >= RSP && dst <= RDI) {
1665 *(out++) = PRE_REX;
1666 } else if (dst >= AH && dst <= BH) {
1667 dst -= AH - X86_AH;
1668 }
1669 *(out++) = PRE_2BYTE;
1670 *(out++) = OP2_SETCC | cc;
1671 *(out++) = MODE_REG_DIRECT | dst;
1672 code->cur = out;
1673}
1674
1675void setcc_rind(code_info *code, uint8_t cc, uint8_t dst)
1676{
1677 check_alloc_code(code, 4);
1678 code_ptr out = code->cur;
1679 if (dst >= R8) {
1680 *(out++) = PRE_REX | REX_RM_FIELD;
1681 dst -= R8 - X86_R8;
1682 }
1683 *(out++) = PRE_2BYTE;
1684 *(out++) = OP2_SETCC | cc;
1685 *(out++) = MODE_REG_INDIRECT | dst;
1686 code->cur = out;
1687}
1688
1689void setcc_rdisp(code_info *code, uint8_t cc, uint8_t dst, int32_t disp)
1690{
1691 check_alloc_code(code, 8);
1692 code_ptr out = code->cur;
1693 if (dst >= R8) {
1694 *(out++) = PRE_REX | REX_RM_FIELD;
1695 dst -= R8 - X86_R8;
1696 }
1697 *(out++) = PRE_2BYTE;
1698 *(out++) = OP2_SETCC | cc;
1699 if (disp < 128 && disp >= -128) {
1700 *(out++) = MODE_REG_DISPLACE8 | dst;
1701 *(out++) = disp;
1702 } else {
1703 *(out++) = MODE_REG_DISPLACE32 | dst;
1704 *(out++) = disp;
1705 *(out++) = disp >> 8;
1706 *(out++) = disp >> 16;
1707 *(out++) = disp >> 24;
1708 }
1709 code->cur = out;
1710}
1711
1712void bit_rr(code_info *code, uint8_t op2, uint8_t src, uint8_t dst, uint8_t size)
1713{
1714 check_alloc_code(code, 5);
1715 code_ptr out = code->cur;
1716 if (size == SZ_W) {
1717 *(out++) = PRE_SIZE;
1718 }
1719 if (size == SZ_Q || src >= R8 || dst >= R8) {
1720 *out = PRE_REX;
1721 if (size == SZ_Q) {
1722 *out |= REX_QUAD;
1723 }
1724 if (src >= R8) {
1725 *out |= REX_REG_FIELD;
1726 src -= (R8 - X86_R8);
1727 }
1728 if (dst >= R8) {
1729 *out |= REX_RM_FIELD;
1730 dst -= (R8 - X86_R8);
1731 }
1732 out++;
1733 }
1734 *(out++) = PRE_2BYTE;
1735 *(out++) = op2;
1736 *(out++) = MODE_REG_DIRECT | dst | (src << 3);
1737 code->cur = out;
1738}
1739
1740void bit_rrdisp(code_info *code, uint8_t op2, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1741{
1742 check_alloc_code(code, 9);
1743 code_ptr out = code->cur;
1744 if (size == SZ_W) {
1745 *(out++) = PRE_SIZE;
1746 }
1747 if (size == SZ_Q || src >= R8 || dst_base >= R8) {
1748 *out = PRE_REX;
1749 if (size == SZ_Q) {
1750 *out |= REX_QUAD;
1751 }
1752 if (src >= R8) {
1753 *out |= REX_REG_FIELD;
1754 src -= (R8 - X86_R8);
1755 }
1756 if (dst_base >= R8) {
1757 *out |= REX_RM_FIELD;
1758 dst_base -= (R8 - X86_R8);
1759 }
1760 out++;
1761 }
1762 *(out++) = PRE_2BYTE;
1763 *(out++) = op2;
1764 if (dst_disp < 128 && dst_disp >= -128) {
1765 *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3);
1766 *(out++) = dst_disp;
1767 } else {
1768 *(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3);
1769 *(out++) = dst_disp;
1770 *(out++) = dst_disp >> 8;
1771 *(out++) = dst_disp >> 16;
1772 *(out++) = dst_disp >> 24;
1773 }
1774 code->cur = out;
1775}
1776
1777void bit_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
1778{
1779 check_alloc_code(code, 6);
1780 code_ptr out = code->cur;
1781 if (size == SZ_W) {
1782 *(out++) = PRE_SIZE;
1783 }
1784 if (size == SZ_Q || dst >= R8) {
1785 *out = PRE_REX;
1786 if (size == SZ_Q) {
1787 *out |= REX_QUAD;
1788 }
1789 if (dst >= R8) {
1790 *out |= REX_RM_FIELD;
1791 dst -= (R8 - X86_R8);
1792 }
1793 out++;
1794 }
1795 *(out++) = PRE_2BYTE;
1796 *(out++) = OP2_BTX_I;
1797 *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
1798 *(out++) = val;
1799 code->cur = out;
1800}
1801
1802void bit_irdisp(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1803{
1804 check_alloc_code(code, 10);
1805 code_ptr out = code->cur;
1806 if (size == SZ_W) {
1807 *(out++) = PRE_SIZE;
1808 }
1809 if (size == SZ_Q || dst_base >= R8) {
1810 *out = PRE_REX;
1811 if (size == SZ_Q) {
1812 *out |= REX_QUAD;
1813 }
1814 if (dst_base >= R8) {
1815 *out |= REX_RM_FIELD;
1816 dst_base -= (R8 - X86_R8);
1817 }
1818 out++;
1819 }
1820 *(out++) = PRE_2BYTE;
1821 *(out++) = OP2_BTX_I;
1822 if (dst_disp < 128 && dst_disp >= -128) {
1823 *(out++) = MODE_REG_DISPLACE8 | dst_base | (op_ex << 3);
1824 *(out++) = dst_disp;
1825 } else {
1826 *(out++) = MODE_REG_DISPLACE32 | dst_base | (op_ex << 3);
1827 *(out++) = dst_disp;
1828 *(out++) = dst_disp >> 8;
1829 *(out++) = dst_disp >> 16;
1830 *(out++) = dst_disp >> 24;
1831 }
1832 *(out++) = val;
1833 code->cur = out;
1834}
1835
1836void bt_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1837{
1838 return bit_rr(code, OP2_BT, src, dst, size);
1839}
1840
1841void bt_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1842{
1843 return bit_rrdisp(code, OP2_BT, src, dst_base, dst_disp, size);
1844}
1845
1846void bt_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
1847{
1848 return bit_ir(code, OP_EX_BT, val, dst, size);
1849}
1850
1851void bt_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1852{
1853 return bit_irdisp(code, OP_EX_BT, val, dst_base, dst_disp, size);
1854}
1855
1856void bts_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1857{
1858 return bit_rr(code, OP2_BTS, src, dst, size);
1859}
1860
1861void bts_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1862{
1863 return bit_rrdisp(code, OP2_BTS, src, dst_base, dst_disp, size);
1864}
1865
1866void bts_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
1867{
1868 return bit_ir(code, OP_EX_BTS, val, dst, size);
1869}
1870
1871void bts_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1872{
1873 return bit_irdisp(code, OP_EX_BTS, val, dst_base, dst_disp, size);
1874}
1875
1876void btr_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1877{
1878 return bit_rr(code, OP2_BTR, src, dst, size);
1879}
1880
1881void btr_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1882{
1883 return bit_rrdisp(code, OP2_BTR, src, dst_base, dst_disp, size);
1884}
1885
1886void btr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
1887{
1888 return bit_ir(code, OP_EX_BTR, val, dst, size);
1889}
1890
1891void btr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1892{
1893 return bit_irdisp(code, OP_EX_BTR, val, dst_base, dst_disp, size);
1894}
1895
1896void btc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1897{
1898 return bit_rr(code, OP2_BTC, src, dst, size);
1899}
1900
1901void btc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1902{
1903 return bit_rrdisp(code, OP2_BTC, src, dst_base, dst_disp, size);
1904}
1905
1906void btc_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
1907{
1908 return bit_ir(code, OP_EX_BTC, val, dst, size);
1909}
1910
1911void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1912{
1913 return bit_irdisp(code, OP_EX_BTC, val, dst_base, dst_disp, size);
1914}
1915
1916void jcc(code_info *code, uint8_t cc, code_ptr dest)
1917{
1918 check_alloc_code(code, 6);
1919 code_ptr out = code->cur;
1920 ptrdiff_t disp = dest-(out+2);
1921 if (disp <= 0x7F && disp >= -0x80) {
1922 *(out++) = OP_JCC | cc;
1923 *(out++) = disp;
1924 } else {
1925 disp = dest-(out+6);
1926 if (CHECK_DISP(disp)) {
1927 *(out++) = PRE_2BYTE;
1928 *(out++) = OP2_JCC | cc;
1929 *(out++) = disp;
1930 disp >>= 8;
1931 *(out++) = disp;
1932 disp >>= 8;
1933 *(out++) = disp;
1934 disp >>= 8;
1935 *(out++) = disp;
1936 } else {
1937 fatal_error("jcc: %p - %p = %lX which is out of range for a 32-bit displacement\n", dest, out + 6, (long)disp);
1938 }
1939 }
1940 code->cur = out;
1941}
1942
1943void jmp(code_info *code, code_ptr dest)
1944{
1945 check_alloc_code(code, 5);
1946 code_ptr out = code->cur;
1947 ptrdiff_t disp = dest-(out+2);
1948 if (disp <= 0x7F && disp >= -0x80) {
1949 *(out++) = OP_JMP_BYTE;
1950 *(out++) = disp;
1951 } else {
1952 disp = dest-(out+5);
1953 if (CHECK_DISP(disp)) {
1954 *(out++) = OP_JMP;
1955 *(out++) = disp;
1956 disp >>= 8;
1957 *(out++) = disp;
1958 disp >>= 8;
1959 *(out++) = disp;
1960 disp >>= 8;
1961 *(out++) = disp;
1962 } else {
1963 fatal_error("jmp: %p - %p = %lX which is out of range for a 32-bit displacement\n", dest, out + 6, (long)disp);
1964 }
1965 }
1966 code->cur = out;
1967}
1968
1969void jmp_r(code_info *code, uint8_t dst)
1970{
1971 check_alloc_code(code, 3);
1972 code_ptr out = code->cur;
1973 if (dst >= R8) {
1974 dst -= R8 - X86_R8;
1975 *(out++) = PRE_REX | REX_RM_FIELD;
1976 }
1977 *(out++) = OP_SINGLE_EA;
1978 *(out++) = MODE_REG_DIRECT | dst | (OP_EX_JMP_EA << 3);
1979 code->cur = out;
1980}
1981
1982void jmp_rind(code_info *code, uint8_t dst)
1983{
1984 check_alloc_code(code, 3);
1985 code_ptr out = code->cur;
1986 if (dst >= R8) {
1987 dst -= R8 - X86_R8;
1988 *(out++) = PRE_REX | REX_RM_FIELD;
1989 }
1990 *(out++) = OP_SINGLE_EA;
1991 *(out++) = MODE_REG_INDIRECT | dst | (OP_EX_JMP_EA << 3);
1992 code->cur = out;
1993}
1994
1995void call_noalign(code_info *code, code_ptr fun)
1996{
1997 check_alloc_code(code, 5);
1998 code_ptr out = code->cur;
1999 ptrdiff_t disp = fun-(out+5);
2000 if (CHECK_DISP(disp)) {
2001 *(out++) = OP_CALL;
2002 *(out++) = disp;
2003 disp >>= 8;
2004 *(out++) = disp;
2005 disp >>= 8;
2006 *(out++) = disp;
2007 disp >>= 8;
2008 *(out++) = disp;
2009 } else {
2010 //TODO: Implement far call???
2011 fatal_error("call: %p - %p = %lX which is out of range for a 32-bit displacement\n", fun, out + 5, (long)disp);
2012 }
2013 code->cur = out;
2014}
2015
2016volatile int foo;
2017void call(code_info *code, code_ptr fun)
2018{
2019 foo = *fun;
2020 code->stack_off += sizeof(void *);
2021 int32_t adjust = 0;
2022 if (code->stack_off & 0xF) {
2023 adjust = 16 - (code->stack_off & 0xF);
2024 code->stack_off += adjust;
2025 sub_ir(code, adjust, RSP, SZ_PTR);
2026 }
2027 call_noalign(code, fun);
2028 if (adjust) {
2029 add_ir(code, adjust, RSP, SZ_PTR);
2030 }
2031 code->stack_off -= sizeof(void *) + adjust;
2032}
2033void call_raxfallback(code_info *code, code_ptr fun)
2034{
2035 check_alloc_code(code, 5);
2036 code_ptr out = code->cur;
2037 ptrdiff_t disp = fun-(out+5);
2038 if (CHECK_DISP(disp)) {
2039 *(out++) = OP_CALL;
2040 *(out++) = disp;
2041 disp >>= 8;
2042 *(out++) = disp;
2043 disp >>= 8;
2044 *(out++) = disp;
2045 disp >>= 8;
2046 *(out++) = disp;
2047 code->cur = out;
2048 } else {
2049 mov_ir(code, (int64_t)fun, RAX, SZ_PTR);
2050 call_r(code, RAX);
2051 }
2052}
2053
2054void call_r(code_info *code, uint8_t dst)
2055{
2056 code->stack_off += sizeof(void *);
2057 int32_t adjust = 0;
2058 if (code->stack_off & 0xF) {
2059 adjust = 16 - (code->stack_off & 0xF);
2060 code->stack_off += adjust;
2061 sub_ir(code, adjust, RSP, SZ_PTR);
2062 }
2063 check_alloc_code(code, 2);
2064 code_ptr out = code->cur;
2065 *(out++) = OP_SINGLE_EA;
2066 *(out++) = MODE_REG_DIRECT | dst | (OP_EX_CALL_EA << 3);
2067 code->cur = out;
2068 if (adjust) {
2069 add_ir(code, adjust, RSP, SZ_PTR);
2070 }
2071 code->stack_off -= sizeof(void *) + adjust;
2072}
2073
2074void retn(code_info *code)
2075{
2076 check_alloc_code(code, 1);
2077 code_ptr out = code->cur;
2078 *(out++) = OP_RETN;
2079 code->cur = out;
2080}
2081
2082void rts(code_info *code)
2083{
2084 retn(code);
2085}
2086
2087void cdq(code_info *code)
2088{
2089 check_alloc_code(code, 1);
2090 code_ptr out = code->cur;
2091 *(out++) = OP_CDQ;
2092 code->cur = out;
2093}
2094
2095void loop(code_info *code, code_ptr dst)
2096{
2097 check_alloc_code(code, 2);
2098 code_ptr out = code->cur;
2099 ptrdiff_t disp = dst-(out+2);
2100 *(out++) = OP_LOOP;
2101 *(out++) = disp;
2102 code->cur = out;
2103}
2104
2105uint32_t prep_args(code_info *code, uint32_t num_args, va_list args)
2106{
2107 uint8_t *arg_arr = malloc(num_args);
2108 for (int i = 0; i < num_args; i ++)
2109 {
2110 arg_arr[i] = va_arg(args, int);
2111 }
2112#ifdef X86_64
2113 uint32_t stack_args = 0;
2114 uint8_t abi_regs[] = {RDI, RSI, RDX, RCX, R8, R9};
2115 int8_t reg_swap[R15+1];
2116 uint32_t usage = 0;
2117 memset(reg_swap, -1, sizeof(reg_swap));
2118 for (int i = 0; i < num_args; i ++)
2119 {
2120 usage |= 1 << arg_arr[i];
2121 }
2122 for (int i = 0; i < num_args; i ++)
2123 {
2124 uint8_t reg_arg = arg_arr[i];
2125 if (i < sizeof(abi_regs)) {
2126 if (reg_swap[reg_arg] >= 0) {
2127 reg_arg = reg_swap[reg_arg];
2128 }
2129 if (reg_arg != abi_regs[i]) {
2130 if (usage & (1 << abi_regs[i])) {
2131 xchg_rr(code, reg_arg, abi_regs[i], SZ_PTR);
2132 reg_swap[abi_regs[i]] = reg_arg;
2133 } else {
2134 mov_rr(code, reg_arg, abi_regs[i], SZ_PTR);
2135 }
2136 }
2137 } else {
2138 arg_arr[stack_args++] = reg_arg;
2139 }
2140 }
2141#else
2142#define stack_args num_args
2143#endif
2144 uint32_t stack_off_call = code->stack_off + sizeof(void *) * (stack_args + 1);
2145 uint32_t adjust = 0;
2146 if (stack_off_call & 0xF) {
2147 adjust = 16 - (stack_off_call & 0xF);
2148 sub_ir(code, adjust, RSP, SZ_PTR);
2149 code->stack_off += adjust;
2150 }
2151 for (int i = stack_args -1; i >= 0; i--)
2152 {
2153 push_r(code, arg_arr[i]);
2154 }
2155 free(arg_arr);
2156
2157 return stack_args * sizeof(void *) + adjust;
2158}
2159
2160void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...)
2161{
2162 va_list args;
2163 va_start(args, num_args);
2164 uint32_t adjust = prep_args(code, num_args, args);
2165 va_end(args);
2166 call_raxfallback(code, fun);
2167 if (adjust) {
2168 add_ir(code, adjust, RSP, SZ_PTR);
2169 code->stack_off -= adjust;
2170 }
2171}
2172
2173void call_args_r(code_info *code, uint8_t fun_reg, uint32_t num_args, ...)
2174{
2175 va_list args;
2176 va_start(args, num_args);
2177 uint32_t adjust = prep_args(code, num_args, args);
2178 va_end(args);
2179 call_r(code, fun_reg);
2180 if (adjust) {
2181 add_ir(code, adjust, RSP, SZ_PTR);
2182 code->stack_off -= adjust;
2183 }
2184}
2185/*
2186void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...)
2187{
2188 va_list args;
2189 va_start(args, num_args);
2190 uint32_t adjust = prep_args(code, num_args, args);
2191 va_end(args);
2192#ifdef X86_64
2193 test_ir(code, 8, RSP, SZ_PTR); //check stack alignment
2194 code_ptr do_adjust_rsp = code->cur + 1;
2195 jcc(code, CC_NZ, code->cur + 2);
2196#endif
2197 call_raxfallback(code, fun);
2198 if (adjust) {
2199 add_ir(code, adjust, RSP, SZ_PTR);
2200 }
2201#ifdef X86_64
2202 code_ptr no_adjust_rsp = code->cur + 1;
2203 jmp(code, code->cur + 2);
2204 *do_adjust_rsp = code->cur - (do_adjust_rsp+1);
2205 sub_ir(code, 8, RSP, SZ_PTR);
2206 call_raxfallback(code, fun);
2207 add_ir(code, adjust + 8 , RSP, SZ_PTR);
2208 *no_adjust_rsp = code->cur - (no_adjust_rsp+1);
2209#endif
2210}
2211*/
2212void save_callee_save_regs(code_info *code)
2213{
2214 push_r(code, RBX);
2215 push_r(code, RBP);
2216#ifdef X86_64
2217 push_r(code, R12);
2218 push_r(code, R13);
2219 push_r(code, R14);
2220 push_r(code, R15);
2221#else
2222 push_r(code, RDI);
2223 push_r(code, RSI);
2224#endif
2225}
2226
2227void restore_callee_save_regs(code_info *code)
2228{
2229#ifdef X86_64
2230 pop_r(code, R15);
2231 pop_r(code, R14);
2232 pop_r(code, R13);
2233 pop_r(code, R12);
2234#else
2235 pop_r(code, RSI);
2236 pop_r(code, RDI);
2237#endif
2238 pop_r(code, RBP);
2239 pop_r(code, RBX);
2240}
2241
2242uint8_t has_modrm(uint8_t prefix, uint8_t opcode)
2243{
2244 if (!prefix) {
2245 switch (opcode)
2246 {
2247 case OP_JMP:
2248 case OP_JMP_BYTE:
2249 case OP_JCC:
2250 case OP_CALL:
2251 case OP_RETN:
2252 case OP_LOOP:
2253 case OP_MOV_I8R:
2254 case OP_MOV_IR:
2255 case OP_PUSHF:
2256 case OP_POPF:
2257 case OP_PUSH:
2258 case OP_POP:
2259 case OP_CDQ:
2260 return 0;
2261 }
2262 } else if (prefix == PRE_2BYTE) {
2263 switch (opcode)
2264 {
2265 case OP2_JCC:
2266 return 0;
2267 }
2268 }
2269 return 1;
2270}
2271
2272uint8_t has_sib(uint8_t mod_rm)
2273{
2274 uint8_t mode = mod_rm & 0xC0;
2275 uint8_t rm = mod_rm & 3;
2276
2277 return mode != MODE_REG_DIRECT && rm == RSP;
2278}
2279
2280uint32_t x86_inst_size(code_ptr start)
2281{
2282 code_ptr code = start;
2283 uint8_t cont = 1;
2284 uint8_t prefix = 0;
2285 uint8_t op_size = SZ_B;
2286 uint8_t main_op;
2287
2288 while (cont)
2289 {
2290 if (*code == PRE_SIZE) {
2291 op_size = SZ_W;
2292 } else if (*code == PRE_REX) {
2293 if (*code & REX_QUAD) {
2294 op_size = SZ_Q;
2295 }
2296 } else if(*code == PRE_2BYTE || *code == PRE_XOP) {
2297 prefix = *code;
2298 } else {
2299 main_op = *code;
2300 cont = 0;
2301 }
2302 code++;
2303 }
2304 if (has_modrm(prefix, main_op)) {
2305 uint8_t mod_rm = *(code++);
2306 if (has_sib(mod_rm)) {
2307 //sib takes up a byte, but can't add any additional ones beyond that
2308 code++;
2309 }
2310 uint8_t mode = mod_rm & 0xC0;
2311 uint8_t rm = mod_rm & 3;
2312 if (mode == MODE_REG_DISPLACE8) {
2313 code++;
2314 } else if (mode == MODE_REG_DISPLACE32 || (mode == MODE_REG_INDIRECT && rm == RBP)) {
2315 code += 4;
2316 }
2317 } else {
2318 }
2319
2320 return code-start;
2321}