📄 i386-asm.c
字号:
if (reg2 == -1) reg2 = 4; /* indicate no index */ g((op->shift << 6) + (reg2 << 3) + sib_reg1); } /* add offset */ if (mod == 0x40) { g(op->e.v); } else if (mod == 0x80 || op->reg == -1) { gen_expr32(&op->e); } }}static void asm_opcode(TCCState *s1, int opcode){ const ASMInstr *pa; int i, modrm_index, reg, v, op1, is_short_jmp; int nb_ops, s, ss; Operand ops[MAX_OPERANDS], *pop; int op_type[3]; /* decoded op type */ /* get operands */ pop = ops; nb_ops = 0; for(;;) { if (tok == ';' || tok == TOK_LINEFEED) break; if (nb_ops >= MAX_OPERANDS) { error("incorrect number of operands"); } parse_operand(s1, pop); pop++; nb_ops++; if (tok != ',') break; next(); } is_short_jmp = 0; s = 0; /* avoid warning */ /* optimize matching by using a lookup table (no hashing is needed !) */ for(pa = asm_instrs; pa->sym != 0; pa++) { s = 0; if (pa->instr_type & OPC_FARITH) { v = opcode - pa->sym; if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) continue; } else if (pa->instr_type & OPC_ARITH) { if (!(opcode >= pa->sym && opcode < pa->sym + 8 * 4)) continue; goto compute_size; } else if (pa->instr_type & OPC_SHIFT) { if (!(opcode >= pa->sym && opcode < pa->sym + 7 * 4)) continue; goto compute_size; } else if (pa->instr_type & OPC_TEST) { if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) continue; } else if (pa->instr_type & OPC_B) { if (!(opcode >= pa->sym && opcode <= pa->sym + 3)) continue; compute_size: s = (opcode - pa->sym) & 3; } else if (pa->instr_type & OPC_WL) { if (!(opcode >= pa->sym && opcode <= pa->sym + 2)) continue; s = opcode - pa->sym + 1; } else { if (pa->sym != opcode) continue; } if (pa->nb_ops != nb_ops) continue; /* now decode and check each operand */ for(i = 0; i < nb_ops; i++) { int op1, op2; op1 = pa->op_type[i]; op2 = op1 & 0x1f; switch(op2) { case OPT_IM: v = OP_IM8 | OP_IM16 | OP_IM32; break; case OPT_REG: v = OP_REG8 | OP_REG16 | OP_REG32; break; case OPT_REGW: v = OP_REG16 | OP_REG32; break; case OPT_IMW: v = OP_IM16 | OP_IM32; break; default: v = 1 << op2; break; } if (op1 & OPT_EA) v |= OP_EA; op_type[i] = v; if ((ops[i].type & v) == 0) goto next; } /* all is matching ! */ break; next: ; } if (pa->sym == 0) { if (opcode >= TOK_ASM_pusha && opcode <= TOK_ASM_emms) { int b; b = op0_codes[opcode - TOK_ASM_pusha]; if (b & 0xff00) g(b >> 8); g(b); return; } else { error("unknown opcode '%s'", get_tok_str(opcode, NULL)); } } /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */ if (s == 3) { for(i = 0; s == 3 && i < nb_ops; i++) { if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX))) s = reg_to_size[ops[i].type & OP_REG]; } if (s == 3) { if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32))) s = 2; else error("cannot infer opcode suffix"); } } /* generate data16 prefix if needed */ ss = s; if (s == 1 || (pa->instr_type & OPC_D16)) g(WORD_PREFIX_OPCODE); else if (s == 2) s = 1; /* now generates the operation */ if (pa->instr_type & OPC_FWAIT) g(0x9b); v = pa->opcode; if (v == 0x69 || v == 0x69) { /* kludge for imul $im, %reg */ nb_ops = 3; ops[2] = ops[1]; } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) { v--; /* int $3 case */ nb_ops = 0; } else if ((v == 0x06 || v == 0x07)) { if (ops[0].reg >= 4) { /* push/pop %fs or %gs */ v = 0x0fa0 + (v - 0x06) + ((ops[0].reg - 4) << 3); } else { v += ops[0].reg << 3; } nb_ops = 0; } else if (v <= 0x05) { /* arith case */ v += ((opcode - TOK_ASM_addb) >> 2) << 3; } else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) { /* fpu arith case */ v += ((opcode - pa->sym) / 6) << 3; } if (pa->instr_type & OPC_REG) { for(i = 0; i < nb_ops; i++) { if (op_type[i] & (OP_REG | OP_ST)) { v += ops[i].reg; break; } } /* mov $im, %reg case */ if (pa->opcode == 0xb0 && s >= 1) v += 7; } if (pa->instr_type & OPC_B) v += s; if (pa->instr_type & OPC_TEST) v += test_bits[opcode - pa->sym]; if (pa->instr_type & OPC_SHORTJMP) { Sym *sym; int jmp_disp; /* see if we can really generate the jump with a byte offset */ sym = ops[0].e.sym; if (!sym) goto no_short_jump; if (sym->r != cur_text_section->sh_num) goto no_short_jump; jmp_disp = ops[0].e.v + (long)sym->next - ind - 2; if (jmp_disp == (int8_t)jmp_disp) { /* OK to generate jump */ is_short_jmp = 1; ops[0].e.v = jmp_disp; } else { no_short_jump: if (pa->instr_type & OPC_JMP) { /* long jump will be allowed. need to modify the opcode slightly */ if (v == 0xeb) v = 0xe9; else v += 0x0f10; } else { error("invalid displacement"); } } } op1 = v >> 8; if (op1) g(op1); g(v); /* search which operand will used for modrm */ modrm_index = 0; if (pa->instr_type & OPC_SHIFT) { reg = (opcode - pa->sym) >> 2; if (reg == 6) reg = 7; } else if (pa->instr_type & OPC_ARITH) { reg = (opcode - pa->sym) >> 2; } else if (pa->instr_type & OPC_FARITH) { reg = (opcode - pa->sym) / 6; } else { reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; } if (pa->instr_type & OPC_MODRM) { /* first look for an ea operand */ for(i = 0;i < nb_ops; i++) { if (op_type[i] & OP_EA) goto modrm_found; } /* then if not found, a register or indirection (shift instructions) */ for(i = 0;i < nb_ops; i++) { if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR)) goto modrm_found; }#ifdef ASM_DEBUG error("bad op table");#endif modrm_found: modrm_index = i; /* if a register is used in another operand then it is used instead of group */ for(i = 0;i < nb_ops; i++) { v = op_type[i]; if (i != modrm_index && (v & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) { reg = ops[i].reg; break; } } asm_modrm(reg, &ops[modrm_index]); } /* emit constants */ if (pa->opcode == 0x9a || pa->opcode == 0xea) { /* ljmp or lcall kludge */ gen_expr32(&ops[1].e); if (ops[0].e.sym) error("cannot relocate"); gen_le16(ops[0].e.v); } else { for(i = 0;i < nb_ops; i++) { v = op_type[i]; if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM8S | OP_ADDR)) { /* if multiple sizes are given it means we must look at the op size */ if (v == (OP_IM8 | OP_IM16 | OP_IM32) || v == (OP_IM16 | OP_IM32)) { if (ss == 0) v = OP_IM8; else if (ss == 1) v = OP_IM16; else v = OP_IM32; } if (v & (OP_IM8 | OP_IM8S)) { if (ops[i].e.sym) goto error_relocate; g(ops[i].e.v); } else if (v & OP_IM16) { if (ops[i].e.sym) { error_relocate: error("cannot relocate"); } gen_le16(ops[i].e.v); } else { if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { if (is_short_jmp) g(ops[i].e.v); else gen_disp32(&ops[i].e); } else { gen_expr32(&ops[i].e); } } } } }}#define NB_SAVED_REGS 3#define NB_ASM_REGS 8/* return the constraint priority (we allocate first the lowest numbered constraints) */static inline int constraint_priority(const char *str){ int priority, c, pr; /* we take the lowest priority */ priority = 0; for(;;) { c = *str; if (c == '\0') break; str++; switch(c) { case 'A': pr = 0; break; case 'a': case 'b': case 'c': case 'd': case 'S': case 'D': pr = 1; break; case 'q': pr = 2; break; case 'r': pr = 3; break; case 'N': case 'M': case 'I': case 'i': case 'm': case 'g': pr = 4; break; default: error("unknown constraint '%c'", c); pr = 0; } if (pr > priority) priority = pr; } return priority;}static const char *skip_constraint_modifiers(const char *p){ while (*p == '=' || *p == '&' || *p == '+' || *p == '%') p++; return p;}#define REG_OUT_MASK 0x01#define REG_IN_MASK 0x02#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)static void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg){ ASMOperand *op; int sorted_op[MAX_ASM_OPERANDS]; int i, j, k, p1, p2, tmp, reg, c, reg_mask; const char *str; uint8_t regs_allocated[NB_ASM_REGS]; /* init fields */ for(i=0;i<nb_operands;i++) { op = &operands[i]; op->input_index = -1; op->ref_index = -1; op->reg = -1; op->is_memory = 0; op->is_rw = 0; } /* compute constraint priority and evaluate references to output constraints if input constraints */ for(i=0;i<nb_operands;i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -