| @@ -116,8 +116,6 @@ static const uint8_t reg_to_size[5] = { · 115 unmodified lines |
| 116 | 116 | */ |
| 117 | 117 | 0, 0, 1, 0, 2 |
| 118 | 118 | }; |
| 119 | | − |
| 120 | | −#define WORD_PREFIX_OPCODE 0x66 |
| 121 | 119 | |
| 122 | 120 | #define NB_TEST_OPCODES 30 |
| 123 | 121 | |
| @@ -190,6 +188,10 @@ static inline int get_reg_shift(TCCState *s1) · 66 unmodified lines |
| 190 | 188 | { |
| 191 | 189 | int shift, v; |
| 192 | 190 | |
| 191 | + if (s1->seg_size == 16) { |
| 192 | + error("invalid effective address"); |
| 193 | + } |
| 194 | + |
| 193 | 195 | v = asm_int_expr(s1); |
| 194 | 196 | switch(v) { |
| 195 | 197 | case 1: |
| @@ -222,9 +224,13 @@ static int asm_parse_reg(void) · 26 unmodified lines |
| 222 | 224 | reg = tok - TOK_ASM_eax; |
| 223 | 225 | next(); |
| 224 | 226 | return reg; |
| 227 | + } else if (tok >= TOK_ASM_ax && tok <= TOK_ASM_di) { |
| 228 | + reg = tok - TOK_ASM_ax; |
| 229 | + next(); |
| 230 | + return reg; |
| 225 | 231 | } else { |
| 226 | 232 | error_32: |
| 227 | | − expect("32 bit register"); |
| 233 | + expect("register"); |
| 228 | 234 | return 0; |
| 229 | 235 | } |
| 230 | 236 | } |
| @@ -336,6 +342,12 @@ static void parse_operand(TCCState *s1, Operand *op) · 105 unmodified lines |
| 336 | 342 | op->type |= indir; |
| 337 | 343 | } |
| 338 | 344 | |
| 345 | +static void gen_le16(int v) |
| 346 | +{ |
| 347 | + g(v); |
| 348 | + g(v >> 8); |
| 349 | +} |
| 350 | + |
| 339 | 351 | /* XXX: unify with C code output ? */ |
| 340 | 352 | static void gen_expr32(ExprValue *pe) |
| 341 | 353 | { |
| @@ -344,6 +356,13 @@ static void gen_expr32(ExprValue *pe) · 2 unmodified lines |
| 344 | 356 | gen_le32(pe->v); |
| 345 | 357 | } |
| 346 | 358 | |
| 359 | +static void gen_expr16(ExprValue *pe) |
| 360 | +{ |
| 361 | + if (pe->sym) |
| 362 | + greloc(cur_text_section, pe->sym, ind, R_386_16); |
| 363 | + gen_le16(pe->v); |
| 364 | +} |
| 365 | + |
| 347 | 366 | /* XXX: unify with C code output ? */ |
| 348 | 367 | static void gen_disp32(ExprValue *pe) |
| 349 | 368 | { |
| @@ -368,11 +387,27 @@ static void gen_disp32(ExprValue *pe) · 18 unmodified lines |
| 368 | 387 | } |
| 369 | 388 | } |
| 370 | 389 | |
| 371 | | − |
| 372 | | −static void gen_le16(int v) |
| 390 | +static void gen_disp16(ExprValue *pe) |
| 373 | 391 | { |
| 374 | | − g(v); |
| 375 | | − g(v >> 8); |
| 392 | + Sym *sym; |
| 393 | + sym = pe->sym; |
| 394 | + if (sym) { |
| 395 | + if (sym->r == cur_text_section->sh_num) { |
| 396 | + /* same section: we can output an absolute value. Note |
| 397 | + that the TCC compiler behaves differently here because |
| 398 | + it always outputs a relocation to ease (future) code |
| 399 | + elimination in the linker */ |
| 400 | + gen_le16(pe->v + (long)sym->next - ind - 2); |
| 401 | + } else { |
| 402 | + greloc(cur_text_section, sym, ind, R_386_PC16); |
| 403 | + gen_le16(pe->v - 2); |
| 404 | + } |
| 405 | + } else { |
| 406 | + /* put an empty PC32 relocation */ |
| 407 | + put_elf_reloc(symtab_section, cur_text_section, |
| 408 | + ind, R_386_PC16, 0); |
| 409 | + gen_le16(pe->v - 2); |
| 410 | + } |
| 376 | 411 | } |
| 377 | 412 | |
| 378 | 413 | /* generate the modrm operand */ |
| @@ -384,8 +419,13 @@ static inline void asm_modrm(int reg, Operand *op) · 5 unmodified lines |
| 384 | 419 | g(0xc0 + (reg << 3) + op->reg); |
| 385 | 420 | } else if (op->reg == -1 && op->reg2 == -1) { |
| 386 | 421 | /* displacement only */ |
| 387 | | − g(0x05 + (reg << 3)); |
| 388 | | − gen_expr32(&op->e); |
| 422 | + if (tcc_state->seg_size == 16) { |
| 423 | + g(0x06 + (reg << 3)); |
| 424 | + gen_expr16(&op->e); |
| 425 | + } else if (tcc_state->seg_size == 32) { |
| 426 | + g(0x05 + (reg << 3)); |
| 427 | + gen_expr32(&op->e); |
| 428 | + } |
| 389 | 429 | } else { |
| 390 | 430 | sib_reg1 = op->reg; |
| 391 | 431 | /* fist compute displacement encoding */ |
| @@ -403,20 +443,59 @@ static inline void asm_modrm(int reg, Operand *op) · 11 unmodified lines |
| 403 | 443 | reg1 = op->reg; |
| 404 | 444 | if (op->reg2 != -1) |
| 405 | 445 | reg1 = 4; |
| 406 | | − g(mod + (reg << 3) + reg1); |
| 407 | | − if (reg1 == 4) { |
| 408 | | − /* add sib byte */ |
| 409 | | − reg2 = op->reg2; |
| 410 | | − if (reg2 == -1) |
| 411 | | − reg2 = 4; /* indicate no index */ |
| 412 | | − g((op->shift << 6) + (reg2 << 3) + sib_reg1); |
| 446 | + if (tcc_state->seg_size == 32) { |
| 447 | + g(mod + (reg << 3) + reg1); |
| 448 | + if (reg1 == 4) { |
| 449 | + /* add sib byte */ |
| 450 | + reg2 = op->reg2; |
| 451 | + if (reg2 == -1) |
| 452 | + reg2 = 4; /* indicate no index */ |
| 453 | + g((op->shift << 6) + (reg2 << 3) + sib_reg1); |
| 454 | + } |
| 455 | + } else if (tcc_state->seg_size == 16) { |
| 456 | + /* edi = 7, esi = 6 --> di = 5, si = 4 */ |
| 457 | + if ((reg1 == 6) || (reg1 == 7)) { |
| 458 | + reg1 -= 2; |
| 459 | + /* ebx = 3 --> bx = 7 */ |
| 460 | + } else if (reg1 == 3) { |
| 461 | + reg1 = 7; |
| 462 | + /* o32 = 5 --> o16 = 6 */ |
| 463 | + } else if (reg1 == 5) { |
| 464 | + reg1 = 6; |
| 465 | + /* sib not valid in 16-bit mode */ |
| 466 | + } else if (reg1 == 4) { |
| 467 | + reg2 = op->reg2; |
| 468 | + /* bp + si + offset */ |
| 469 | + if ((sib_reg1 == 5) && (reg2 == 6)) { |
| 470 | + reg1 = 2; |
| 471 | + /* bp + di + offset */ |
| 472 | + } else if ((sib_reg1 == 5) && (reg2 == 7)) { |
| 473 | + reg1 = 3; |
| 474 | + /* bx + si + offset */ |
| 475 | + } else if ((sib_reg1 == 3) && (reg2 == 6)) { |
| 476 | + reg1 = 0; |
| 477 | + /* bx + di + offset */ |
| 478 | + } else if ((sib_reg1 == 3) && (reg2 == 7)) { |
| 479 | + reg1 = 1; |
| 480 | + } else { |
| 481 | + error("invalid effective address"); |
| 482 | + } |
| 483 | + if (op->e.v == 0) |
| 484 | + mod = 0; |
| 485 | + } else { |
| 486 | + error("invalid register"); |
| 487 | + } |
| 488 | + g(mod + (reg << 3) + reg1); |
| 413 | 489 | } |
| 414 | 490 | |
| 415 | 491 | /* add offset */ |
| 416 | 492 | if (mod == 0x40) { |
| 417 | 493 | g(op->e.v); |
| 418 | 494 | } else if (mod == 0x80 || op->reg == -1) { |
| 419 | | − gen_expr32(&op->e); |
| 495 | + if (tcc_state->seg_size == 16) |
| 496 | + gen_expr16(&op->e); |
| 497 | + else if (tcc_state->seg_size == 32) |
| 498 | + gen_expr32(&op->e); |
| 420 | 499 | } |
| 421 | 500 | } |
| 422 | 501 | } |
| @@ -428,6 +507,7 @@ static void asm_opcode(TCCState *s1, int opcode) · 5 unmodified lines |
| 428 | 507 | int nb_ops, s, ss; |
| 429 | 508 | Operand ops[MAX_OPERANDS], *pop; |
| 430 | 509 | int op_type[3]; /* decoded op type */ |
| 510 | + static int a32 = 0, o32 = 0, addr32 = 0, data32 = 0; |
| 431 | 511 | |
| 432 | 512 | /* get operands */ |
| 433 | 513 | pop = ops; |
| @@ -442,14 +522,17 @@ static void asm_opcode(TCCState *s1, int opcode) · 8 unmodified lines |
| 442 | 522 | parse_operand(s1, pop); |
| 443 | 523 | if (tok == ':') { |
| 444 | 524 | if (pop->type != OP_SEG || seg_prefix) { |
| 525 | + bad_prefix: |
| 445 | 526 | error("incorrect prefix"); |
| 446 | 527 | } |
| 447 | 528 | seg_prefix = segment_prefixes[pop->reg]; |
| 448 | 529 | next(); |
| 449 | 530 | parse_operand(s1, pop); |
| 531 | +#if 0 |
| 450 | 532 | if (!(pop->type & OP_EA)) { |
| 451 | 533 | error("segment prefix must be followed by memory reference"); |
| 452 | 534 | } |
| 535 | +#endif |
| 453 | 536 | } |
| 454 | 537 | pop++; |
| 455 | 538 | nb_ops++; |
| @@ -531,6 +614,17 @@ static void asm_opcode(TCCState *s1, int opcode) · 75 unmodified lines |
| 531 | 614 | if (opcode >= TOK_ASM_pusha && opcode <= TOK_ASM_emms) { |
| 532 | 615 | int b; |
| 533 | 616 | b = op0_codes[opcode - TOK_ASM_pusha]; |
| 617 | + if (opcode == TOK_ASM_o32) { |
| 618 | + if (s1->seg_size == 32) |
| 619 | + goto bad_prefix; |
| 620 | + else |
| 621 | + o32 = data32 = 1; |
| 622 | + } else if (opcode == TOK_ASM_a32) { |
| 623 | + if (s1->seg_size == 32) |
| 624 | + goto bad_prefix; |
| 625 | + else |
| 626 | + a32 = addr32 = 1; |
| 627 | + } |
| 534 | 628 | if (b & 0xff00) |
| 535 | 629 | g(b >> 8); |
| 536 | 630 | g(b); |
| @@ -555,12 +649,37 @@ static void asm_opcode(TCCState *s1, int opcode) · 18 unmodified lines |
| 555 | 649 | } |
| 556 | 650 | } |
| 557 | 651 | |
| 558 | | − /* generate data16 prefix if needed */ |
| 652 | + for(i = 0; i < nb_ops; i++) { |
| 653 | + if (ops[i].type & OP_REG32) { |
| 654 | + if (s1->seg_size == 16) |
| 655 | + o32 = 1; |
| 656 | + } else if (!ops[i].type & OP_REG32) { |
| 657 | + if (s1->seg_size == 32) |
| 658 | + o32 = 1; |
| 659 | + } |
| 660 | + } |
| 661 | + |
| 559 | 662 | ss = s; |
| 560 | | − if (s == 1 || (pa->instr_type & OPC_D16)) |
| 561 | | − g(WORD_PREFIX_OPCODE); |
| 562 | | − else if (s == 2) |
| 663 | + if (s == 1 || (pa->instr_type & OPC_D16)) { |
| 664 | + if (s1->seg_size == 32) |
| 665 | + o32 = 1; |
| 666 | + } else if (s == 2) { |
| 667 | + if (s1->seg_size == 16) { |
| 668 | + if (!(pa->instr_type & OPC_D16)) |
| 669 | + o32 = 1; |
| 670 | + } |
| 563 | 671 | s = 1; |
| 672 | + } |
| 673 | + |
| 674 | + /* generate a16/a32 prefix if needed */ |
| 675 | + if ((a32 == 1) && (addr32 == 0)) |
| 676 | + g(0x67); |
| 677 | + /* generate o16/o32 prefix if needed */ |
| 678 | + if ((o32 == 1) && (data32 == 0)) |
| 679 | + g(0x66); |
| 680 | + |
| 681 | + addr32 = data32 = 0; |
| 682 | + |
| 564 | 683 | /* now generates the operation */ |
| 565 | 684 | if (pa->instr_type & OPC_FWAIT) |
| 566 | 685 | g(0x9b); |
| @@ -685,9 +804,17 @@ static void asm_opcode(TCCState *s1, int opcode) · 118 unmodified lines |
| 685 | 804 | /* emit constants */ |
| 686 | 805 | if (pa->opcode == 0x9a || pa->opcode == 0xea) { |
| 687 | 806 | /* ljmp or lcall kludge */ |
| 688 | | − gen_expr32(&ops[1].e); |
| 689 | | − if (ops[0].e.sym) |
| 807 | + if (s1->seg_size == 16) { |
| 808 | + if (o32 == 0) |
| 809 | + gen_expr16(&ops[1].e); |
| 810 | + else if (o32 == 1) |
| 811 | + gen_expr32(&ops[1].e); |
| 812 | + } else |
| 813 | + gen_expr32(&ops[1].e); |
| 814 | + if (ops[0].e.sym) { |
| 815 | + error_relocate: |
| 690 | 816 | error("cannot relocate"); |
| 817 | + } |
| 691 | 818 | gen_le16(ops[0].e.v); |
| 692 | 819 | } else { |
| 693 | 820 | for(i = 0;i < nb_ops; i++) { |
| @@ -709,24 +836,48 @@ static void asm_opcode(TCCState *s1, int opcode) · 15 unmodified lines |
| 709 | 836 | goto error_relocate; |
| 710 | 837 | g(ops[i].e.v); |
| 711 | 838 | } else if (v & OP_IM16) { |
| 712 | | − if (ops[i].e.sym) { |
| 713 | | − error_relocate: |
| 714 | | − error("cannot relocate"); |
| 839 | + if (s1->seg_size == 16) |
| 840 | + gen_expr16(&ops[i].e); |
| 841 | + else { |
| 842 | + if (ops[i].e.sym) |
| 843 | + goto error_relocate; |
| 715 | 844 | } |
| 716 | 845 | gen_le16(ops[i].e.v); |
| 846 | + } |
| 717 | 847 | } else { |
| 718 | 848 | if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { |
| 719 | 849 | if (is_short_jmp) |
| 720 | 850 | g(ops[i].e.v); |
| 721 | | − else |
| 722 | | − gen_disp32(&ops[i].e); |
| 851 | + else { |
| 852 | + if (s1->seg_size == 16) |
| 853 | + gen_disp16(&ops[i].e); |
| 854 | + else |
| 855 | + gen_disp32(&ops[i].e); |
| 856 | + } |
| 723 | 857 | } else { |
| 724 | | − gen_expr32(&ops[i].e); |
| 858 | + if (s1->seg_size == 16) { |
| 859 | + if ((o32 == 1) && (v & OP_IM32)) |
| 860 | + gen_expr32(&ops[i].e); |
| 861 | + else |
| 862 | + gen_expr16(&ops[i].e); |
| 863 | + } else if (s1->seg_size == 32) { |
| 864 | + if (o32 == 1) |
| 865 | + gen_expr16(&ops[i].e); |
| 866 | + else |
| 867 | + gen_expr32(&ops[i].e); |
| 868 | + } |
| 725 | 869 | } |
| 726 | 870 | } |
| 871 | + } else if (v & (OP_REG16 | OP_REG32)) { |
| 872 | + if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { |
| 873 | + /* jmp $r */ |
| 874 | + g(0xE0 + ops[i].reg); |
| 875 | + } |
| 727 | 876 | } |
| 728 | 877 | } |
| 729 | 878 | } |
| 879 | + |
| 880 | + a32 = o32 = 0; |
| 730 | 881 | } |
| 731 | 882 | |
| 732 | 883 | #define NB_SAVED_REGS 3 |
| @@ -1127,8 +1278,11 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands, · 394 unmodified lines |
| 1127 | 1278 | /* generate reg save code */ |
| 1128 | 1279 | for(i = 0; i < NB_SAVED_REGS; i++) { |
| 1129 | 1280 | reg = reg_saved[i]; |
| 1130 | | − if (regs_allocated[reg]) |
| 1281 | + if (regs_allocated[reg]) { |
| 1282 | + if (tcc_state->seg_size == 16) |
| 1283 | + g(0x66); |
| 1131 | 1284 | g(0x50 + reg); |
| 1285 | + } |
| 1132 | 1286 | } |
| 1133 | 1287 | |
| 1134 | 1288 | /* generate load code */ |
| @@ -1184,8 +1338,11 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands, · 49 unmodified lines |
| 1184 | 1338 | /* generate reg restore code */ |
| 1185 | 1339 | for(i = NB_SAVED_REGS - 1; i >= 0; i--) { |
| 1186 | 1340 | reg = reg_saved[i]; |
| 1187 | | − if (regs_allocated[reg]) |
| 1341 | + if (regs_allocated[reg]) { |
| 1342 | + if (tcc_state->seg_size == 16) |
| 1343 | + g(0x66); |
| 1188 | 1344 | g(0x58 + reg); |
| 1345 | + } |
| 1189 | 1346 | } |
| 1190 | 1347 | } |
| 1191 | 1348 | } |