diff options
| author | grischka <grischka> | 2016-11-20 14:50:56 +0100 |
|---|---|---|
| committer | grischka <grischka> | 2016-11-20 14:50:56 +0100 |
| commit | 4a3741bf02eb51c377312bdabc979e5ccbf5bf89 (patch) | |
| tree | 11b4469c57da947e9aa7ab60c8063e85b21fc2ab /i386-asm.c | |
| parent | 47fd807f9b62945600cb15409c46cc70d3b1fa97 (diff) | |
| download | tinycc-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.c | 75 |
1 files changed, 48 insertions, 27 deletions
@@ -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 */ |
