Ignore:
Timestamp:
Jan 21, 2018, 12:10:09 AM (6 years ago)
Author:
coas-nagasima
Message:

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

Location:
EcnlProtoTool/trunk/tcc-0.9.27
Files:
1 edited
1 moved

Legend:

Unmodified
Added
Removed
  • EcnlProtoTool/trunk/tcc-0.9.27/i386-asm.c

    r321 r331  
    2222#include "tcc.h"
    2323
    24 // #define NB_ASM_REGS 8
    2524#define MAX_OPERANDS 3
    26 #define NB_SAVED_REGS 3
    2725
    2826#define TOK_ASM_first TOK_ASM_clc
    2927#define TOK_ASM_last TOK_ASM_emms
    30 
    31 #define OPC_JMP        0x01  /* jmp operand */
    32 #define OPC_B          0x02  /* only used with OPC_WL */
    33 #define OPC_WL         0x04  /* accepts w, l or no suffix */
     28#define TOK_ASM_alllast TOK_ASM_subps
     29
     30#define OPC_B          0x01  /* only used with OPC_WL */
     31#define OPC_WL         0x02  /* accepts w, l or no suffix */
    3432#define OPC_BWL        (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */
    35 #define OPC_REG        0x08 /* register is added to opcode */
    36 #define OPC_MODRM      0x10 /* modrm encoding */
    37 #define OPC_FWAIT      0x20 /* add fwait opcode */
    38 #define OPC_TEST       0x40 /* test opcodes */
    39 #define OPC_SHIFT      0x80 /* shift opcodes */
    40 #define OPC_D16      0x0100 /* generate data16 prefix */
    41 #define OPC_ARITH    0x0200 /* arithmetic opcodes */
    42 #define OPC_SHORTJMP 0x0400 /* short jmp operand */
    43 #define OPC_FARITH   0x0800 /* FPU arithmetic opcodes */
     33#define OPC_REG        0x04 /* register is added to opcode */
     34#define OPC_MODRM      0x08 /* modrm encoding */
     35
     36#define OPCT_MASK      0x70
     37#define OPC_FWAIT      0x10 /* add fwait opcode */
     38#define OPC_SHIFT      0x20 /* shift opcodes */
     39#define OPC_ARITH      0x30 /* arithmetic opcodes */
     40#define OPC_FARITH     0x40 /* FPU arithmetic opcodes */
     41#define OPC_TEST       0x50 /* test opcodes */
     42#define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i))
     43
     44#define OPC_0F        0x100 /* Is secondary map (0x0f prefix) */
     45#define OPC_48        0x200 /* Always has REX prefix */
    4446#ifdef TCC_TARGET_X86_64
    4547# define OPC_WLQ     0x1000  /* accepts w, l, q or no suffix */
    4648# define OPC_BWLQ    (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */
    4749# define OPC_WLX     OPC_WLQ
     50# define OPC_BWLX    OPC_BWLQ
    4851#else
    4952# define OPC_WLX     OPC_WL
     53# define OPC_BWLX    OPC_BWL
    5054#endif
    5155
     
    6872    OPT_SEG,
    6973    OPT_ST,
     74#ifdef TCC_TARGET_X86_64
     75    OPT_REG8_LOW, /* %spl,%bpl,%sil,%dil, encoded like ah,ch,dh,bh, but
     76                     with REX prefix, not used in insn templates */
     77#endif
    7078    OPT_IM8,
    7179    OPT_IM8S,
     
    8391    /* composite types */
    8492    OPT_COMPOSITE_FIRST,
    85     OPT_IM,     /* IM8 | IM16 | IM32 | IM64 */
     93    OPT_IM,     /* IM8 | IM16 | IM32 */
    8694    OPT_REG,    /* REG8 | REG16 | REG32 | REG64 */
    8795    OPT_REGW,   /* REG16 | REG32 | REG64 */
    88     OPT_IMW,    /* IM16 | IM32 | IM64 */
    89 #ifdef TCC_TARGET_X86_64
    90     OPT_IMNO64, /* IM16 | IM32 */
    91 #endif
     96    OPT_IMW,    /* IM16 | IM32 */
     97    OPT_MMXSSE, /* MMX | SSE */
     98    OPT_DISP,   /* Like OPT_ADDR, but emitted as displacement (for jumps) */
     99    OPT_DISP8,  /* Like OPT_ADDR, but only 8bit (short jumps) */
    92100    /* can be ored with any OPT_xxx */
    93101    OPT_EA = 0x80
     
    115123#define OP_INDIR  (1 << OPT_INDIR)
    116124#ifdef TCC_TARGET_X86_64
    117 # define OP_REG64  (1 << OPT_REG64)
    118 # define OP_IM64   (1 << OPT_IM64)
     125# define OP_REG64 (1 << OPT_REG64)
     126# define OP_REG8_LOW (1 << OPT_REG8_LOW)
     127# define OP_IM64  (1 << OPT_IM64)
     128# define OP_EA32  (OP_EA << 1)
    119129#else
    120130# define OP_REG64 0
     131# define OP_REG8_LOW 0
    121132# define OP_IM64  0
     133# define OP_EA32  0
    122134#endif
    123135
     
    126138
    127139#ifdef TCC_TARGET_X86_64
    128 # define OP_IM      OP_IM64
    129140# define TREG_XAX   TREG_RAX
    130141# define TREG_XCX   TREG_RCX
    131142# define TREG_XDX   TREG_RDX
    132143#else
    133 # define OP_IM      OP_IM32
    134144# define TREG_XAX   TREG_EAX
    135145# define TREG_XCX   TREG_ECX
     
    211221static const ASMInstr asm_instrs[] = {
    212222#define ALT(x) x
     223/* This removes a 0x0f in the second byte */
     224#define O(o) ((uint64_t) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o)))
     225/* This constructs instr_type from opcode, type and group.  */
     226#define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0))
    213227#define DEF_ASM_OP0(name, opcode)
    214 #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 0 },
    215 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }},
    216 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }},
    217 #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 }},
     228#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0, { 0 } },
     229#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }},
     230#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }},
     231#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 }},
    218232#ifdef TCC_TARGET_X86_64
    219233# include "x86_64-asm.h"
     
    242256{
    243257    int shift, v;
    244 #ifdef I386_ASM_16
    245     if (s1->seg_size == 16)
    246         tcc_error("invalid effective address");
    247 #endif
    248258    v = asm_int_expr(s1);
    249259    switch(v) {
     
    268278}
    269279
    270 static int asm_parse_reg(void)
     280#ifdef TCC_TARGET_X86_64
     281static int asm_parse_numeric_reg(int t, unsigned int *type)
     282{
     283    int reg = -1;
     284    if (t >= TOK_IDENT && t < tok_ident) {
     285        const char *s = table_ident[t - TOK_IDENT]->str;
     286        char c;
     287        *type = OP_REG64;
     288        if (*s == 'c') {
     289            s++;
     290            *type = OP_CR;
     291        }
     292        if (*s++ != 'r')
     293          return -1;
     294        /* Don't allow leading '0'.  */
     295        if ((c = *s++) >= '1' && c <= '9')
     296          reg = c - '0';
     297        else
     298          return -1;
     299        if ((c = *s) >= '0' && c <= '5')
     300          s++, reg = reg * 10 + c - '0';
     301        if (reg > 15)
     302          return -1;
     303        if ((c = *s) == 0)
     304          ;
     305        else if (*type != OP_REG64)
     306          return -1;
     307        else if (c == 'b' && !s[1])
     308          *type = OP_REG8;
     309        else if (c == 'w' && !s[1])
     310          *type = OP_REG16;
     311        else if (c == 'd' && !s[1])
     312          *type = OP_REG32;
     313        else
     314          return -1;
     315    }
     316    return reg;
     317}
     318#endif
     319
     320static int asm_parse_reg(unsigned int *type)
    271321{
    272322    int reg = 0;
     323    *type = 0;
    273324    if (tok != '%')
    274325        goto error_32;
     
    276327    if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) {
    277328        reg = tok - TOK_ASM_eax;
     329        *type = OP_REG32;
    278330#ifdef TCC_TARGET_X86_64
    279331    } else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) {
    280332        reg = tok - TOK_ASM_rax;
    281 #endif
    282 #ifdef I386_ASM_16
    283     } else if (tok >= TOK_ASM_ax && tok <= TOK_ASM_di) {
    284         reg = tok - TOK_ASM_ax;
     333        *type = OP_REG64;
     334    } else if (tok == TOK_ASM_rip) {
     335        reg = -2; /* Probably should use different escape code. */
     336        *type = OP_REG64;
     337    } else if ((reg = asm_parse_numeric_reg(tok, type)) >= 0
     338               && (*type == OP_REG32 || *type == OP_REG64)) {
     339        ;
    285340#endif
    286341    } else {
     
    330385                if (tok != TOK_PPNUM)
    331386                    goto reg_error;
    332                 p = tokc.cstr->data;
     387                p = tokc.str.data;
    333388                reg = p[0] - '0';
    334389                if ((unsigned)reg >= 8 || p[1] != '\0')
     
    341396                op->type |= OP_ST0;
    342397            goto no_skip;
     398#ifdef TCC_TARGET_X86_64
     399        } else if (tok >= TOK_ASM_spl && tok <= TOK_ASM_dil) {
     400            op->type = OP_REG8 | OP_REG8_LOW;
     401            op->reg = 4 + tok - TOK_ASM_spl;
     402        } else if ((op->reg = asm_parse_numeric_reg(tok, &op->type)) >= 0) {
     403            ;
     404#endif
    343405        } else {
    344406        reg_error:
    345             tcc_error("unknown register");
     407            tcc_error("unknown register %%%s", get_tok_str(tok, &tokc));
    346408        }
    347409        next();
     
    351413        next();
    352414        asm_expr(s1, &e);
    353         op->type = OP_IM;
    354         op->e.v = e.v;
    355         op->e.sym = e.sym;
     415        op->type = OP_IM32;
     416        op->e = e;
    356417        if (!op->e.sym) {
    357418            if (op->e.v == (uint8_t)op->e.v)
     
    362423                op->type |= OP_IM16;
    363424#ifdef TCC_TARGET_X86_64
    364             if (op->e.v == (uint32_t)op->e.v)
    365                 op->type |= OP_IM32;
     425            if (op->e.v != (int32_t)op->e.v && op->e.v != (uint32_t)op->e.v)
     426                op->type = OP_IM64;
    366427#endif
    367428        }
     
    374435        if (tok != '(') {
    375436            asm_expr(s1, &e);
    376             op->e.v = e.v;
    377             op->e.sym = e.sym;
     437            op->e = e;
    378438        } else {
    379439            next();
     
    391451                op->e.sym = e.sym;
    392452            }
     453            op->e.pcrel = 0;
    393454        }
    394455        if (tok == '(') {
     456            unsigned int type = 0;
    395457            next();
    396458            if (tok != ',') {
    397                 op->reg = asm_parse_reg();
     459                op->reg = asm_parse_reg(&type);
    398460            }
    399461            if (tok == ',') {
    400462                next();
    401463                if (tok != ',') {
    402                     op->reg2 = asm_parse_reg();
     464                    op->reg2 = asm_parse_reg(&type);
    403465                }
    404466                if (tok == ',') {
     
    407469                }
    408470            }
     471            if (type & OP_REG32)
     472                op->type |= OP_EA32;
    409473            skip(')');
    410474        }
     
    418482ST_FUNC void gen_expr32(ExprValue *pe)
    419483{
    420     gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
     484    if (pe->pcrel)
     485        /* If PC-relative, always set VT_SYM, even without symbol,
     486           so as to force a relocation to be emitted.  */
     487        gen_addrpc32(VT_SYM, pe->sym, pe->v);
     488    else
     489        gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
    421490}
    422491
    423492#ifdef TCC_TARGET_X86_64
    424 static void gen_expr64(ExprValue *pe)
     493ST_FUNC void gen_expr64(ExprValue *pe)
    425494{
    426495    gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
     
    432501{
    433502    Sym *sym = pe->sym;
    434     if (sym && sym->r == cur_text_section->sh_num) {
     503    ElfSym *esym = elfsym(sym);
     504    if (esym && esym->st_shndx == cur_text_section->sh_num) {
    435505        /* same section: we can output an absolute value. Note
    436506           that the TCC compiler behaves differently here because
    437507           it always outputs a relocation to ease (future) code
    438508           elimination in the linker */
    439         gen_le32(pe->v + sym->jnext - ind - 4);
     509        gen_le32(pe->v + esym->st_value - ind - 4);
    440510    } else {
    441511        if (sym && sym->type.t == VT_VOID) {
     
    447517}
    448518
    449 #ifdef I386_ASM_16
    450 static void gen_expr16(ExprValue *pe)
    451 {
    452     if (pe->sym)
    453         greloc(cur_text_section, pe->sym, ind, R_386_16);
    454     gen_le16(pe->v);
    455 }
    456 static void gen_disp16(ExprValue *pe)
    457 {
    458     Sym *sym;
    459     sym = pe->sym;
    460     if (sym) {
    461         if (sym->r == cur_text_section->sh_num) {
    462             /* same section: we can output an absolute value. Note
    463                that the TCC compiler behaves differently here because
    464                it always outputs a relocation to ease (future) code
    465                elimination in the linker */
    466             gen_le16(pe->v + sym->jnext - ind - 2);
    467         } else {
    468             greloc(cur_text_section, sym, ind, R_386_PC16);
    469             gen_le16(pe->v - 2);
    470         }
    471     } else {
    472         /* put an empty PC32 relocation */
    473         put_elf_reloc(symtab_section, cur_text_section,
    474                       ind, R_386_PC16, 0);
    475         gen_le16(pe->v - 2);
    476     }
    477 }
    478 #endif
    479 
    480519/* generate the modrm operand */
    481 static inline void asm_modrm(int reg, Operand *op)
     520static inline int asm_modrm(int reg, Operand *op)
    482521{
    483522    int mod, reg1, reg2, sib_reg1;
     
    487526    } else if (op->reg == -1 && op->reg2 == -1) {
    488527        /* displacement only */
    489 #ifdef I386_ASM_16
    490         if (tcc_state->seg_size == 16) {
    491             g(0x06 + (reg << 3));
    492             gen_expr16(&op->e);
    493         } else if (tcc_state->seg_size == 32)
    494 #endif
    495         {
    496             g(0x05 + (reg << 3));
    497             gen_expr32(&op->e);
    498         }
     528#ifdef TCC_TARGET_X86_64
     529        g(0x04 + (reg << 3));
     530        g(0x25);
     531#else
     532        g(0x05 + (reg << 3));
     533#endif
     534        gen_expr32(&op->e);
     535#ifdef TCC_TARGET_X86_64
     536    } else if (op->reg == -2) {
     537        ExprValue *pe = &op->e;
     538        g(0x05 + (reg << 3));
     539        gen_addrpc32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
     540        return ind;
     541#endif
    499542    } else {
    500543        sib_reg1 = op->reg;
     
    514557        if (op->reg2 != -1)
    515558            reg1 = 4;
    516 #ifdef I386_ASM_16
    517         if (tcc_state->seg_size == 32) {
    518 #endif
    519559        g(mod + (reg << 3) + reg1);
    520560        if (reg1 == 4) {
     
    525565            g((op->shift << 6) + (reg2 << 3) + sib_reg1);
    526566        }
    527 #ifdef I386_ASM_16
    528         } else if (tcc_state->seg_size == 16) {
    529             /* edi = 7, esi = 6 --> di = 5, si = 4 */
    530             if ((reg1 == 6) || (reg1 == 7)) {
    531                 reg1 -= 2;
    532             /* ebx = 3 --> bx = 7 */
    533             } else if (reg1 == 3) {
    534                 reg1 = 7;
    535             /* o32 = 5 --> o16 = 6 */
    536             } else if (reg1 == 5) {
    537                 reg1 = 6;
    538             /* sib not valid in 16-bit mode */
    539             } else if (reg1 == 4) {
    540                 reg2 = op->reg2;
    541                 /* bp + si + offset */
    542                 if ((sib_reg1 == 5) && (reg2 == 6)) {
    543                     reg1 = 2;
    544                 /* bp + di + offset */
    545                 } else if ((sib_reg1 == 5) && (reg2 == 7)) {
    546                     reg1 = 3;
    547                 /* bx + si + offset */
    548                 } else if ((sib_reg1 == 3) && (reg2 == 6)) {
    549                     reg1 = 0;
    550                 /* bx + di + offset */
    551                 } else if ((sib_reg1 == 3) && (reg2 == 7)) {
    552                     reg1 = 1;
    553                 } else {
    554                     tcc_error("invalid effective address");
    555                 }
    556                 if (op->e.v == 0)
    557                     mod = 0;
    558             } else {
    559                 tcc_error("invalid register");
    560             }
    561             g(mod + (reg << 3) + reg1);
    562         }
    563 #endif
    564567        /* add offset */
    565568        if (mod == 0x40) {
    566569            g(op->e.v);
    567570        } else if (mod == 0x80 || op->reg == -1) {
    568 #ifdef I386_ASM_16
    569             if (tcc_state->seg_size == 16)
    570                 gen_expr16(&op->e);
    571             else if (tcc_state->seg_size == 32)
    572 #endif
    573                 gen_expr32(&op->e);
    574         }
     571            gen_expr32(&op->e);
     572        }
     573    }
     574    return 0;
     575}
     576
     577#ifdef TCC_TARGET_X86_64
     578#define REX_W 0x48
     579#define REX_R 0x44
     580#define REX_X 0x42
     581#define REX_B 0x41
     582
     583static void asm_rex(int width64, Operand *ops, int nb_ops, int *op_type,
     584                    int regi, int rmi)
     585{
     586  unsigned char rex = width64 ? 0x48 : 0;
     587  int saw_high_8bit = 0;
     588  int i;
     589  if (rmi == -1) {
     590      /* No mod/rm byte, but we might have a register op nevertheless
     591         (we will add it to the opcode later).  */
     592      for(i = 0; i < nb_ops; i++) {
     593          if (op_type[i] & (OP_REG | OP_ST)) {
     594              if (ops[i].reg >= 8) {
     595                  rex |= REX_B;
     596                  ops[i].reg -= 8;
     597              } else if (ops[i].type & OP_REG8_LOW)
     598                  rex |= 0x40;
     599              else if (ops[i].type & OP_REG8 && ops[i].reg >= 4)
     600                  /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
     601                  saw_high_8bit = ops[i].reg;
     602              break;
     603          }
     604      }
     605  } else {
     606      if (regi != -1) {
     607          if (ops[regi].reg >= 8) {
     608              rex |= REX_R;
     609              ops[regi].reg -= 8;
     610          } else if (ops[regi].type & OP_REG8_LOW)
     611              rex |= 0x40;
     612          else if (ops[regi].type & OP_REG8 && ops[regi].reg >= 4)
     613              /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
     614              saw_high_8bit = ops[regi].reg;
     615      }
     616      if (ops[rmi].type & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_EA)) {
     617          if (ops[rmi].reg >= 8) {
     618              rex |= REX_B;
     619              ops[rmi].reg -= 8;
     620          } else if (ops[rmi].type & OP_REG8_LOW)
     621              rex |= 0x40;
     622          else if (ops[rmi].type & OP_REG8 && ops[rmi].reg >= 4)
     623              /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
     624              saw_high_8bit = ops[rmi].reg;
     625      }
     626      if (ops[rmi].type & OP_EA && ops[rmi].reg2 >= 8) {
     627          rex |= REX_X;
     628          ops[rmi].reg2 -= 8;
     629      }
     630  }
     631  if (rex) {
     632      if (saw_high_8bit)
     633          tcc_error("can't encode register %%%ch when REX prefix is required",
     634                    "acdb"[saw_high_8bit-4]);
     635      g(rex);
     636  }
     637}
     638#endif
     639
     640static void maybe_print_stats (void)
     641{
     642  static int already = 1;
     643  if (!already)
     644    /* print stats about opcodes */
     645    {
     646        const struct ASMInstr *pa;
     647        int freq[4];
     648        int op_vals[500];
     649        int nb_op_vals, i, j;
     650
     651        already = 1;
     652        nb_op_vals = 0;
     653        memset(freq, 0, sizeof(freq));
     654        for(pa = asm_instrs; pa->sym != 0; pa++) {
     655            freq[pa->nb_ops]++;
     656            //for(i=0;i<pa->nb_ops;i++) {
     657                for(j=0;j<nb_op_vals;j++) {
     658                    //if (pa->op_type[i] == op_vals[j])
     659                    if (pa->instr_type == op_vals[j])
     660                        goto found;
     661                }
     662                //op_vals[nb_op_vals++] = pa->op_type[i];
     663                op_vals[nb_op_vals++] = pa->instr_type;
     664            found: ;
     665            //}
     666        }
     667        for(i=0;i<nb_op_vals;i++) {
     668            int v = op_vals[i];
     669            //if ((v & (v - 1)) != 0)
     670                printf("%3d: %08x\n", i, v);
     671        }
     672        printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n",
     673               (int)sizeof(asm_instrs),
     674               (int)sizeof(asm_instrs) / (int)sizeof(ASMInstr),
     675               freq[0], freq[1], freq[2], freq[3]);
    575676    }
    576677}
     
    579680{
    580681    const ASMInstr *pa;
    581     int i, modrm_index, reg, v, op1, is_short_jmp, seg_prefix;
     682    int i, modrm_index, modreg_index, reg, v, op1, seg_prefix, pc;
    582683    int nb_ops, s;
    583684    Operand ops[MAX_OPERANDS], *pop;
    584685    int op_type[3]; /* decoded op type */
    585 #ifdef I386_ASM_16
    586     static int a32 = 0, o32 = 0, addr32 = 0, data32 = 0;
    587 #endif
    588 
     686    int alltypes;   /* OR of all operand types */
     687    int autosize;
     688    int p66;
     689#ifdef TCC_TARGET_X86_64
     690    int rex64;
     691#endif
     692
     693    maybe_print_stats();
    589694    /* force synthetic ';' after prefix instruction, so we can handle */
    590695    /* one-line things like "rep stosb" instead of only "rep\nstosb" */
     
    596701    nb_ops = 0;
    597702    seg_prefix = 0;
     703    alltypes = 0;
    598704    for(;;) {
    599705        if (tok == ';' || tok == TOK_LINEFEED)
     
    609715           next();
    610716           parse_operand(s1, pop);
    611 #ifndef I386_ASM_16
    612717           if (!(pop->type & OP_EA)) {
    613718               tcc_error("segment prefix must be followed by memory reference");
    614719           }
    615 #endif
    616720        }
    617721        pop++;
     
    622726    }
    623727
    624     is_short_jmp = 0;
    625728    s = 0; /* avoid warning */
    626729
     730again:
    627731    /* optimize matching by using a lookup table (no hashing is needed
    628732       !) */
    629733    for(pa = asm_instrs; pa->sym != 0; pa++) {
     734        int it = pa->instr_type & OPCT_MASK;
    630735        s = 0;
    631         if (pa->instr_type & OPC_FARITH) {
     736        if (it == OPC_FARITH) {
    632737            v = opcode - pa->sym;
    633738            if (!((unsigned)v < 8 * 6 && (v % 6) == 0))
    634739                continue;
    635         } else if (pa->instr_type & OPC_ARITH) {
     740        } else if (it == OPC_ARITH) {
    636741            if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX))
    637742                continue;
    638743            s = (opcode - pa->sym) % NBWLX;
    639         } else if (pa->instr_type & OPC_SHIFT) {
     744            if ((pa->instr_type & OPC_BWLX) == OPC_WLX)
     745              {
     746                /* We need to reject the xxxb opcodes that we accepted above.
     747                   Note that pa->sym for WLX opcodes is the 'w' token,
     748                   to get the 'b' token subtract one.  */
     749                if (((opcode - pa->sym + 1) % NBWLX) == 0)
     750                    continue;
     751                s++;
     752              }
     753        } else if (it == OPC_SHIFT) {
    640754            if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX))
    641755                continue;
    642756            s = (opcode - pa->sym) % NBWLX;
    643         } else if (pa->instr_type & OPC_TEST) {
     757        } else if (it == OPC_TEST) {
    644758            if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))
    645759                continue;
     760            /* cmovxx is a test opcode but accepts multiple sizes.
     761               The suffixes aren't encoded in the table, instead we
     762               simply force size autodetection always and deal with suffixed
     763               variants below when we don't find e.g. "cmovzl".  */
     764            if (pa->instr_type & OPC_WLX)
     765                s = NBWLX - 1;
    646766        } else if (pa->instr_type & OPC_B) {
     767#ifdef TCC_TARGET_X86_64
     768            /* Some instructions don't have the full size but only
     769               bwl form.  insb e.g. */
     770            if ((pa->instr_type & OPC_WLQ) != OPC_WLQ
     771                && !(opcode >= pa->sym && opcode < pa->sym + NBWLX-1))
     772                continue;
     773#endif
    647774            if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX))
    648775                continue;
     
    658785        if (pa->nb_ops != nb_ops)
    659786            continue;
     787#ifdef TCC_TARGET_X86_64
     788        /* Special case for moves.  Selecting the IM64->REG64 form
     789           should only be done if we really have an >32bit imm64, and that
     790           is hardcoded.  Ignore it here.  */
     791        if (pa->opcode == 0xb0 && ops[0].type != OP_IM64
     792            && (ops[1].type & OP_REG) == OP_REG64
     793            && !(pa->instr_type & OPC_0F))
     794            continue;
     795#endif
    660796        /* now decode and check each operand */
     797        alltypes = 0;
    661798        for(i = 0; i < nb_ops; i++) {
    662799            int op1, op2;
     
    665802            switch(op2) {
    666803            case OPT_IM:
    667                 v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64;
     804                v = OP_IM8 | OP_IM16 | OP_IM32;
    668805                break;
    669806            case OPT_REG:
     
    674811                break;
    675812            case OPT_IMW:
    676                 v = OP_IM16 | OP_IM32 | OP_IM64;
    677                 break;
    678 #ifdef TCC_TARGET_X86_64
    679             case OPT_IMNO64:
    680813                v = OP_IM16 | OP_IM32;
    681814                break;
    682 #endif
     815            case OPT_MMXSSE:
     816                v = OP_MMX | OP_SSE;
     817                break;
     818            case OPT_DISP:
     819            case OPT_DISP8:
     820                v = OP_ADDR;
     821                break;
    683822            default:
    684823                v = 1 << op2;
     
    687826            if (op1 & OPT_EA)
    688827                v |= OP_EA;
    689             op_type[i] = v;
     828            op_type[i] = v;
    690829            if ((ops[i].type & v) == 0)
    691830                goto next;
     831            alltypes |= ops[i].type;
    692832        }
    693833        /* all is matching ! */
     
    699839            int b;
    700840            b = op0_codes[opcode - TOK_ASM_first];
    701 #ifdef I386_ASM_16
    702             if (opcode == TOK_ASM_o32) {
    703                 if (s1->seg_size == 32)
    704                     tcc_error("incorrect prefix");
    705                 else
    706                     o32 = data32 = 1;
    707             } else if (opcode == TOK_ASM_a32) {
    708                 if (s1->seg_size == 32)
    709                     tcc_error("incorrect prefix");
    710                 else
    711                     a32 = addr32 = 1;
    712             }
    713 #endif
    714841            if (b & 0xff00)
    715842                g(b >> 8);
    716843            g(b);
    717844            return;
     845        } else if (opcode <= TOK_ASM_alllast) {
     846            tcc_error("bad operand with opcode '%s'",
     847                  get_tok_str(opcode, NULL));
    718848        } else {
    719             tcc_error("unknown opcode '%s'",
    720                   get_tok_str(opcode, NULL));
     849            /* Special case for cmovcc, we accept size suffixes but ignore
     850               them, but we don't want them to blow up our tables.  */
     851            TokenSym *ts = table_ident[opcode - TOK_IDENT];
     852            if (ts->len >= 6
     853                && strchr("wlq", ts->str[ts->len-1])
     854                && !memcmp(ts->str, "cmov", 4)) {
     855                opcode = tok_alloc(ts->str, ts->len-1)->tok;
     856                goto again;
     857            }
     858            tcc_error("unknown opcode '%s'", ts->str);
    721859        }
    722860    }
    723861    /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
    724     if (s == NBWLX-1) {
    725         for(i = 0; s == NBWLX-1 && i < nb_ops; i++) {
     862    autosize = NBWLX-1;
     863#ifdef TCC_TARGET_X86_64
     864    /* XXX the autosize should rather be zero, to not have to adjust this
     865       all the time.  */
     866    if ((pa->instr_type & OPC_BWLQ) == OPC_B)
     867        autosize = NBWLX-2;
     868#endif
     869    if (s == autosize) {
     870        /* Check for register operands providing hints about the size.
     871           Start from the end, i.e. destination operands.  This matters
     872           only for opcodes accepting different sized registers, lar and lsl
     873           are such opcodes.  */
     874        for(i = nb_ops - 1; s == autosize && i >= 0; i--) {
    726875            if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX)))
    727876                s = reg_to_size[ops[i].type & OP_REG];
    728877        }
    729         if (s == NBWLX-1) {
     878        if (s == autosize) {
    730879            if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
    731                 (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32 | OP_IM64)))
     880                (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32)))
    732881                s = 2;
     882            else if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
     883                     (ops[0].type & OP_EA))
     884                s = NBWLX - 2;
    733885            else
    734886                tcc_error("cannot infer opcode suffix");
     
    736888    }
    737889
    738 #ifdef I386_ASM_16
     890#ifdef TCC_TARGET_X86_64
     891    /* Generate addr32 prefix if needed */
    739892    for(i = 0; i < nb_ops; i++) {
    740         if (ops[i].type & OP_REG32) {
    741             if (s1->seg_size == 16)
    742                 o32 = 1;
    743         } else if (!(ops[i].type & OP_REG32)) {
    744             if (s1->seg_size == 32)
    745                 o32 = 1;
    746         }
    747     }
    748 
    749 
    750     if (s == 1 || (pa->instr_type & OPC_D16)) {
    751         if (s1->seg_size == 32)
    752             o32 = 1;
    753     } else if (s == 2) {
    754         if (s1->seg_size == 16) {
    755             if (!(pa->instr_type & OPC_D16))
    756             o32 = 1;
    757         }
    758     }
    759 
    760     /* generate a16/a32 prefix if needed */
    761     if ((a32 == 1) && (addr32 == 0))
    762         g(0x67);
    763     /* generate o16/o32 prefix if needed */
    764     if ((o32 == 1) && (data32 == 0))
     893        if (ops[i].type & OP_EA32) {
     894            g(0x67);
     895            break;
     896        }
     897    }
     898#endif
     899    /* generate data16 prefix if needed */
     900    p66 = 0;
     901    if (s == 1)
     902        p66 = 1;
     903    else {
     904        /* accepting mmx+sse in all operands --> needs 0x66 to
     905           switch to sse mode.  Accepting only sse in an operand --> is
     906           already SSE insn and needs 0x66/f2/f3 handling.  */
     907        for (i = 0; i < nb_ops; i++)
     908            if ((op_type[i] & (OP_MMX | OP_SSE)) == (OP_MMX | OP_SSE)
     909                && ops[i].type & OP_SSE)
     910                p66 = 1;
     911    }
     912    if (p66)
    765913        g(0x66);
    766 
    767     addr32 = data32 = 0;
    768 #else
    769     /* generate data16 prefix if needed */
    770     if (s == 1 || (pa->instr_type & OPC_D16))
    771         g(0x66);
    772 #ifdef TCC_TARGET_X86_64
    773     else if (s == 3) {
     914#ifdef TCC_TARGET_X86_64
     915    rex64 = 0;
     916    if (pa->instr_type & OPC_48)
     917        rex64 = 1;
     918    else if (s == 3 || (alltypes & OP_REG64)) {
    774919        /* generate REX prefix */
    775         if ((opcode != TOK_ASM_push && opcode != TOK_ASM_pop)
    776             || !(ops[0].type & OP_REG64))
    777             g(0x48);
    778     }
    779 #endif
     920        int default64 = 0;
     921        for(i = 0; i < nb_ops; i++) {
     922            if (op_type[i] == OP_REG64 && pa->opcode != 0xb8) {
     923                /* If only 64bit regs are accepted in one operand
     924                   this is a default64 instruction without need for
     925                   REX prefixes, except for movabs(0xb8).  */
     926                default64 = 1;
     927                break;
     928            }
     929        }
     930        /* XXX find better encoding for the default64 instructions.  */
     931        if (((opcode != TOK_ASM_push && opcode != TOK_ASM_pop
     932              && opcode != TOK_ASM_pushw && opcode != TOK_ASM_pushl
     933              && opcode != TOK_ASM_pushq && opcode != TOK_ASM_popw
     934              && opcode != TOK_ASM_popl && opcode != TOK_ASM_popq
     935              && opcode != TOK_ASM_call && opcode != TOK_ASM_jmp))
     936            && !default64)
     937            rex64 = 1;
     938    }
    780939#endif
    781940
    782941    /* now generates the operation */
    783     if (pa->instr_type & OPC_FWAIT)
     942    if (OPCT_IS(pa->instr_type, OPC_FWAIT))
    784943        g(0x9b);
    785944    if (seg_prefix)
     
    787946
    788947    v = pa->opcode;
     948    if (pa->instr_type & OPC_0F)
     949        v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff);
    789950    if ((v == 0x69 || v == 0x6b) && nb_ops == 2) {
    790951        /* kludge for imul $im, %reg */
     
    806967        /* arith case */
    807968        v += ((opcode - TOK_ASM_addb) / NBWLX) << 3;
    808     } else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) {
     969    } else if ((pa->instr_type & (OPCT_MASK | OPC_MODRM)) == OPC_FARITH) {
    809970        /* fpu arith case */
    810971        v += ((opcode - pa->sym) / 6) << 3;
    811972    }
     973
     974    /* search which operand will be used for modrm */
     975    modrm_index = -1;
     976    modreg_index = -1;
     977    if (pa->instr_type & OPC_MODRM) {
     978        if (!nb_ops) {
     979            /* A modrm opcode without operands is a special case (e.g. mfence).
     980               It has a group and acts as if there's an register operand 0
     981               (ax).  */
     982            i = 0;
     983            ops[i].type = OP_REG;
     984            ops[i].reg = 0;
     985            goto modrm_found;
     986        }
     987        /* first look for an ea operand */
     988        for(i = 0;i < nb_ops; i++) {
     989            if (op_type[i] & OP_EA)
     990                goto modrm_found;
     991        }
     992        /* then if not found, a register or indirection (shift instructions) */
     993        for(i = 0;i < nb_ops; i++) {
     994            if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR))
     995                goto modrm_found;
     996        }
     997#ifdef ASM_DEBUG
     998        tcc_error("bad op table");
     999#endif
     1000    modrm_found:
     1001        modrm_index = i;
     1002        /* if a register is used in another operand then it is
     1003           used instead of group */
     1004        for(i = 0;i < nb_ops; i++) {
     1005            int t = op_type[i];
     1006            if (i != modrm_index &&
     1007                (t & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) {
     1008                modreg_index = i;
     1009                break;
     1010            }
     1011        }
     1012    }
     1013#ifdef TCC_TARGET_X86_64
     1014    asm_rex (rex64, ops, nb_ops, op_type, modreg_index, modrm_index);
     1015#endif
     1016
    8121017    if (pa->instr_type & OPC_REG) {
     1018        /* mov $im, %reg case */
     1019        if (v == 0xb0 && s >= 1)
     1020            v += 7;
    8131021        for(i = 0; i < nb_ops; i++) {
    8141022            if (op_type[i] & (OP_REG | OP_ST)) {
     
    8171025            }
    8181026        }
    819         /* mov $im, %reg case */
    820         if (pa->opcode == 0xb0 && s >= 1)
    821             v += 7;
    8221027    }
    8231028    if (pa->instr_type & OPC_B)
    8241029        v += s >= 1;
    825     if (pa->instr_type & OPC_TEST)
    826         v += test_bits[opcode - pa->sym];
    827     if (pa->instr_type & OPC_SHORTJMP) {
    828         Sym *sym;
     1030    if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) {
     1031        ElfSym *esym;
    8291032        int jmp_disp;
    8301033
    8311034        /* see if we can really generate the jump with a byte offset */
    832         sym = ops[0].e.sym;
    833         if (!sym)
     1035        esym = elfsym(ops[0].e.sym);
     1036        if (!esym || esym->st_shndx != cur_text_section->sh_num)
    8341037            goto no_short_jump;
    835         if (sym->r != cur_text_section->sh_num)
    836             goto no_short_jump;
    837         jmp_disp = ops[0].e.v + sym->jnext - ind - 2;
     1038        jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff);
    8381039        if (jmp_disp == (int8_t)jmp_disp) {
    8391040            /* OK to generate jump */
    840             is_short_jmp = 1;
     1041            ops[0].e.sym = 0;
    8411042            ops[0].e.v = jmp_disp;
     1043            op_type[0] = OP_IM8S;
    8421044        } else {
    8431045        no_short_jump:
    844             if (pa->instr_type & OPC_JMP) {
    845                 /* long jump will be allowed. need to modify the
    846                    opcode slightly */
    847                 if (v == 0xeb)
    848                     v = 0xe9;
    849                 else
    850                     v += 0x0f10;
    851             } else {
    852                 tcc_error("invalid displacement");
    853             }
    854         }
    855     }
    856     op1 = v >> 8;
     1046            /* long jump will be allowed. need to modify the
     1047               opcode slightly */
     1048            if (v == 0xeb) /* jmp */
     1049                v = 0xe9;
     1050            else if (v == 0x70) /* jcc */
     1051                v += 0x0f10;
     1052            else
     1053                tcc_error("invalid displacement");
     1054        }
     1055    }
     1056    if (OPCT_IS(pa->instr_type, OPC_TEST))
     1057        v += test_bits[opcode - pa->sym];
     1058    op1 = v >> 16;
     1059    if (op1)
     1060        g(op1);
     1061    op1 = (v >> 8) & 0xff;
    8571062    if (op1)
    8581063        g(op1);
    8591064    g(v);
    8601065
    861     /* search which operand will used for modrm */
    862     modrm_index = 0;
    863     if (pa->instr_type & OPC_SHIFT) {
     1066    if (OPCT_IS(pa->instr_type, OPC_SHIFT)) {
    8641067        reg = (opcode - pa->sym) / NBWLX;
    8651068        if (reg == 6)
    8661069            reg = 7;
    867     } else if (pa->instr_type & OPC_ARITH) {
     1070    } else if (OPCT_IS(pa->instr_type, OPC_ARITH)) {
    8681071        reg = (opcode - pa->sym) / NBWLX;
    869     } else if (pa->instr_type & OPC_FARITH) {
     1072    } else if (OPCT_IS(pa->instr_type, OPC_FARITH)) {
    8701073        reg = (opcode - pa->sym) / 6;
    8711074    } else {
    8721075        reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7;
    8731076    }
     1077
     1078    pc = 0;
    8741079    if (pa->instr_type & OPC_MODRM) {
    875         /* first look for an ea operand */
    876         for(i = 0;i < nb_ops; i++) {
    877             if (op_type[i] & OP_EA)
    878                 goto modrm_found;
    879         }
    880         /* then if not found, a register or indirection (shift instructions) */
    881         for(i = 0;i < nb_ops; i++) {
    882             if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR))
    883                 goto modrm_found;
    884         }
    885 #ifdef ASM_DEBUG
    886         tcc_error("bad op table");
    887 #endif
    888     modrm_found:
    889         modrm_index = i;
    8901080        /* if a register is used in another operand then it is
    8911081           used instead of group */
    892         for(i = 0;i < nb_ops; i++) {
    893             v = op_type[i];
    894             if (i != modrm_index &&
    895                 (v & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) {
    896                 reg = ops[i].reg;
    897                 break;
    898             }
    899         }
    900 
    901         asm_modrm(reg, &ops[modrm_index]);
     1082        if (modreg_index >= 0)
     1083            reg = ops[modreg_index].reg;
     1084        pc = asm_modrm(reg, &ops[modrm_index]);
    9021085    }
    9031086
    9041087    /* emit constants */
    9051088#ifndef TCC_TARGET_X86_64
    906     if (pa->opcode == 0x9a || pa->opcode == 0xea) {
     1089    if (!(pa->instr_type & OPC_0F)
     1090        && (pa->opcode == 0x9a || pa->opcode == 0xea)) {
    9071091        /* ljmp or lcall kludge */
    908 #ifdef I386_ASM_16
    909         if (s1->seg_size == 16 && o32 == 0)
    910             gen_expr16(&ops[1].e);
    911         else
    912 #endif
    913             gen_expr32(&ops[1].e);
     1092        gen_expr32(&ops[1].e);
    9141093        if (ops[0].e.sym)
    9151094            tcc_error("cannot relocate");
     
    9331112                    v = OP_IM64;
    9341113            }
     1114
     1115            if ((v & (OP_IM8 | OP_IM8S | OP_IM16)) && ops[i].e.sym)
     1116                tcc_error("cannot relocate");
     1117
    9351118            if (v & (OP_IM8 | OP_IM8S)) {
    936                 if (ops[i].e.sym)
    937                     goto error_relocate;
    9381119                g(ops[i].e.v);
    9391120            } else if (v & OP_IM16) {
    940 #ifdef I386_ASM_16
    941                 if (s1->seg_size == 16)
    942                     gen_expr16(&ops[i].e);
    943                 else
    944 #endif
    945                 if (ops[i].e.sym)
    946                 error_relocate:
    947                     tcc_error("cannot relocate");
    948                 else
    949                     gen_le16(ops[i].e.v);
     1121                gen_le16(ops[i].e.v);
     1122#ifdef TCC_TARGET_X86_64
     1123            } else if (v & OP_IM64) {
     1124                gen_expr64(&ops[i].e);
     1125#endif
     1126            } else if (pa->op_type[i] == OPT_DISP || pa->op_type[i] == OPT_DISP8) {
     1127                gen_disp32(&ops[i].e);
    9501128            } else {
    951                 if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
    952                     if (is_short_jmp)
    953                         g(ops[i].e.v);
    954 #ifdef I386_ASM_16
    955                     else if (s1->seg_size == 16)
    956                         gen_disp16(&ops[i].e);
    957 #endif
    958                     else
    959                         gen_disp32(&ops[i].e);
    960                 } else {
    961 #ifdef I386_ASM_16
    962                     if (s1->seg_size == 16 && !((o32 == 1) && (v & OP_IM32)))
    963                         gen_expr16(&ops[i].e);
    964                     else
    965 #endif
    966 #ifdef TCC_TARGET_X86_64
    967                     if (v & OP_IM64)
    968                         gen_expr64(&ops[i].e);
    969                     else
    970 #endif
    971                         gen_expr32(&ops[i].e);
    972                 }
     1129                gen_expr32(&ops[i].e);
    9731130            }
    974 #ifdef I386_ASM_16
    975         } else if (v & (OP_REG16 | OP_REG32)) {
    976             if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
    977                 /* jmp $r */
    978                 g(0xE0 + ops[i].reg);
    979             }
    980 #endif
    981 #ifdef TCC_TARGET_X86_64
    982         } else if (v & (OP_REG32 | OP_REG64)) {
    983             if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
    984                 /* jmp $r */
    985                 g(0xE0 + ops[i].reg);
    986             }
    987 #endif
    988         }
    989     }
    990 #ifdef I386_ASM_16
    991     a32 = o32 = 0;
    992 #endif
     1131        }
     1132    }
     1133
     1134    /* after immediate operands, adjust pc-relative address */
     1135    if (pc)
     1136        add32le(cur_text_section->data + pc - 4, pc - ind);
    9931137}
    9941138
     
    10221166            break;
    10231167        case 'r':
     1168        case 'R':
     1169        case 'p':
    10241170            pr = 3;
    10251171            break;
     
    10271173        case 'M':
    10281174        case 'I':
     1175        case 'e':
    10291176        case 'i':
    10301177        case 'm':
     
    10471194        p++;
    10481195    return p;
     1196}
     1197
     1198/* If T (a token) is of the form "%reg" returns the register
     1199   number and type, otherwise return -1.  */
     1200ST_FUNC int asm_parse_regvar (int t)
     1201{
     1202    const char *s;
     1203    Operand op;
     1204    if (t < TOK_IDENT)
     1205        return -1;
     1206    s = table_ident[t - TOK_IDENT]->str;
     1207    if (s[0] != '%')
     1208        return -1;
     1209    t = tok_alloc(s+1, strlen(s)-1)->tok;
     1210    unget_tok(t);
     1211    unget_tok('%');
     1212    parse_operand(tcc_state, &op);
     1213    /* Accept only integer regs for now.  */
     1214    if (op.type & OP_REG)
     1215        return op.reg;
     1216    else
     1217        return -1;
    10491218}
    10501219
     
    10911260            operands[k].input_index = i;
    10921261            op->priority = 5;
     1262        } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL
     1263                   && op->vt->sym
     1264                   && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) {
     1265            op->priority = 1;
     1266            op->reg = reg;
    10931267        } else {
    10941268            op->priority = constraint_priority(str);
     
    11381312            reg_mask = REG_IN_MASK;
    11391313        }
     1314        if (op->reg >= 0) {
     1315            if (is_reg_allocated(op->reg))
     1316                tcc_error("asm regvar requests register that's taken already");
     1317            reg = op->reg;
     1318            goto reg_found;
     1319        }
    11401320    try_next:
    11411321        c = *str++;
     
    11901370            goto try_next;
    11911371        case 'r':
     1372        case 'R':
     1373        case 'p': /* A general address, for x86(64) any register is acceptable*/
    11921374            /* any general register */
    11931375            for(reg = 0; reg < 8; reg++) {
     
    12021384            regs_allocated[reg] |= reg_mask;
    12031385            break;
     1386        case 'e':
    12041387        case 'i':
    12051388            if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
     
    12941477    r = sv->r;
    12951478    if ((r & VT_VALMASK) == VT_CONST) {
    1296         if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n')
     1479        if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' &&
     1480            modifier != 'P')
    12971481            cstr_ccat(add_str, '$');
    12981482        if (r & VT_SYM) {
    1299             cstr_cat(add_str, get_tok_str(sv->sym->v, NULL));
    1300             if (sv->c.i != 0) {
    1301                 cstr_ccat(add_str, '+');
    1302             } else {
    1303                 return;
    1304             }
     1483            const char *name = get_tok_str(sv->sym->v, NULL);
     1484            if (sv->sym->v >= SYM_FIRST_ANOM) {
     1485                /* In case of anonymous symbols ("L.42", used
     1486                   for static data labels) we can't find them
     1487                   in the C symbol table when later looking up
     1488                   this name.  So enter them now into the asm label
     1489                   list when we still know the symbol.  */
     1490                get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
     1491            }
     1492            cstr_cat(add_str, name, -1);
     1493            if ((uint32_t)sv->c.i == 0)
     1494                goto no_offset;
     1495            cstr_ccat(add_str, '+');
    13051496        }
    13061497        val = sv->c.i;
    13071498        if (modifier == 'n')
    13081499            val = -val;
    1309         snprintf(buf, sizeof(buf), "%d", sv->c.i);
    1310         cstr_cat(add_str, buf);
     1500        snprintf(buf, sizeof(buf), "%d", (int)sv->c.i);
     1501        cstr_cat(add_str, buf, -1);
     1502    no_offset:;
     1503#ifdef TCC_TARGET_X86_64
     1504        if (r & VT_LVAL)
     1505            cstr_cat(add_str, "(%rip)", -1);
     1506#endif
    13111507    } else if ((r & VT_VALMASK) == VT_LOCAL) {
    1312         snprintf(buf, sizeof(buf), "%d(%%ebp)", sv->c.i);
    1313         cstr_cat(add_str, buf);
     1508#ifdef TCC_TARGET_X86_64
     1509        snprintf(buf, sizeof(buf), "%d(%%rbp)", (int)sv->c.i);
     1510#else
     1511        snprintf(buf, sizeof(buf), "%d(%%ebp)", (int)sv->c.i);
     1512#endif
     1513        cstr_cat(add_str, buf, -1);
    13141514    } else if (r & VT_LVAL) {
    13151515        reg = r & VT_VALMASK;
     
    13171517            tcc_error("internal compiler error");
    13181518        snprintf(buf, sizeof(buf), "(%%%s)",
    1319                  get_tok_str(TOK_ASM_eax + reg, NULL));
    1320         cstr_cat(add_str, buf);
     1519#ifdef TCC_TARGET_X86_64
     1520                 get_tok_str(TOK_ASM_rax + reg, NULL)
     1521#else
     1522                 get_tok_str(TOK_ASM_eax + reg, NULL)
     1523#endif
     1524                 );
     1525        cstr_cat(add_str, buf, -1);
    13211526    } else {
    13221527        /* register case */
     
    13261531
    13271532        /* choose register operand size */
    1328         if ((sv->type.t & VT_BTYPE) == VT_BYTE)
     1533        if ((sv->type.t & VT_BTYPE) == VT_BYTE ||
     1534            (sv->type.t & VT_BTYPE) == VT_BOOL)
    13291535            size = 1;
    13301536        else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
    13311537            size = 2;
    13321538#ifdef TCC_TARGET_X86_64
    1333         else if ((sv->type.t & VT_BTYPE) == VT_LLONG)
     1539        else if ((sv->type.t & VT_BTYPE) == VT_LLONG ||
     1540                 (sv->type.t & VT_BTYPE) == VT_PTR)
    13341541            size = 8;
    13351542#endif
     
    13491556        } else if (modifier == 'w') {
    13501557            size = 2;
     1558        } else if (modifier == 'k') {
     1559            size = 4;
    13511560#ifdef TCC_TARGET_X86_64
    13521561        } else if (modifier == 'q') {
     
    13751584        }
    13761585        snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL));
    1377         cstr_cat(add_str, buf);
     1586        cstr_cat(add_str, buf, -1);
    13781587    }
    13791588}
    13801589
    1381 /* generate prolog and epilog code for asm statment */
     1590/* generate prolog and epilog code for asm statement */
    13821591ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
    13831592                         int nb_outputs, int is_output,
     
    13881597    ASMOperand *op;
    13891598    int i, reg;
    1390     static uint8_t reg_saved[NB_SAVED_REGS] = { 3, 6, 7 };
     1599
     1600    /* Strictly speaking %Xbp and %Xsp should be included in the
     1601       call-preserved registers, but currently it doesn't matter.  */
     1602#ifdef TCC_TARGET_X86_64
     1603#ifdef TCC_TARGET_PE
     1604    static uint8_t reg_saved[] = { 3, 6, 7, 12, 13, 14, 15 };
     1605#else
     1606    static uint8_t reg_saved[] = { 3, 12, 13, 14, 15 };
     1607#endif
     1608#else
     1609    static uint8_t reg_saved[] = { 3, 6, 7 };
     1610#endif
    13911611
    13921612    /* mark all used registers */
     
    13991619    if (!is_output) {
    14001620        /* generate reg save code */
    1401         for(i = 0; i < NB_SAVED_REGS; i++) {
     1621        for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) {
    14021622            reg = reg_saved[i];
    14031623            if (regs_allocated[reg]) {
    1404 #ifdef I386_ASM_16
    1405                 if (tcc_state->seg_size == 16)
    1406                     g(0x66);
    1407 #endif
     1624                if (reg >= 8)
     1625                  g(0x41), reg-=8;
    14081626                g(0x50 + reg);
    14091627            }
     
    14201638                    SValue sv;
    14211639                    sv = *op->vt;
    1422                     sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
     1640                    sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
     1641                    sv.type.t = VT_PTR;
    14231642                    load(op->reg, &sv);
    14241643                } else if (i >= nb_outputs || op->is_rw) {
     
    14281647                        SValue sv;
    14291648                        sv = *op->vt;
    1430                         sv.c.ul += 4;
     1649                        sv.c.i += 4;
    14311650                        load(TREG_XDX, &sv);
    14321651                    }
     
    14441663                        sv = *op->vt;
    14451664                        sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
     1665                        sv.type.t = VT_PTR;
    14461666                        load(out_reg, &sv);
    14471667
     1668                        sv = *op->vt;
    14481669                        sv.r = (sv.r & ~VT_VALMASK) | out_reg;
    14491670                        store(op->reg, &sv);
     
    14541675                        SValue sv;
    14551676                        sv = *op->vt;
    1456                         sv.c.ul += 4;
     1677                        sv.c.i += 4;
    14571678                        store(TREG_XDX, &sv);
    14581679                    }
     
    14611682        }
    14621683        /* generate reg restore code */
    1463         for(i = NB_SAVED_REGS - 1; i >= 0; i--) {
     1684        for(i = sizeof(reg_saved)/sizeof(reg_saved[0]) - 1; i >= 0; i--) {
    14641685            reg = reg_saved[i];
    14651686            if (regs_allocated[reg]) {
    1466 #ifdef I386_ASM_16
    1467                 if (tcc_state->seg_size == 16)
    1468                     g(0x66);
    1469 #endif
     1687                if (reg >= 8)
     1688                  g(0x41), reg-=8;
    14701689                g(0x58 + reg);
    14711690            }
     
    14781697    int reg;
    14791698    TokenSym *ts;
     1699#ifdef TCC_TARGET_X86_64
     1700    unsigned int type;
     1701#endif
    14801702
    14811703    if (!strcmp(str, "memory") ||
    1482         !strcmp(str, "cc"))
     1704        !strcmp(str, "cc") ||
     1705        !strcmp(str, "flags"))
    14831706        return;
    14841707    ts = tok_alloc(str, strlen(str));
     
    14911714    } else if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) {
    14921715        reg -= TOK_ASM_rax;
     1716    } else if ((reg = asm_parse_numeric_reg(reg, &type)) >= 0) {
     1717        ;
    14931718#endif
    14941719    } else {
Note: See TracChangeset for help on using the changeset viewer.