Alien-TinyCC

 view release on metacpan or  search on metacpan

src/i386-asm.c  view on Meta::CPAN

            op->e.sym = e.sym;
        } else {
            next();
            if (tok == '%') {
                unget_tok('(');
                op->e.v = 0;
                op->e.sym = NULL;
            } else {
                /* bracketed offset expression */
                asm_expr(s1, &e);
                if (tok != ')')
                    expect(")");
                next();
                op->e.v = e.v;
                op->e.sym = e.sym;
            }
        }
        if (tok == '(') {
            next();
            if (tok != ',') {
                op->reg = asm_parse_reg();
            }
            if (tok == ',') {
                next();
                if (tok != ',') {
                    op->reg2 = asm_parse_reg();
                }
                if (tok == ',') {
                    next();
                    op->shift = get_reg_shift(s1);
                }
            }
            skip(')');
        }
        if (op->reg == -1 && op->reg2 == -1)
            op->type |= OP_ADDR;
    }
    op->type |= indir;
}

/* XXX: unify with C code output ? */
ST_FUNC void gen_expr32(ExprValue *pe)
{
    gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
}

#ifdef TCC_TARGET_X86_64
static void gen_expr64(ExprValue *pe)
{
    gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
}
#endif

/* XXX: unify with C code output ? */
static void gen_disp32(ExprValue *pe)
{
    Sym *sym = pe->sym;
    if (sym && sym->r == cur_text_section->sh_num) {
        /* same section: we can output an absolute value. Note
           that the TCC compiler behaves differently here because
           it always outputs a relocation to ease (future) code
           elimination in the linker */
        gen_le32(pe->v + sym->jnext - ind - 4);
    } else {
        if (sym && sym->type.t == VT_VOID) {
            sym->type.t = VT_FUNC;
            sym->type.ref = NULL;
        }
        gen_addrpc32(VT_SYM, sym, pe->v);
    }
}

#ifdef I386_ASM_16
static void gen_expr16(ExprValue *pe)
{
    if (pe->sym)
        greloc(cur_text_section, pe->sym, ind, R_386_16);
    gen_le16(pe->v);
}
static void gen_disp16(ExprValue *pe)
{
    Sym *sym;
    sym = pe->sym;
    if (sym) {
        if (sym->r == cur_text_section->sh_num) {
            /* same section: we can output an absolute value. Note
               that the TCC compiler behaves differently here because
               it always outputs a relocation to ease (future) code
               elimination in the linker */
            gen_le16(pe->v + sym->jnext - ind - 2);
        } else {
            greloc(cur_text_section, sym, ind, R_386_PC16);
            gen_le16(pe->v - 2);
        }
    } else {
        /* put an empty PC32 relocation */
        put_elf_reloc(symtab_section, cur_text_section,
                      ind, R_386_PC16, 0);
        gen_le16(pe->v - 2);
    }
}
#endif

