| @@ -29,19 +29,26 @@ · 28 unmodified lines |
| 29 | #define TOK_ASM_last TOK_ASM_emms | 29 | #define TOK_ASM_last TOK_ASM_emms |
| 30 | #define TOK_ASM_alllast TOK_ASM_subps | 30 | #define TOK_ASM_alllast TOK_ASM_subps |
| 31 | | 31 | |
| 32 | #define OPC_JMP 0x01 /* jmp operand */ | 32 | #define OPC_B 0x01 /* only used with OPC_WL */ |
| 33 | #define OPC_B 0x02 /* only used with OPC_WL */ | 33 | #define OPC_WL 0x02 /* accepts w, l or no suffix */ |
| 34 | #define OPC_WL 0x04 /* accepts w, l or no suffix */ | | |
| 35 | #define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ | 34 | #define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ |
| 36 | #define OPC_REG 0x08 /* register is added to opcode */ | 35 | #define OPC_REG 0x04 /* register is added to opcode */ |
| 37 | #define OPC_MODRM 0x10 /* modrm encoding */ | 36 | #define OPC_MODRM 0x08 /* modrm encoding */ |
| 38 | #define OPC_FWAIT 0x20 /* add fwait opcode */ | 37 | |
| 39 | #define OPC_TEST 0x40 /* test opcodes */ | 38 | #define OPCT_MASK 0x70 |
| 40 | #define OPC_SHIFT 0x80 /* shift opcodes */ | 39 | #define OPC_FWAIT 0x10 /* add fwait opcode */ |
| 41 | #define OPC_D16 0x0100 /* generate data16 prefix */ | 40 | #define OPC_SHIFT 0x20 /* shift opcodes */ |
| 42 | #define OPC_ARITH 0x0200 /* arithmetic opcodes */ | 41 | #define OPC_ARITH 0x30 /* arithmetic opcodes */ |
| 43 | #define OPC_SHORTJMP 0x0400 /* short jmp operand */ | 42 | #define OPC_FARITH 0x40 /* FPU arithmetic opcodes */ |
| 44 | #define OPC_FARITH 0x0800 /* FPU arithmetic opcodes */ | 43 | #define OPC_TEST 0x50 /* test opcodes */ |
| | 44 | #define OPC_JMP_TEST 0x60 /* A test and jmp opcode */ |
| | 45 | #define OPC_JMP 0x70 /* A non-testing jmp opcode */ |
| | 46 | #define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i)) |
| | 47 | |
| | 48 | #define OPC_SHORTJMP 0x80 /* short jmp operand */ |
| | 49 | |
| | 50 | #define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */ |
| | 51 | #define OPC_D16 0x0800 /* generate data16 prefix */ |
| 45 | #ifdef TCC_TARGET_X86_64 | 52 | #ifdef TCC_TARGET_X86_64 |
| 46 | # define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */ | 53 | # define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */ |
| 47 | # define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */ | 54 | # define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */ |
| @@ -211,11 +218,15 @@ static const uint8_t segment_prefixes[] = { · 163 unmodified lines |
| 211 | | 218 | |
| 212 | static const ASMInstr asm_instrs[] = { | 219 | static const ASMInstr asm_instrs[] = { |
| 213 | #define ALT(x) x | 220 | #define ALT(x) x |
| | 221 | /* This removes a 0x0f in the second byte */ |
| | 222 | #define O(o) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o)) |
| | 223 | /* This constructs instr_type from opcode, type and group. */ |
| | 224 | #define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0)) |
| 214 | #define DEF_ASM_OP0(name, opcode) | 225 | #define DEF_ASM_OP0(name, opcode) |
| 215 | #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 0 }, | 226 | #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0 }, |
| 216 | #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }}, | 227 | #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }}, |
| 217 | #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }}, | 228 | #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }}, |
| 218 | #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 3, { op0, op1, op2 }}, | 229 | #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 3, { op0, op1, op2 }}, |
| 219 | #ifdef TCC_TARGET_X86_64 | 230 | #ifdef TCC_TARGET_X86_64 |
| 220 | # include "x86_64-asm.h" | 231 | # include "x86_64-asm.h" |
| 221 | #else | 232 | #else |
| @@ -594,12 +605,13 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 372 unmodified lines |
| 594 | /* optimize matching by using a lookup table (no hashing is needed | 605 | /* optimize matching by using a lookup table (no hashing is needed |
| 595 | !) */ | 606 | !) */ |
| 596 | for(pa = asm_instrs; pa->sym != 0; pa++) { | 607 | for(pa = asm_instrs; pa->sym != 0; pa++) { |
| | 608 | int it = pa->instr_type & OPCT_MASK; |
| 597 | s = 0; | 609 | s = 0; |
| 598 | if (pa->instr_type & OPC_FARITH) { | 610 | if (it == OPC_FARITH) { |
| 599 | v = opcode - pa->sym; | 611 | v = opcode - pa->sym; |
| 600 | if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) | 612 | if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) |
| 601 | continue; | 613 | continue; |
| 602 | } else if (pa->instr_type & OPC_ARITH) { | 614 | } else if (it == OPC_ARITH) { |
| 603 | if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX)) | 615 | if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX)) |
| 604 | continue; | 616 | continue; |
| 605 | s = (opcode - pa->sym) % NBWLX; | 617 | s = (opcode - pa->sym) % NBWLX; |
| @@ -612,11 +624,11 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 6 unmodified lines |
| 612 | continue; | 624 | continue; |
| 613 | s++; | 625 | s++; |
| 614 | } | 626 | } |
| 615 | } else if (pa->instr_type & OPC_SHIFT) { | 627 | } else if (it == OPC_SHIFT) { |
| 616 | if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX)) | 628 | if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX)) |
| 617 | continue; | 629 | continue; |
| 618 | s = (opcode - pa->sym) % NBWLX; | 630 | s = (opcode - pa->sym) % NBWLX; |
| 619 | } else if (pa->instr_type & OPC_TEST) { | 631 | } else if (it == OPC_TEST || it == OPC_JMP_TEST) { |
| 620 | if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) | 632 | if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) |
| 621 | continue; | 633 | continue; |
| 622 | /* cmovxx is a test opcode but accepts multiple sizes. | 634 | /* cmovxx is a test opcode but accepts multiple sizes. |
| @@ -650,7 +662,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 27 unmodified lines |
| 650 | should only be done if we really have an >32bit imm64, and that | 662 | should only be done if we really have an >32bit imm64, and that |
| 651 | is hardcoded. Ignore it here. */ | 663 | is hardcoded. Ignore it here. */ |
| 652 | if (pa->opcode == 0xb0 && ops[0].type != OP_IM64 | 664 | if (pa->opcode == 0xb0 && ops[0].type != OP_IM64 |
| 653 | && ops[1].type == OP_REG64) | 665 | && ops[1].type == OP_REG64 |
| | 666 | && !(pa->instr_type & OPC_0F)) |
| 654 | continue; | 667 | continue; |
| 655 | #endif | 668 | #endif |
| 656 | /* now decode and check each operand */ | 669 | /* now decode and check each operand */ |
| @@ -777,12 +790,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 120 unmodified lines |
| 777 | #endif | 790 | #endif |
| 778 | | 791 | |
| 779 | /* now generates the operation */ | 792 | /* now generates the operation */ |
| 780 | if (pa->instr_type & OPC_FWAIT) | 793 | if (OPCT_IS(pa->instr_type, OPC_FWAIT)) |
| 781 | g(0x9b); | 794 | g(0x9b); |
| 782 | if (seg_prefix) | 795 | if (seg_prefix) |
| 783 | g(seg_prefix); | 796 | g(seg_prefix); |
| 784 | | 797 | |
| 785 | v = pa->opcode; | 798 | v = pa->opcode; |
| | 799 | if (pa->instr_type & OPC_0F) |
| | 800 | v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff); |
| 786 | if ((v == 0x69 || v == 0x6b) && nb_ops == 2) { | 801 | if ((v == 0x69 || v == 0x6b) && nb_ops == 2) { |
| 787 | /* kludge for imul $im, %reg */ | 802 | /* kludge for imul $im, %reg */ |
| 788 | nb_ops = 3; | 803 | nb_ops = 3; |
| @@ -802,25 +817,23 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 13 unmodified lines |
| 802 | } else if (v <= 0x05) { | 817 | } else if (v <= 0x05) { |
| 803 | /* arith case */ | 818 | /* arith case */ |
| 804 | v += ((opcode - TOK_ASM_addb) / NBWLX) << 3; | 819 | v += ((opcode - TOK_ASM_addb) / NBWLX) << 3; |
| 805 | } else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) { | 820 | } else if ((pa->instr_type & (OPCT_MASK | OPC_MODRM)) == OPC_FARITH) { |
| 806 | /* fpu arith case */ | 821 | /* fpu arith case */ |
| 807 | v += ((opcode - pa->sym) / 6) << 3; | 822 | v += ((opcode - pa->sym) / 6) << 3; |
| 808 | } | 823 | } |
| 809 | if (pa->instr_type & OPC_REG) { | 824 | if (pa->instr_type & OPC_REG) { |
| | 825 | /* mov $im, %reg case */ |
| | 826 | if (v == 0xb0 && s >= 1) |
| | 827 | v += 7; |
| 810 | for(i = 0; i < nb_ops; i++) { | 828 | for(i = 0; i < nb_ops; i++) { |
| 811 | if (op_type[i] & (OP_REG | OP_ST)) { | 829 | if (op_type[i] & (OP_REG | OP_ST)) { |
| 812 | v += ops[i].reg; | 830 | v += ops[i].reg; |
| 813 | break; | 831 | break; |
| 814 | } | 832 | } |
| 815 | } | 833 | } |
| 816 | /* mov $im, %reg case */ | | |
| 817 | if (pa->opcode == 0xb0 && s >= 1) | | |
| 818 | v += 7; | | |
| 819 | } | 834 | } |
| 820 | if (pa->instr_type & OPC_B) | 835 | if (pa->instr_type & OPC_B) |
| 821 | v += s >= 1; | 836 | v += s >= 1; |
| 822 | if (pa->instr_type & OPC_TEST) | | |
| 823 | v += test_bits[opcode - pa->sym]; | | |
| 824 | if (pa->instr_type & OPC_SHORTJMP) { | 837 | if (pa->instr_type & OPC_SHORTJMP) { |
| 825 | Sym *sym; | 838 | Sym *sym; |
| 826 | int jmp_disp; | 839 | int jmp_disp; |
| @@ -839,32 +852,36 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 12 unmodified lines |
| 839 | op_type[0] = OP_IM8S; | 852 | op_type[0] = OP_IM8S; |
| 840 | } else { | 853 | } else { |
| 841 | no_short_jump: | 854 | no_short_jump: |
| 842 | if (pa->instr_type & OPC_JMP) { | 855 | /* long jump will be allowed. need to modify the |
| 843 | /* long jump will be allowed. need to modify the | 856 | opcode slightly */ |
| 844 | opcode slightly */ | 857 | if (v == 0xeb) /* jmp */ |
| 845 | if (v == 0xeb) | 858 | v = 0xe9; |
| 846 | v = 0xe9; | 859 | else if (v == 0x70) /* jcc */ |
| 847 | else | 860 | v += 0x0f10; |
| 848 | v += 0x0f10; | 861 | else |
| 849 | } else { | 862 | tcc_error("invalid displacement"); |
| 850 | tcc_error("invalid displacement"); | | |
| 851 | } | | |
| 852 | } | 863 | } |
| 853 | } | 864 | } |
| 854 | op1 = v >> 8; | 865 | if (OPCT_IS(pa->instr_type, OPC_TEST) |
| | 866 | || OPCT_IS(pa->instr_type, OPC_JMP_TEST)) |
| | 867 | v += test_bits[opcode - pa->sym]; |
| | 868 | op1 = v >> 16; |
| | 869 | if (op1) |
| | 870 | g(op1); |
| | 871 | op1 = (v >> 8) & 0xff; |
| 855 | if (op1) | 872 | if (op1) |
| 856 | g(op1); | 873 | g(op1); |
| 857 | g(v); | 874 | g(v); |
| 858 | | 875 | |
| 859 | /* search which operand will used for modrm */ | 876 | /* search which operand will used for modrm */ |
| 860 | modrm_index = 0; | 877 | modrm_index = 0; |
| 861 | if (pa->instr_type & OPC_SHIFT) { | 878 | if (OPCT_IS(pa->instr_type, OPC_SHIFT)) { |
| 862 | reg = (opcode - pa->sym) / NBWLX; | 879 | reg = (opcode - pa->sym) / NBWLX; |
| 863 | if (reg == 6) | 880 | if (reg == 6) |
| 864 | reg = 7; | 881 | reg = 7; |
| 865 | } else if (pa->instr_type & OPC_ARITH) { | 882 | } else if (OPCT_IS(pa->instr_type, OPC_ARITH)) { |
| 866 | reg = (opcode - pa->sym) / NBWLX; | 883 | reg = (opcode - pa->sym) / NBWLX; |
| 867 | } else if (pa->instr_type & OPC_FARITH) { | 884 | } else if (OPCT_IS(pa->instr_type, OPC_FARITH)) { |
| 868 | reg = (opcode - pa->sym) / 6; | 885 | reg = (opcode - pa->sym) / 6; |
| 869 | } else { | 886 | } else { |
| 870 | reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; | 887 | reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; |
| @@ -902,7 +919,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 31 unmodified lines |
| 902 | | 919 | |
| 903 | /* emit constants */ | 920 | /* emit constants */ |
| 904 | #ifndef TCC_TARGET_X86_64 | 921 | #ifndef TCC_TARGET_X86_64 |
| 905 | if (pa->opcode == 0x9a || pa->opcode == 0xea) { | 922 | if (!(pa->instr_type & OPC_0F) |
| | 923 | && (pa->opcode == 0x9a || pa->opcode == 0xea)) { |
| 906 | /* ljmp or lcall kludge */ | 924 | /* ljmp or lcall kludge */ |
| 907 | gen_expr32(&ops[1].e); | 925 | gen_expr32(&ops[1].e); |
| 908 | if (ops[0].e.sym) | 926 | if (ops[0].e.sym) |
| @@ -938,7 +956,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 29 unmodified lines |
| 938 | } else if (v & OP_IM64) { | 956 | } else if (v & OP_IM64) { |
| 939 | gen_expr64(&ops[i].e); | 957 | gen_expr64(&ops[i].e); |
| 940 | #endif | 958 | #endif |
| 941 | } else if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { | 959 | } else if (OPCT_IS (pa->instr_type, OPC_JMP) |
| | 960 | || OPCT_IS (pa->instr_type, OPC_JMP_TEST)) { |
| 942 | gen_disp32(&ops[i].e); | 961 | gen_disp32(&ops[i].e); |
| 943 | } else { | 962 | } else { |
| 944 | gen_expr32(&ops[i].e); | 963 | gen_expr32(&ops[i].e); |