mirror of
https://github.com/frida/tinycc
synced 2025-02-08 19:34:04 +03:00
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.
This commit is contained in:
parent
47fd807f9b
commit
4a3741bf02
2
Makefile
2
Makefile
@ -176,7 +176,7 @@ $(ARM64_CROSS): $(ARM64_FILES)
|
|||||||
# libtcc generation and test
|
# libtcc generation and test
|
||||||
ifndef ONE_SOURCE
|
ifndef ONE_SOURCE
|
||||||
LIBTCC_OBJ = $(filter-out tcc.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES))))
|
LIBTCC_OBJ = $(filter-out tcc.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES))))
|
||||||
LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES),$(NATIVE_FILES))
|
LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES) i386-asm.c,$(NATIVE_FILES))
|
||||||
else
|
else
|
||||||
LIBTCC_OBJ = libtcc.o
|
LIBTCC_OBJ = libtcc.o
|
||||||
LIBTCC_INC = $(NATIVE_FILES)
|
LIBTCC_INC = $(NATIVE_FILES)
|
||||||
|
69
i386-asm.c
69
i386-asm.c
@ -276,6 +276,8 @@ static int asm_parse_reg(int *type)
|
|||||||
*type = OP_EA32;
|
*type = OP_EA32;
|
||||||
} else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) {
|
} else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) {
|
||||||
reg = tok - TOK_ASM_rax;
|
reg = tok - TOK_ASM_rax;
|
||||||
|
} else if (tok == TOK_ASM_rip) {
|
||||||
|
reg = 8;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
error_32:
|
error_32:
|
||||||
@ -444,7 +446,7 @@ static void gen_disp32(ExprValue *pe)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* generate the modrm operand */
|
/* 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;
|
int mod, reg1, reg2, sib_reg1;
|
||||||
|
|
||||||
@ -459,6 +461,13 @@ static inline void asm_modrm(int reg, Operand *op)
|
|||||||
g(0x05 + (reg << 3));
|
g(0x05 + (reg << 3));
|
||||||
#endif
|
#endif
|
||||||
gen_expr32(&op->e);
|
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 {
|
} else {
|
||||||
sib_reg1 = op->reg;
|
sib_reg1 = op->reg;
|
||||||
/* fist compute displacement encoding */
|
/* fist compute displacement encoding */
|
||||||
@ -491,12 +500,13 @@ static inline void asm_modrm(int reg, Operand *op)
|
|||||||
gen_expr32(&op->e);
|
gen_expr32(&op->e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
||||||
{
|
{
|
||||||
const ASMInstr *pa;
|
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;
|
int nb_ops, s;
|
||||||
Operand ops[MAX_OPERANDS], *pop;
|
Operand ops[MAX_OPERANDS], *pop;
|
||||||
int op_type[3]; /* decoded op type */
|
int op_type[3]; /* decoded op type */
|
||||||
@ -802,6 +812,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
|||||||
} else {
|
} else {
|
||||||
reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7;
|
reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pc = 0;
|
||||||
if (pa->instr_type & OPC_MODRM) {
|
if (pa->instr_type & OPC_MODRM) {
|
||||||
/* first look for an ea operand */
|
/* first look for an ea operand */
|
||||||
for(i = 0;i < nb_ops; i++) {
|
for(i = 0;i < nb_ops; i++) {
|
||||||
@ -828,8 +840,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pc = asm_modrm(reg, &ops[modrm_index]);
|
||||||
asm_modrm(reg, &ops[modrm_index]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* emit constants */
|
/* emit constants */
|
||||||
@ -858,30 +869,29 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
|||||||
else
|
else
|
||||||
v = OP_IM64;
|
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 (v & (OP_IM8 | OP_IM8S)) {
|
||||||
if (ops[i].e.sym)
|
|
||||||
goto error_relocate;
|
|
||||||
g(ops[i].e.v);
|
g(ops[i].e.v);
|
||||||
} else if (v & OP_IM16) {
|
} else if (v & OP_IM16) {
|
||||||
if (ops[i].e.sym)
|
|
||||||
error_relocate:
|
|
||||||
tcc_error("cannot relocate");
|
|
||||||
else
|
|
||||||
gen_le16(ops[i].e.v);
|
gen_le16(ops[i].e.v);
|
||||||
} else {
|
#ifdef TCC_TARGET_X86_64
|
||||||
if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
|
} 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);
|
gen_disp32(&ops[i].e);
|
||||||
} else {
|
} else {
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
if (v & OP_IM64)
|
|
||||||
gen_expr64(&ops[i].e);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
gen_expr32(&ops[i].e);
|
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
|
/* 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, '$');
|
cstr_ccat(add_str, '$');
|
||||||
if (r & VT_SYM) {
|
if (r & VT_SYM) {
|
||||||
cstr_cat(add_str, get_tok_str(sv->sym->v, NULL), -1);
|
cstr_cat(add_str, get_tok_str(sv->sym->v, NULL), -1);
|
||||||
if ((uint32_t)sv->c.i != 0) {
|
if ((uint32_t)sv->c.i == 0)
|
||||||
|
goto no_offset;
|
||||||
cstr_ccat(add_str, '+');
|
cstr_ccat(add_str, '+');
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val = sv->c.i;
|
val = sv->c.i;
|
||||||
if (modifier == 'n')
|
if (modifier == 'n')
|
||||||
val = -val;
|
val = -val;
|
||||||
snprintf(buf, sizeof(buf), "%d", (int)sv->c.i);
|
snprintf(buf, sizeof(buf), "%d", (int)sv->c.i);
|
||||||
cstr_cat(add_str, buf, -1);
|
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) {
|
} else if ((r & VT_VALMASK) == VT_LOCAL) {
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
snprintf(buf, sizeof(buf), "%d(%%rbp)", (int)sv->c.i);
|
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)
|
if (reg >= VT_CONST)
|
||||||
tcc_error("internal compiler error");
|
tcc_error("internal compiler error");
|
||||||
snprintf(buf, sizeof(buf), "(%%%s)",
|
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);
|
cstr_cat(add_str, buf, -1);
|
||||||
} else {
|
} else {
|
||||||
/* register case */
|
/* register case */
|
||||||
@ -1244,6 +1262,8 @@ ST_FUNC void subst_asm_operand(CString *add_str,
|
|||||||
size = -1;
|
size = -1;
|
||||||
} else if (modifier == 'w') {
|
} else if (modifier == 'w') {
|
||||||
size = 2;
|
size = 2;
|
||||||
|
} else if (modifier == 'k') {
|
||||||
|
size = 4;
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
} else if (modifier == 'q') {
|
} else if (modifier == 'q') {
|
||||||
size = 8;
|
size = 8;
|
||||||
@ -1311,7 +1331,8 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
|||||||
output cases) */
|
output cases) */
|
||||||
SValue sv;
|
SValue sv;
|
||||||
sv = *op->vt;
|
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);
|
load(op->reg, &sv);
|
||||||
} else if (i >= nb_outputs || op->is_rw) {
|
} else if (i >= nb_outputs || op->is_rw) {
|
||||||
/* load value in register */
|
/* load value in register */
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
DEF_ASM(rbp)
|
DEF_ASM(rbp)
|
||||||
DEF_ASM(rsi)
|
DEF_ASM(rsi)
|
||||||
DEF_ASM(rdi)
|
DEF_ASM(rdi)
|
||||||
|
DEF_ASM(rip)
|
||||||
#endif
|
#endif
|
||||||
DEF_ASM(mm0)
|
DEF_ASM(mm0)
|
||||||
DEF_ASM(mm1)
|
DEF_ASM(mm1)
|
||||||
|
4
tccasm.c
4
tccasm.c
@ -977,7 +977,8 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
|||||||
}
|
}
|
||||||
modifier = 0;
|
modifier = 0;
|
||||||
if (*str == 'c' || *str == 'n' ||
|
if (*str == 'c' || *str == 'n' ||
|
||||||
*str == 'b' || *str == 'w' || *str == 'h')
|
*str == 'b' || *str == 'w' ||
|
||||||
|
*str == 'h' || *str == 'k')
|
||||||
modifier = *str++;
|
modifier = *str++;
|
||||||
index = find_constraint(operands, nb_operands, str, &str);
|
index = find_constraint(operands, nb_operands, str, &str);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
@ -1029,6 +1030,7 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
|
|||||||
skip('(');
|
skip('(');
|
||||||
gexpr();
|
gexpr();
|
||||||
if (is_output) {
|
if (is_output) {
|
||||||
|
if (!(vtop->type.t & VT_ARRAY))
|
||||||
test_lvalue();
|
test_lvalue();
|
||||||
} else {
|
} else {
|
||||||
/* we want to avoid LLOCAL case, except when the 'm'
|
/* we want to avoid LLOCAL case, except when the 'm'
|
||||||
|
2
tccrun.c
2
tccrun.c
@ -52,6 +52,8 @@ static void *win64_add_function_table(TCCState *s1);
|
|||||||
static void win64_del_function_table(void *);
|
static void win64_del_function_table(void *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// #define HAVE_SELINUX
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/* Do all relocations (needed before using tcc_get_symbol())
|
/* Do all relocations (needed before using tcc_get_symbol())
|
||||||
Returns -1 on error. */
|
Returns -1 on error. */
|
||||||
|
@ -2565,12 +2565,33 @@ static __inline__ unsigned long long inc64(unsigned long long a)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct struct123 {
|
||||||
|
int a;
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
struct struct1231 {
|
||||||
|
unsigned long addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned long mconstraint_test(struct struct1231 *r)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
unsigned int a[2];
|
||||||
|
a[0] = 0;
|
||||||
|
__asm__ volatile ("lea %2,%0; movl 4(%0),%k0; addl %2,%k0; movl $51,%2; movl $52,4%2; movl $63,%1"
|
||||||
|
: "=&r" (ret), "=m" (a)
|
||||||
|
: "m" (*(struct struct123 *)r->addr));
|
||||||
|
return ret + a[0];
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int set;
|
unsigned int set;
|
||||||
|
|
||||||
void asm_test(void)
|
void asm_test(void)
|
||||||
{
|
{
|
||||||
char buf[128];
|
char buf[128];
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
|
struct struct123 s1;
|
||||||
|
struct struct1231 s2 = { (unsigned long)&s1 };
|
||||||
|
|
||||||
printf("inline asm:\n");
|
printf("inline asm:\n");
|
||||||
|
|
||||||
@ -2592,6 +2613,10 @@ void asm_test(void)
|
|||||||
printf("mul64=0x%Lx\n", mul64(0x12345678, 0xabcd1234));
|
printf("mul64=0x%Lx\n", mul64(0x12345678, 0xabcd1234));
|
||||||
printf("inc64=0x%Lx\n", inc64(0x12345678ffffffff));
|
printf("inc64=0x%Lx\n", inc64(0x12345678ffffffff));
|
||||||
|
|
||||||
|
s1.a = 42;
|
||||||
|
s1.b = 43;
|
||||||
|
printf("mconstraint: %d", mconstraint_test(&s2));
|
||||||
|
printf(" %d %d\n", s1.a, s1.b);
|
||||||
set = 0xff;
|
set = 0xff;
|
||||||
sigdelset1(&set, 2);
|
sigdelset1(&set, 2);
|
||||||
sigaddset1(&set, 16);
|
sigaddset1(&set, 16);
|
||||||
@ -2600,9 +2625,6 @@ void asm_test(void)
|
|||||||
goto label1;
|
goto label1;
|
||||||
label2:
|
label2:
|
||||||
__asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc");
|
__asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc");
|
||||||
#ifdef __GNUC__ // works strange with GCC 4.3
|
|
||||||
set=0x1080fd;
|
|
||||||
#endif
|
|
||||||
printf("set=0x%x\n", set);
|
printf("set=0x%x\n", set);
|
||||||
val = 0x01020304;
|
val = 0x01020304;
|
||||||
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));
|
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user