comparison gen_x86.c @ 744:fc68992cf18d

Merge windows branch with latest changes
author Michael Pavone <pavone@retrodev.com>
date Thu, 28 May 2015 21:19:55 -0700
parents cb1c005880e7
children cfa402c6ced8
comparison
equal deleted inserted replaced
743:cf78cb045fa4 744:fc68992cf18d
6 #include "gen_x86.h" 6 #include "gen_x86.h"
7 #include "mem.h" 7 #include "mem.h"
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <stdio.h> 9 #include <stdio.h>
10 #include <stdlib.h> 10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <string.h>
11 13
12 #define REX_RM_FIELD 0x1 14 #define REX_RM_FIELD 0x1
13 #define REX_SIB_FIELD 0x2 15 #define REX_SIB_FIELD 0x2
14 #define REX_REG_FIELD 0x4 16 #define REX_REG_FIELD 0x4
15 #define REX_QUAD 0x8 17 #define REX_QUAD 0x8
31 #define OP_JCC 0x70 33 #define OP_JCC 0x70
32 #define OP_IMMED_ARITH 0x80 34 #define OP_IMMED_ARITH 0x80
33 #define OP_TEST 0x84 35 #define OP_TEST 0x84
34 #define OP_XCHG 0x86 36 #define OP_XCHG 0x86
35 #define OP_MOV 0x88 37 #define OP_MOV 0x88
38 #define PRE_XOP 0x8F
36 #define OP_XCHG_AX 0x90 39 #define OP_XCHG_AX 0x90
37 #define OP_CDQ 0x99 40 #define OP_CDQ 0x99
38 #define OP_PUSHF 0x9C 41 #define OP_PUSHF 0x9C
39 #define OP_POPF 0x9D 42 #define OP_POPF 0x9D
40 #define OP_MOV_I8R 0xB0 43 #define OP_MOV_I8R 0xB0
125 X86_R13, 128 X86_R13,
126 X86_R14, 129 X86_R14,
127 X86_R15 130 X86_R15
128 } x86_regs_enc; 131 } x86_regs_enc;
129 132
133 char * x86_reg_names[] = {
134 #ifdef X86_64
135 "rax",
136 "rcx",
137 "rdx",
138 "rbx",
139 "rsp",
140 "rbp",
141 "rsi",
142 "rdi",
143 #else
144 "eax",
145 "ecx",
146 "edx",
147 "ebx",
148 "esp",
149 "ebp",
150 "esi",
151 "edi",
152 #endif
153 "ah",
154 "ch",
155 "dh",
156 "bh",
157 "r8",
158 "r9",
159 "r10",
160 "r11",
161 "r12",
162 "r13",
163 "r14",
164 "r15",
165 };
166
167 char * x86_sizes[] = {
168 "b", "w", "d", "q"
169 };
170
130 void jmp_nocheck(code_info *code, code_ptr dest) 171 void jmp_nocheck(code_info *code, code_ptr dest)
131 { 172 {
132 code_ptr out = code->cur; 173 code_ptr out = code->cur;
133 ptrdiff_t disp = dest-(out+2); 174 ptrdiff_t disp = dest-(out+2);
134 if (disp <= 0x7F && disp >= -0x80) { 175 if (disp <= 0x7F && disp >= -0x80) {
185 tmp = dst; 226 tmp = dst;
186 dst = src; 227 dst = src;
187 src = tmp; 228 src = tmp;
188 } 229 }
189 if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) { 230 if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) {
231 #ifdef X86_64
190 *out = PRE_REX; 232 *out = PRE_REX;
191 if (src >= AH && src <= BH || dst >= AH && dst <= BH) { 233 if (src >= AH && src <= BH || dst >= AH && dst <= BH) {
192 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); 234 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
193 exit(1); 235 exit(1);
194 } 236 }
202 if (dst >= R8) { 244 if (dst >= R8) {
203 *out |= REX_RM_FIELD; 245 *out |= REX_RM_FIELD;
204 dst -= (R8 - X86_R8); 246 dst -= (R8 - X86_R8);
205 } 247 }
206 out++; 248 out++;
249 #else
250 fprintf(stderr, "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]);
251 exit(1);
252 #endif
207 } 253 }
208 if (size == SZ_B) { 254 if (size == SZ_B) {
209 if (src >= AH && src <= BH) { 255 if (src >= AH && src <= BH) {
210 src -= (AH-X86_AH); 256 src -= (AH-X86_AH);
211 } 257 }
233 uint8_t tmp; 279 uint8_t tmp;
234 if (size == SZ_W) { 280 if (size == SZ_W) {
235 *(out++) = PRE_SIZE; 281 *(out++) = PRE_SIZE;
236 } 282 }
237 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) { 283 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
284 #ifdef X86_64
238 *out = PRE_REX; 285 *out = PRE_REX;
239 if (reg >= AH && reg <= BH) { 286 if (reg >= AH && reg <= BH) {
240 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); 287 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
241 exit(1); 288 exit(1);
242 } 289 }
250 if (base >= R8) { 297 if (base >= R8) {
251 *out |= REX_RM_FIELD; 298 *out |= REX_RM_FIELD;
252 base -= (R8 - X86_R8); 299 base -= (R8 - X86_R8);
253 } 300 }
254 out++; 301 out++;
302 #else
303 fprintf(stderr, "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]);
304 exit(1);
305 #endif
255 } 306 }
256 if (size == SZ_B) { 307 if (size == SZ_B) {
257 if (reg >= AH && reg <= BH) { 308 if (reg >= AH && reg <= BH) {
258 reg -= (AH-X86_AH); 309 reg -= (AH-X86_AH);
259 } 310 }
266 *(out++) = opcode; 317 *(out++) = opcode;
267 } else { 318 } else {
268 *(out++) = opcode; 319 *(out++) = opcode;
269 } 320 }
270 if (disp < 128 && disp >= -128) { 321 if (disp < 128 && disp >= -128) {
271 *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3); 322 *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
272 } else { 323 } else {
273 *(out++) = MODE_REG_DISPLACE32 | base | (reg << 3); 324 *(out++) = MODE_REG_DISPLACE32 | base | (reg << 3);
274 } 325 }
275 if (base == RSP) { 326 if (base == RSP) {
276 //add SIB byte, with no index and RSP as base 327 //add SIB byte, with no index and RSP as base
277 *(out++) = (RSP << 3) | RSP; 328 *(out++) = (RSP << 3) | RSP;
278 } 329 }
279 *(out++) = disp; 330 *(out++) = disp;
280 if (disp >= 128 || disp < -128) { 331 if (disp >= 128 || disp < -128) {
281 *(out++) = disp >> 8; 332 *(out++) = disp >> 8;
282 *(out++) = disp >> 16; 333 *(out++) = disp >> 16;
283 *(out++) = disp >> 24; 334 *(out++) = disp >> 24;
284 } 335 }
285 code->cur = out; 336 code->cur = out;
286 } 337 }
287 338
288 void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir) 339 void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir)
293 uint8_t tmp; 344 uint8_t tmp;
294 if (size == SZ_W) { 345 if (size == SZ_W) {
295 *(out++) = PRE_SIZE; 346 *(out++) = PRE_SIZE;
296 } 347 }
297 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) { 348 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
349 #ifdef X86_64
298 *out = PRE_REX; 350 *out = PRE_REX;
299 if (reg >= AH && reg <= BH) { 351 if (reg >= AH && reg <= BH) {
300 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); 352 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
301 exit(1); 353 exit(1);
302 } 354 }
310 if (base >= R8) { 362 if (base >= R8) {
311 *out |= REX_RM_FIELD; 363 *out |= REX_RM_FIELD;
312 base -= (R8 - X86_R8); 364 base -= (R8 - X86_R8);
313 } 365 }
314 out++; 366 out++;
367 #else
368 fprintf(stderr, "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 exit(1);
370 #endif
315 } 371 }
316 if (size == SZ_B) { 372 if (size == SZ_B) {
317 if (reg >= AH && reg <= BH) { 373 if (reg >= AH && reg <= BH) {
318 reg -= (AH-X86_AH); 374 reg -= (AH-X86_AH);
319 } 375 }
320 } else { 376 } else {
321 opcode |= BIT_SIZE; 377 opcode |= BIT_SIZE;
322 } 378 }
323 *(out++) = opcode | dir; 379 *(out++) = opcode | dir;
380 if (base == RBP) {
381 //add a dummy 8-bit displacement since MODE_REG_INDIRECT with
382 //an R/M field of RBP selects RIP, relative addressing
383 *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
384 *(out++) = 0;
385 } else {
324 *(out++) = MODE_REG_INDIRECT | base | (reg << 3); 386 *(out++) = MODE_REG_INDIRECT | base | (reg << 3);
325 if (base == RSP) { 387 if (base == RSP) {
326 //add SIB byte, with no index and RSP as base 388 //add SIB byte, with no index and RSP as base
327 *(out++) = (RSP << 3) | RSP; 389 *(out++) = (RSP << 3) | RSP;
328 } 390 }
391 }
329 code->cur = out; 392 code->cur = out;
330 } 393 }
331 394
332 void 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 void 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)
333 { 396 {
337 uint8_t tmp; 400 uint8_t tmp;
338 if (size == SZ_W) { 401 if (size == SZ_W) {
339 *(out++) = PRE_SIZE; 402 *(out++) = PRE_SIZE;
340 } 403 }
341 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) { 404 if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
405 #ifdef X86_64
342 *out = PRE_REX; 406 *out = PRE_REX;
343 if (reg >= AH && reg <= BH) { 407 if (reg >= AH && reg <= BH) {
344 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); 408 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
345 exit(1); 409 exit(1);
346 } 410 }
358 if (index >= R8) { 422 if (index >= R8) {
359 *out |= REX_SIB_FIELD; 423 *out |= REX_SIB_FIELD;
360 index -= (R8 - X86_R8); 424 index -= (R8 - X86_R8);
361 } 425 }
362 out++; 426 out++;
427 #else
428 fprintf(stderr, "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]);
429 exit(1);
430 #endif
363 } 431 }
364 if (size == SZ_B) { 432 if (size == SZ_B) {
365 if (reg >= AH && reg <= BH) { 433 if (reg >= AH && reg <= BH) {
366 reg -= (AH-X86_AH); 434 reg -= (AH-X86_AH);
367 } 435 }
371 *(out++) = opcode | dir; 439 *(out++) = opcode | dir;
372 *(out++) = MODE_REG_INDIRECT | RSP | (reg << 3); 440 *(out++) = MODE_REG_INDIRECT | RSP | (reg << 3);
373 if (scale == 4) { 441 if (scale == 4) {
374 scale = 2; 442 scale = 2;
375 } else if(scale == 8) { 443 } else if(scale == 8) {
376 scale = 3; 444 scale = 3;
377 } else { 445 } else {
378 scale--; 446 scale--;
379 } 447 }
380 *(out++) = scale << 6 | (index << 3) | base; 448 *(out++) = scale << 6 | (index << 3) | base;
381 code->cur = out; 449 code->cur = out;
388 uint8_t tmp; 456 uint8_t tmp;
389 if (size == SZ_W) { 457 if (size == SZ_W) {
390 *(out++) = PRE_SIZE; 458 *(out++) = PRE_SIZE;
391 } 459 }
392 if (size == SZ_Q || dst >= R8) { 460 if (size == SZ_Q || dst >= R8) {
461 #ifdef X86_64
393 *out = PRE_REX; 462 *out = PRE_REX;
394 if (dst >= AH && dst <= BH) { 463 if (dst >= AH && dst <= BH) {
395 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); 464 fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
396 exit(1); 465 exit(1);
397 } 466 }
401 if (dst >= R8) { 470 if (dst >= R8) {
402 *out |= REX_RM_FIELD; 471 *out |= REX_RM_FIELD;
403 dst -= (R8 - X86_R8); 472 dst -= (R8 - X86_R8);
404 } 473 }
405 out++; 474 out++;
475 #else
476 fprintf(stderr, "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]);
477 exit(1);
478 #endif
406 } 479 }
407 if (size == SZ_B) { 480 if (size == SZ_B) {
408 if (dst >= AH && dst <= BH) { 481 if (dst >= AH && dst <= BH) {
409 dst -= (AH-X86_AH); 482 dst -= (AH-X86_AH);
410 } 483 }
423 uint8_t tmp; 496 uint8_t tmp;
424 if (size == SZ_W) { 497 if (size == SZ_W) {
425 *(out++) = PRE_SIZE; 498 *(out++) = PRE_SIZE;
426 } 499 }
427 if (size == SZ_Q || dst >= R8) { 500 if (size == SZ_Q || dst >= R8) {
501 #ifdef X86_64
428 *out = PRE_REX; 502 *out = PRE_REX;
429 if (size == SZ_Q) { 503 if (size == SZ_Q) {
430 *out |= REX_QUAD; 504 *out |= REX_QUAD;
431 } 505 }
432 if (dst >= R8) { 506 if (dst >= R8) {
433 *out |= REX_RM_FIELD; 507 *out |= REX_RM_FIELD;
434 dst -= (R8 - X86_R8); 508 dst -= (R8 - X86_R8);
435 } 509 }
436 out++; 510 out++;
511 #else
512 fprintf(stderr, "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]);
513 exit(1);
514 #endif
437 } 515 }
438 if (size != SZ_B) { 516 if (size != SZ_B) {
439 opcode |= BIT_SIZE; 517 opcode |= BIT_SIZE;
440 } 518 }
441 *(out++) = opcode; 519 *(out++) = opcode;
442 if (disp < 128 && disp >= -128) { 520 if (disp < 128 && disp >= -128) {
443 *(out++) = MODE_REG_DISPLACE8 | dst | (opex << 3); 521 *(out++) = MODE_REG_DISPLACE8 | dst | (opex << 3);
444 *(out++) = disp; 522 *(out++) = disp;
445 } else { 523 } else {
446 *(out++) = MODE_REG_DISPLACE32 | dst | (opex << 3); 524 *(out++) = MODE_REG_DISPLACE32 | dst | (opex << 3);
447 *(out++) = disp; 525 *(out++) = disp;
448 *(out++) = disp >> 8; 526 *(out++) = disp >> 8;
449 *(out++) = disp >> 16; 527 *(out++) = disp >> 16;
466 } 544 }
467 if (dst == RAX && !sign_extend) { 545 if (dst == RAX && !sign_extend) {
468 if (size != SZ_B) { 546 if (size != SZ_B) {
469 al_opcode |= BIT_SIZE; 547 al_opcode |= BIT_SIZE;
470 if (size == SZ_Q) { 548 if (size == SZ_Q) {
549 #ifdef X86_64
471 *out = PRE_REX | REX_QUAD; 550 *out = PRE_REX | REX_QUAD;
551 #else
552 fprintf(stderr, "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]);
553 exit(1);
554 #endif
472 } 555 }
473 } 556 }
474 *(out++) = al_opcode | BIT_IMMED_RAX; 557 *(out++) = al_opcode | BIT_IMMED_RAX;
475 } else { 558 } else {
476 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) { 559 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
560 #ifdef X86_64
477 *out = PRE_REX; 561 *out = PRE_REX;
478 if (size == SZ_Q) { 562 if (size == SZ_Q) {
479 *out |= REX_QUAD; 563 *out |= REX_QUAD;
480 } 564 }
481 if (dst >= R8) { 565 if (dst >= R8) {
482 *out |= REX_RM_FIELD; 566 *out |= REX_RM_FIELD;
483 dst -= (R8 - X86_R8); 567 dst -= (R8 - X86_R8);
484 } 568 }
485 out++; 569 out++;
570 #else
571 fprintf(stderr, "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]);
572 exit(1);
573 #endif
486 } 574 }
487 if (dst >= AH && dst <= BH) { 575 if (dst >= AH && dst <= BH) {
488 dst -= (AH-X86_AH); 576 dst -= (AH-X86_AH);
489 } 577 }
490 if (size != SZ_B) { 578 if (size != SZ_B) {
519 if (size == SZ_W) { 607 if (size == SZ_W) {
520 *(out++) = PRE_SIZE; 608 *(out++) = PRE_SIZE;
521 } 609 }
522 610
523 if (size == SZ_Q || dst >= R8) { 611 if (size == SZ_Q || dst >= R8) {
612 #ifdef X86_64
524 *out = PRE_REX; 613 *out = PRE_REX;
525 if (size == SZ_Q) { 614 if (size == SZ_Q) {
526 *out |= REX_QUAD; 615 *out |= REX_QUAD;
527 } 616 }
528 if (dst >= R8) { 617 if (dst >= R8) {
529 *out |= REX_RM_FIELD; 618 *out |= REX_RM_FIELD;
530 dst -= (R8 - X86_R8); 619 dst -= (R8 - X86_R8);
531 } 620 }
532 out++; 621 out++;
622 #else
623 fprintf(stderr, "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]);
624 exit(1);
625 #endif
533 } 626 }
534 if (size != SZ_B) { 627 if (size != SZ_B) {
535 opcode |= BIT_SIZE; 628 opcode |= BIT_SIZE;
536 } 629 }
537 *(out++) = opcode; 630 *(out++) = opcode;
538 if (disp < 128 && disp >= -128) { 631 if (disp < 128 && disp >= -128) {
539 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); 632 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
540 *(out++) = disp; 633 *(out++) = disp;
541 } else { 634 } else {
542 *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3); 635 *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
543 *(out++) = disp; 636 *(out++) = disp;
544 disp >>= 8; 637 disp >>= 8;
545 *(out++) = disp; 638 *(out++) = disp;
546 disp >>= 8; 639 disp >>= 8;
547 *(out++) = disp; 640 *(out++) = disp;
548 disp >>= 8; 641 disp >>= 8;
549 *(out++) = disp; 642 *(out++) = disp;
550 } 643 }
551 *(out++) = val; 644 *(out++) = val;
552 if (size != SZ_B && !sign_extend) { 645 if (size != SZ_B && !sign_extend) {
553 val >>= 8; 646 val >>= 8;
554 *(out++) = val; 647 *(out++) = val;
614 dst -= (AH-X86_AH); 707 dst -= (AH-X86_AH);
615 } 708 }
616 709
617 *(out++) = (val == 1 ? OP_SHIFTROT_1: OP_SHIFTROT_IR) | (size == SZ_B ? 0 : BIT_SIZE); 710 *(out++) = (val == 1 ? OP_SHIFTROT_1: OP_SHIFTROT_IR) | (size == SZ_B ? 0 : BIT_SIZE);
618 if (disp < 128 && disp >= -128) { 711 if (disp < 128 && disp >= -128) {
619 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); 712 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
620 *(out++) = disp; 713 *(out++) = disp;
621 } else { 714 } else {
622 *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3); 715 *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
623 *(out++) = disp; 716 *(out++) = disp;
624 *(out++) = disp >> 8; 717 *(out++) = disp >> 8;
625 *(out++) = disp >> 16; 718 *(out++) = disp >> 16;
680 dst -= (AH-X86_AH); 773 dst -= (AH-X86_AH);
681 } 774 }
682 775
683 *(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE); 776 *(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE);
684 if (disp < 128 && disp >= -128) { 777 if (disp < 128 && disp >= -128) {
685 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); 778 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
686 *(out++) = disp; 779 *(out++) = disp;
687 } else { 780 } else {
688 *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3); 781 *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
689 *(out++) = disp; 782 *(out++) = disp;
690 *(out++) = disp >> 8; 783 *(out++) = disp >> 8;
691 *(out++) = disp >> 16; 784 *(out++) = disp >> 16;
692 *(out++) = disp >> 24; 785 *(out++) = disp >> 24;
693 } 786 }
694 code->cur = out; 787 code->cur = out;
695 } 788 }
696 789
697 void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size) 790 void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
698 { 791 {
1241 if (dst >= AH && dst <= BH) { 1334 if (dst >= AH && dst <= BH) {
1242 dst -= (AH-X86_AH); 1335 dst -= (AH-X86_AH);
1243 } 1336 }
1244 *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE); 1337 *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE);
1245 if (disp < 128 && disp >= -128) { 1338 if (disp < 128 && disp >= -128) {
1246 *(out++) = MODE_REG_DISPLACE8 | dst; 1339 *(out++) = MODE_REG_DISPLACE8 | dst;
1247 *(out++) = disp; 1340 *(out++) = disp;
1248 } else { 1341 } else {
1249 *(out++) = MODE_REG_DISPLACE32 | dst; 1342 *(out++) = MODE_REG_DISPLACE32 | dst;
1250 *(out++) = disp; 1343 *(out++) = disp;
1251 *(out++) = disp >> 8; 1344 *(out++) = disp >> 8;
1252 *(out++) = disp >> 16; 1345 *(out++) = disp >> 16;
1364 } else { 1457 } else {
1365 *(out++) = PRE_2BYTE; 1458 *(out++) = PRE_2BYTE;
1366 *(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE); 1459 *(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE);
1367 } 1460 }
1368 if (disp < 128 && disp >= -128) { 1461 if (disp < 128 && disp >= -128) {
1369 *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3); 1462 *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
1370 *(out++) = disp; 1463 *(out++) = disp;
1371 } else { 1464 } else {
1372 *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3); 1465 *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3);
1373 *(out++) = disp; 1466 *(out++) = disp;
1374 *(out++) = disp >> 8; 1467 *(out++) = disp >> 8;
1375 *(out++) = disp >> 16; 1468 *(out++) = disp >> 16;
1429 out++; 1522 out++;
1430 } 1523 }
1431 *(out++) = PRE_2BYTE; 1524 *(out++) = PRE_2BYTE;
1432 *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE); 1525 *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE);
1433 if (disp < 128 && disp >= -128) { 1526 if (disp < 128 && disp >= -128) {
1434 *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3); 1527 *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
1435 *(out++) = disp; 1528 *(out++) = disp;
1436 } else { 1529 } else {
1437 *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3); 1530 *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3);
1438 *(out++) = disp; 1531 *(out++) = disp;
1439 *(out++) = disp >> 8; 1532 *(out++) = disp >> 8;
1440 *(out++) = disp >> 16; 1533 *(out++) = disp >> 16;
1514 } 1607 }
1515 *(out++) = OP_PUSH | reg; 1608 *(out++) = OP_PUSH | reg;
1516 code->cur = out; 1609 code->cur = out;
1517 } 1610 }
1518 1611
1612 void push_rdisp(code_info *code, uint8_t base, int32_t disp)
1613 {
1614 //This instruction has no explicit size, so we pass SZ_B
1615 //to avoid any prefixes or bits being set
1616 x86_rdisp_size(code, OP_SINGLE_EA, OP_EX_PUSH_EA, base, disp, SZ_B);
1617 }
1618
1519 void pop_r(code_info *code, uint8_t reg) 1619 void pop_r(code_info *code, uint8_t reg)
1520 { 1620 {
1521 check_alloc_code(code, 2); 1621 check_alloc_code(code, 2);
1522 code_ptr out = code->cur; 1622 code_ptr out = code->cur;
1523 if (reg >= R8) { 1623 if (reg >= R8) {
1524 *(out++) = PRE_REX | REX_RM_FIELD; 1624 *(out++) = PRE_REX | REX_RM_FIELD;
1525 reg -= R8 - X86_R8; 1625 reg -= R8 - X86_R8;
1526 } 1626 }
1527 *(out++) = OP_POP | reg; 1627 *(out++) = OP_POP | reg;
1628 code->cur = out;
1629 }
1630
1631 void pop_rind(code_info *code, uint8_t reg)
1632 {
1633 check_alloc_code(code, 3);
1634 code_ptr out = code->cur;
1635 if (reg >= R8) {
1636 *(out++) = PRE_REX | REX_RM_FIELD;
1637 reg -= R8 - X86_R8;
1638 }
1639 *(out++) = PRE_XOP;
1640 *(out++) = MODE_REG_INDIRECT | reg;
1528 code->cur = out; 1641 code->cur = out;
1529 } 1642 }
1530 1643
1531 void setcc_r(code_info *code, uint8_t cc, uint8_t dst) 1644 void setcc_r(code_info *code, uint8_t cc, uint8_t dst)
1532 { 1645 {
1569 dst -= R8 - X86_R8; 1682 dst -= R8 - X86_R8;
1570 } 1683 }
1571 *(out++) = PRE_2BYTE; 1684 *(out++) = PRE_2BYTE;
1572 *(out++) = OP2_SETCC | cc; 1685 *(out++) = OP2_SETCC | cc;
1573 if (disp < 128 && disp >= -128) { 1686 if (disp < 128 && disp >= -128) {
1574 *(out++) = MODE_REG_DISPLACE8 | dst; 1687 *(out++) = MODE_REG_DISPLACE8 | dst;
1575 *(out++) = disp; 1688 *(out++) = disp;
1576 } else { 1689 } else {
1577 *(out++) = MODE_REG_DISPLACE32 | dst; 1690 *(out++) = MODE_REG_DISPLACE32 | dst;
1578 *(out++) = disp; 1691 *(out++) = disp;
1579 *(out++) = disp >> 8; 1692 *(out++) = disp >> 8;
1580 *(out++) = disp >> 16; 1693 *(out++) = disp >> 16;
1634 out++; 1747 out++;
1635 } 1748 }
1636 *(out++) = PRE_2BYTE; 1749 *(out++) = PRE_2BYTE;
1637 *(out++) = op2; 1750 *(out++) = op2;
1638 if (dst_disp < 128 && dst_disp >= -128) { 1751 if (dst_disp < 128 && dst_disp >= -128) {
1639 *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3); 1752 *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3);
1640 *(out++) = dst_disp; 1753 *(out++) = dst_disp;
1641 } else { 1754 } else {
1642 *(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3); 1755 *(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3);
1643 *(out++) = dst_disp; 1756 *(out++) = dst_disp;
1644 *(out++) = dst_disp >> 8; 1757 *(out++) = dst_disp >> 8;
1645 *(out++) = dst_disp >> 16; 1758 *(out++) = dst_disp >> 16;
1646 *(out++) = dst_disp >> 24; 1759 *(out++) = dst_disp >> 24;
1647 } 1760 }
1648 code->cur = out; 1761 code->cur = out;
1649 } 1762 }
1650 1763
1651 void bit_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size) 1764 void bit_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
1692 out++; 1805 out++;
1693 } 1806 }
1694 *(out++) = PRE_2BYTE; 1807 *(out++) = PRE_2BYTE;
1695 *(out++) = OP2_BTX_I; 1808 *(out++) = OP2_BTX_I;
1696 if (dst_disp < 128 && dst_disp >= -128) { 1809 if (dst_disp < 128 && dst_disp >= -128) {
1697 *(out++) = MODE_REG_DISPLACE8 | dst_base | (op_ex << 3); 1810 *(out++) = MODE_REG_DISPLACE8 | dst_base | (op_ex << 3);
1698 *(out++) = dst_disp; 1811 *(out++) = dst_disp;
1699 } else { 1812 } else {
1700 *(out++) = MODE_REG_DISPLACE32 | dst_base | (op_ex << 3); 1813 *(out++) = MODE_REG_DISPLACE32 | dst_base | (op_ex << 3);
1701 *(out++) = dst_disp; 1814 *(out++) = dst_disp;
1702 *(out++) = dst_disp >> 8; 1815 *(out++) = dst_disp >> 8;
1703 *(out++) = dst_disp >> 16; 1816 *(out++) = dst_disp >> 16;
1853 *(out++) = OP_SINGLE_EA; 1966 *(out++) = OP_SINGLE_EA;
1854 *(out++) = MODE_REG_DIRECT | dst | (OP_EX_JMP_EA << 3); 1967 *(out++) = MODE_REG_DIRECT | dst | (OP_EX_JMP_EA << 3);
1855 code->cur = out; 1968 code->cur = out;
1856 } 1969 }
1857 1970
1971 void jmp_rind(code_info *code, uint8_t dst)
1972 {
1973 check_alloc_code(code, 3);
1974 code_ptr out = code->cur;
1975 if (dst >= R8) {
1976 dst -= R8 - X86_R8;
1977 *(out++) = PRE_REX | REX_RM_FIELD;
1978 }
1979 *(out++) = OP_SINGLE_EA;
1980 *(out++) = MODE_REG_INDIRECT | dst | (OP_EX_JMP_EA << 3);
1981 code->cur = out;
1982 }
1983
1858 void call(code_info *code, code_ptr fun) 1984 void call(code_info *code, code_ptr fun)
1859 { 1985 {
1860 check_alloc_code(code, 5); 1986 check_alloc_code(code, 5);
1861 code_ptr out = code->cur; 1987 code_ptr out = code->cur;
1862 ptrdiff_t disp = fun-(out+5); 1988 ptrdiff_t disp = fun-(out+5);
1910 *(out++) = OP_LOOP; 2036 *(out++) = OP_LOOP;
1911 *(out++) = disp; 2037 *(out++) = disp;
1912 code->cur = out; 2038 code->cur = out;
1913 } 2039 }
1914 2040
2041 uint32_t prep_args(code_info *code, uint32_t num_args, va_list args)
2042 {
2043 uint8_t *arg_arr = malloc(num_args);
2044 for (int i = 0; i < num_args; i ++)
2045 {
2046 arg_arr[i] = va_arg(args, int);
2047 }
2048 #ifdef X86_64
2049 uint32_t stack_args = 0;
2050 uint8_t abi_regs[] = {RDI, RSI, RDX, RCX, R8, R9};
2051 int8_t reg_swap[R15+1];
2052 uint32_t usage = 0;
2053 memset(reg_swap, -1, sizeof(reg_swap));
2054 for (int i = 0; i < num_args; i ++)
2055 {
2056 usage |= 1 << arg_arr[i];
2057 }
2058 for (int i = 0; i < num_args; i ++)
2059 {
2060 uint8_t reg_arg = arg_arr[i];
2061 if (i < sizeof(abi_regs)) {
2062 if (reg_swap[reg_arg] >= 0) {
2063 reg_arg = reg_swap[reg_arg];
2064 }
2065 if (reg_arg != abi_regs[i]) {
2066 if (usage & (1 << abi_regs[i])) {
2067 xchg_rr(code, reg_arg, abi_regs[i], SZ_PTR);
2068 reg_swap[abi_regs[i]] = reg_arg;
2069 } else {
2070 mov_rr(code, reg_arg, abi_regs[i], SZ_PTR);
2071 }
2072 }
2073 } else {
2074 arg_arr[stack_args++] = reg_arg;
2075 }
2076 }
2077 #else
2078 #define stack_args num_args
2079 #endif
2080 for (int i = stack_args -1; i >= 0; i--)
2081 {
2082 push_r(code, arg_arr[i]);
2083 }
2084
2085 return stack_args * sizeof(void *);
2086 }
2087
2088 void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...)
2089 {
2090 va_list args;
2091 va_start(args, num_args);
2092 uint32_t adjust = prep_args(code, num_args, args);
2093 va_end(args);
2094 call(code, fun);
2095 if (adjust) {
2096 add_ir(code, adjust, RSP, SZ_PTR);
2097 }
2098 }
2099
2100 void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...)
2101 {
2102 va_list args;
2103 va_start(args, num_args);
2104 uint32_t adjust = prep_args(code, num_args, args);
2105 va_end(args);
2106 #ifdef X86_64
2107 test_ir(code, 8, RSP, SZ_PTR); //check stack alignment
2108 code_ptr do_adjust_rsp = code->cur + 1;
2109 jcc(code, CC_NZ, code->cur + 2);
2110 #endif
2111 call(code, fun);
2112 if (adjust) {
2113 add_ir(code, adjust, RSP, SZ_PTR);
2114 }
2115 #ifdef X86_64
2116 code_ptr no_adjust_rsp = code->cur + 1;
2117 jmp(code, code->cur + 2);
2118 *do_adjust_rsp = code->cur - (do_adjust_rsp+1);
2119 sub_ir(code, 8, RSP, SZ_PTR);
2120 call(code, fun);
2121 add_ir(code, adjust + 8 , RSP, SZ_PTR);
2122 *no_adjust_rsp = code->cur - (no_adjust_rsp+1);
2123 #endif
2124 }
2125
2126 void save_callee_save_regs(code_info *code)
2127 {
2128 push_r(code, RBX);
2129 push_r(code, RBP);
2130 #ifdef X86_64
2131 push_r(code, R12);
2132 push_r(code, R13);
2133 push_r(code, R14);
2134 push_r(code, R15);
2135 #else
2136 push_r(code, RDI);
2137 push_r(code, RSI);
2138 #endif
2139 }
2140
2141 void restore_callee_save_regs(code_info *code)
2142 {
2143 #ifdef X86_64
2144 pop_r(code, R15);
2145 pop_r(code, R14);
2146 pop_r(code, R13);
2147 pop_r(code, R12);
2148 #else
2149 pop_r(code, RSI);
2150 pop_r(code, RDI);
2151 #endif
2152 pop_r(code, RBP);
2153 pop_r(code, RBX);
2154 }
2155
2156 uint8_t has_modrm(uint8_t prefix, uint8_t opcode)
2157 {
2158 if (!prefix) {
2159 switch (opcode)
2160 {
2161 case OP_JMP:
2162 case OP_JMP_BYTE:
2163 case OP_JCC:
2164 case OP_CALL:
2165 case OP_RETN:
2166 case OP_LOOP:
2167 case OP_MOV_I8R:
2168 case OP_MOV_IR:
2169 case OP_PUSHF:
2170 case OP_POPF:
2171 case OP_PUSH:
2172 case OP_POP:
2173 case OP_CDQ:
2174 return 0;
2175 }
2176 } else if (prefix == PRE_2BYTE) {
2177 switch (opcode)
2178 {
2179 case OP2_JCC:
2180 return 0;
2181 }
2182 }
2183 return 1;
2184 }
2185
2186 uint8_t has_sib(uint8_t mod_rm)
2187 {
2188 uint8_t mode = mod_rm & 0xC0;
2189 uint8_t rm = mod_rm & 3;
2190
2191 return mode != MODE_REG_DIRECT && rm == RSP;
2192 }
2193
2194 uint32_t x86_inst_size(code_ptr start)
2195 {
2196 code_ptr code = start;
2197 uint8_t cont = 1;
2198 uint8_t prefix = 0;
2199 uint8_t op_size = SZ_B;
2200 uint8_t main_op;
2201
2202 while (cont)
2203 {
2204 if (*code == PRE_SIZE) {
2205 op_size = SZ_W;
2206 } else if (*code == PRE_REX) {
2207 if (*code & REX_QUAD) {
2208 op_size = SZ_Q;
2209 }
2210 } else if(*code == PRE_2BYTE || PRE_XOP) {
2211 prefix = *code;
2212 } else {
2213 main_op = *code;
2214 cont = 0;
2215 }
2216 code++;
2217 }
2218 if (has_modrm(prefix, main_op)) {
2219 uint8_t mod_rm = *(code++);
2220 if (has_sib(mod_rm)) {
2221 //sib takes up a byte, but can't add any additional ones beyond that
2222 code++;
2223 }
2224 uint8_t mode = mod_rm & 0xC0;
2225 uint8_t rm = mod_rm & 3;
2226 if (mode == MODE_REG_DISPLACE8) {
2227 code++;
2228 } else if (mode == MODE_REG_DISPLACE32 || (mode == MODE_REG_INDIRECT && rm == RBP)) {
2229 code += 4;
2230 }
2231 } else {
2232 }
2233
2234 return code-start;
2235 }