/* generate the modrm operand */
static inline void asm_modrm(int reg, Operand *op)
{
    int mod, reg1, reg2, sib_reg1;

    if (op->type & (OP_REG | OP_MMX | OP_SSE)) {
        g(0xc0 + (reg << 3) + op->reg);
    } else if (op->reg == -1 && op->reg2 == -1) {
        /* displacement only */
#ifdef I386_ASM_16
        if (tcc_state->seg_size == 16) {
            g(0x06 + (reg << 3));
            gen_expr16(&op->e);
        } else if (tcc_state->seg_size == 32)
#endif
        {
            g(0x05 + (reg << 3));
            gen_expr32(&op->e);
        }
    } else {
        sib_reg1 = op->reg;
        /* fist compute displacement encoding */
        if (sib_reg1 == -1) {
            sib_reg1 = 5;
            mod = 0x00;
        } else if (op->e.v == 0 && !op->e.sym && op->reg != 5) {
            mod = 0x00;
        } else if (op->e.v == (int8_t)op->e.v && !op->e.sym) {
            mod = 0x40;
        } else {
            mod = 0x80;
        }
        /* compute if sib byte needed */
        reg1 = op->reg;
        if (op->reg2 != -1)
            reg1 = 4;
#ifdef I386_ASM_16
        if (tcc_state->seg_size == 32) {
#endif
        g(mod + (reg << 3) + reg1);
        if (reg1 == 4) {
            /* add sib byte */
            reg2 = op->reg2;
            if (reg2 == -1)
                reg2 = 4; /* indicate no index */
            g((op->shift << 6) + (reg2 << 3) + sib_reg1);
        }
#ifdef I386_ASM_16
        } else if (tcc_state->seg_size == 16) {
            /* edi = 7, esi = 6 --> di = 5, si = 4 */
            if ((reg1 == 6) || (reg1 == 7)) {
                reg1 -= 2;
            /* ebx = 3 --> bx = 7 */

src/i386-asm.c  view on Meta::CPAN

    }
    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) / NBWLX;
        if (reg == 6)
            reg = 7;
    } else if (pa->instr_type & OPC_ARITH) {
        reg = (opcode - pa->sym) / NBWLX;
    } 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
        tcc_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 */
#ifndef TCC_TARGET_X86_64
    if (pa->opcode == 0x9a || pa->opcode == 0xea) {
        /* ljmp or lcall kludge */
#ifdef I386_ASM_16
        if (s1->seg_size == 16 && o32 == 0)
            gen_expr16(&ops[1].e);
        else
#endif
            gen_expr32(&ops[1].e);
        if (ops[0].e.sym)
            tcc_error("cannot relocate");
        gen_le16(ops[0].e.v);
        return;
    }
#endif
    for(i = 0;i < nb_ops; i++) {
        v = op_type[i];
        if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) {
            /* if multiple sizes are given it means we must look
               at the op size */
            if ((v | OP_IM8 | OP_IM64) == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64)) {
                if (s == 0)
                    v = OP_IM8;
                else if (s == 1)
                    v = OP_IM16;
                else if (s == 2 || (v & OP_IM64) == 0)
                    v = OP_IM32;
                else
                    v = OP_IM64;
            }
            if (v & (OP_IM8 | OP_IM8S)) {
                if (ops[i].e.sym)
                    goto error_relocate;
                g(ops[i].e.v);
            } else if (v & OP_IM16) {
#ifdef I386_ASM_16
                if (s1->seg_size == 16)
                    gen_expr16(&ops[i].e);
                else
#endif
                if (ops[i].e.sym)
                error_relocate:
                    tcc_error("cannot relocate");
                else
                    gen_le16(ops[i].e.v);
            } else {
                if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
                    if (is_short_jmp)
                        g(ops[i].e.v);
#ifdef I386_ASM_16
                    else if (s1->seg_size == 16)
                        gen_disp16(&ops[i].e);
#endif
                    else
                        gen_disp32(&ops[i].e);
                } else {
#ifdef I386_ASM_16
                    if (s1->seg_size == 16 && !((o32 == 1) && (v & OP_IM32)))
                        gen_expr16(&ops[i].e);
                    else
#endif
#ifdef TCC_TARGET_X86_64
                    if (v & OP_IM64)
                        gen_expr64(&ops[i].e);
                    else
#endif
                        gen_expr32(&ops[i].e);
                }
            }
#ifdef I386_ASM_16
        } else if (v & (OP_REG16 | OP_REG32)) {
            if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
                /* jmp $r */
                g(0xE0 + ops[i].reg);
            }
#endif
#ifdef TCC_TARGET_X86_64
        } else if (v & (OP_REG32 | OP_REG64)) {
            if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
                /* jmp $r */
                g(0xE0 + ops[i].reg);
            }
#endif
        }
    }
#ifdef I386_ASM_16
    a32 = o32 = 0;
#endif
}

/* 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++;



( run in 1.806 second using v1.01-cache-2.11-cpan-5511b514fd6 )