Alien-TinyCCx
view release on metacpan or search on metacpan
src/i386-asm.c view on Meta::CPAN
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 == '(') {
int type = 0;
next();
if (tok != ',') {
op->reg = asm_parse_reg(&type);
}
if (tok == ',') {
next();
if (tok != ',') {
op->reg2 = asm_parse_reg(&type);
}
if (tok == ',') {
next();
op->shift = get_reg_shift(s1);
}
}
if (type & OP_EA32)
op->type |= OP_EA32;
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);
}
}
/* generate the modrm operand */
static inline int 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 TCC_TARGET_X86_64
g(0x04 + (reg << 3));
g(0x25);
#else
g(0x05 + (reg << 3));
#endif
gen_expr32(&op->e);
#ifdef TCC_TARGET_X86_64
} else if (op->reg == 8) {
ExprValue *pe = &op->e;
g(0x05 + (reg << 3));
gen_addrpc32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
return ind;
#endif
} 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;
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);
}
/* add offset */
src/i386-asm.c view on Meta::CPAN
} else {
tcc_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) / 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;
}
pc = 0;
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;
}
}
pc = asm_modrm(reg, &ops[modrm_index]);
}
/* emit constants */
#ifndef TCC_TARGET_X86_64
if (pa->opcode == 0x9a || pa->opcode == 0xea) {
/* ljmp or lcall kludge */
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 | OP_IM16)) && ops[i].e.sym)
tcc_error("cannot relocate");
if (v & (OP_IM8 | OP_IM8S)) {
g(ops[i].e.v);
} else if (v & OP_IM16) {
gen_le16(ops[i].e.v);
#ifdef TCC_TARGET_X86_64
} else if (v & OP_IM64) {
gen_expr64(&ops[i].e);
#endif
} else if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
gen_disp32(&ops[i].e);
} else {
gen_expr32(&ops[i].e);
}
}
}
/* after immediate operands, adjust pc-relative address */
if (pc)
add32le(text_section->data + pc - 4, pc - ind);
}
/* 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;
( run in 0.603 second using v1.01-cache-2.11-cpan-71847e10f99 )