aboutsummaryrefslogtreecommitdiff
path: root/i386-asm.c
diff options
context:
space:
mode:
authorgrischka <grischka>2016-11-20 14:50:56 +0100
committergrischka <grischka>2016-11-20 14:50:56 +0100
commit4a3741bf02eb51c377312bdabc979e5ccbf5bf89 (patch)
tree11b4469c57da947e9aa7ab60c8063e85b21fc2ab /i386-asm.c
parent47fd807f9b62945600cb15409c46cc70d3b1fa97 (diff)
downloadtinycc-4a3741bf02eb51c377312bdabc979e5ccbf5bf89.tar.gz
tinycc-4a3741bf02eb51c377312bdabc979e5ccbf5bf89.tar.bz2
x86_64-asm: =m operand fixes
The problem was with tcctest.c: unsigned set; __asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc"); when with tcc compiled with the HAVE_SELINUX option, run with tcc -run, it would use large addresses far beyond the 32bits range when tcc did not use the pc-relative mode for accessing 'set' in global data memory. In fact the assembler did not know about %rip at all. Changes: - memory operands use (%rax) not (%eax) - conversion from VT_LLOCAL: use type VT_PTR - support 'k' modifier - support %rip register - support X(%rip) pc-relative addresses The test in tcctest.c is from Michael Matz.
Diffstat (limited to 'i386-asm.c')
-rw-r--r--i386-asm.c75
1 files changed, 48 insertions, 27 deletions
diff --git a/i386-asm.c b/i386-asm.c
index b25bd42..b875aad 100644
--- a/i386-asm.c
+++ b/i386-asm.c
@@ -276,6 +276,8 @@ static int asm_parse_reg(int *type)
*type = OP_EA32;
} else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) {
reg = tok - TOK_ASM_rax;
+ } else if (tok == TOK_ASM_rip) {
+ reg = 8;
#endif
} else {
error_32:
@@ -444,7 +446,7 @@ static void gen_disp32(ExprValue *pe)
}
/* generate the modrm operand */
-static inline void asm_modrm(int reg, Operand *op)
+static inline int asm_modrm(int reg, Operand *op)
{
int mod, reg1, reg2, sib_reg1;
@@ -459,6 +461,13 @@ static inline void asm_modrm(int reg, Operand *op)
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 */
@@ -491,12 +500,13 @@ static inline void asm_modrm(int reg, Operand *op)
gen_expr32(&op->e);
}
}
+ return 0;
}
ST_FUNC void asm_opcode(TCCState *s1, int opcode)
{
const ASMInstr *pa;
- int i, modrm_index, reg, v, op1, seg_prefix;
+ int i, modrm_index, reg, v, op1, seg_prefix, pc;
int nb_ops, s;
Operand ops[MAX_OPERANDS], *pop;
int op_type[3]; /* decoded op type */
@@ -802,6 +812,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
} 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++) {
@@ -828,8 +840,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
break;
}
}
-
- asm_modrm(reg, &ops[modrm_index]);
+ pc = asm_modrm(reg, &ops[modrm_index]);
}
/* emit constants */
@@ -858,30 +869,29 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
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)) {
- 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:
- tcc_error("cannot relocate");
- else
- gen_le16(ops[i].e.v);
- } else {
- if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
- gen_disp32(&ops[i].e);
- } else {
+ gen_le16(ops[i].e.v);
#ifdef TCC_TARGET_X86_64
- if (v & OP_IM64)
- gen_expr64(&ops[i].e);
- else
+ } else if (v & OP_IM64) {
+ gen_expr64(&ops[i].e);
#endif
- gen_expr32(&ops[i].e);
- }
+ } 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)
+ *(int*)(text_section->data + pc - 4) -= ind - pc;
}
/* return the constraint priority (we allocate first the lowest
@@ -1189,17 +1199,20 @@ ST_FUNC void subst_asm_operand(CString *add_str,
cstr_ccat(add_str, '$');
if (r & VT_SYM) {
cstr_cat(add_str, get_tok_str(sv->sym->v, NULL), -1);
- if ((uint32_t)sv->c.i != 0) {
- cstr_ccat(add_str, '+');
- } else {
- return;
- }
+ if ((uint32_t)sv->c.i == 0)
+ goto no_offset;
+ cstr_ccat(add_str, '+');
}
val = sv->c.i;
if (modifier == 'n')
val = -val;
snprintf(buf, sizeof(buf), "%d", (int)sv->c.i);
cstr_cat(add_str, buf, -1);
+ no_offset:;
+#ifdef TCC_TARGET_X86_64
+ if (r & VT_LVAL)
+ cstr_cat(add_str, "(%rip)", -1);
+#endif
} else if ((r & VT_VALMASK) == VT_LOCAL) {
#ifdef TCC_TARGET_X86_64
snprintf(buf, sizeof(buf), "%d(%%rbp)", (int)sv->c.i);
@@ -1212,7 +1225,12 @@ ST_FUNC void subst_asm_operand(CString *add_str,
if (reg >= VT_CONST)
tcc_error("internal compiler error");
snprintf(buf, sizeof(buf), "(%%%s)",
- get_tok_str(TOK_ASM_eax + reg, NULL));
+#ifdef TCC_TARGET_X86_64
+ get_tok_str(TOK_ASM_rax + reg, NULL)
+#else
+ get_tok_str(TOK_ASM_eax + reg, NULL)
+#endif
+ );
cstr_cat(add_str, buf, -1);
} else {
/* register case */
@@ -1244,6 +1262,8 @@ ST_FUNC void subst_asm_operand(CString *add_str,
size = -1;
} else if (modifier == 'w') {
size = 2;
+ } else if (modifier == 'k') {
+ size = 4;
#ifdef TCC_TARGET_X86_64
} else if (modifier == 'q') {
size = 8;
@@ -1311,7 +1331,8 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
output cases) */
SValue sv;
sv = *op->vt;
- sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
+ sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
+ sv.type.t = VT_PTR;
load(op->reg, &sv);
} else if (i >= nb_outputs || op->is_rw) {
/* load value in register */