Mercurial > repos > blastem
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 } |