History

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.

grischka committed 9 years ago

Commit 4a3741b1 parent 47fd8076 files · +81 −33Browse files

Unified · Split

6 files
  1. Makefile +1 −1
  2. i386-asm.c +48 −27
  3. i386-tok.h +1 −0
  4. tccasm.c +4 −2
  5. tccrun.c +2 −0
  6. tests/tcctest.c +25 −3
Makefile+1−1
@@ -176,7 +176,7 @@ $(ARM64_CROSS): $(ARM64_FILES) · 175 unmodified lines
176176 # libtcc generation and test
177177 ifndef ONE_SOURCE
178178 LIBTCC_OBJ = $(filter-out tcc.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES))))
179−LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES),$(NATIVE_FILES))
179+LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES) i386-asm.c,$(NATIVE_FILES))
180180 else
181181 LIBTCC_OBJ = libtcc.o
182182 LIBTCC_INC = $(NATIVE_FILES)
i386-asm.c+48−27
@@ -276,6 +276,8 @@ static int asm_parse_reg(int *type) · 275 unmodified lines
276276 *type = OP_EA32;
277277 } else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) {
278278 reg = tok - TOK_ASM_rax;
279+ } else if (tok == TOK_ASM_rip) {
280+ reg = 8;
279281 #endif
280282 } else {
281283 error_32:
@@ -444,7 +446,7 @@ static void gen_disp32(ExprValue *pe) · 162 unmodified lines
444446 }
445447
446448 /* generate the modrm operand */
447−static inline void asm_modrm(int reg, Operand *op)
449+static inline int asm_modrm(int reg, Operand *op)
448450 {
449451 int mod, reg1, reg2, sib_reg1;
450452
@@ -459,6 +461,13 @@ static inline void asm_modrm(int reg, Operand *op) · 8 unmodified lines
459461 g(0x05 + (reg << 3));
460462 #endif
461463 gen_expr32(&op->e);
464+#ifdef TCC_TARGET_X86_64
465+ } else if (op->reg == 8) {
466+ ExprValue *pe = &op->e;
467+ g(0x05 + (reg << 3));
468+ gen_addrpc32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
469+ return ind;
470+#endif
462471 } else {
463472 sib_reg1 = op->reg;
464473 /* fist compute displacement encoding */
@@ -491,12 +500,13 @@ static inline void asm_modrm(int reg, Operand *op) · 26 unmodified lines
491500 gen_expr32(&op->e);
492501 }
493502 }
503+ return 0;
494504 }
495505
496506 ST_FUNC void asm_opcode(TCCState *s1, int opcode)
497507 {
498508 const ASMInstr *pa;
499− int i, modrm_index, reg, v, op1, seg_prefix;
509+ int i, modrm_index, reg, v, op1, seg_prefix, pc;
500510 int nb_ops, s;
501511 Operand ops[MAX_OPERANDS], *pop;
502512 int op_type[3]; /* decoded op type */
@@ -802,6 +812,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 299 unmodified lines
802812 } else {
803813 reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7;
804814 }
815+
816+ pc = 0;
805817 if (pa->instr_type & OPC_MODRM) {
806818 /* first look for an ea operand */
807819 for(i = 0;i < nb_ops; i++) {
@@ -828,8 +840,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 20 unmodified lines
828840 break;
829841 }
830842 }
831−
832− asm_modrm(reg, &ops[modrm_index]);
843+ pc = asm_modrm(reg, &ops[modrm_index]);
833844 }
834845
835846 /* emit constants */
@@ -858,30 +869,29 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 22 unmodified lines
858869 else
859870 v = OP_IM64;
860871 }
872+
873+ if ((v & (OP_IM8 | OP_IM8S | OP_IM16)) && ops[i].e.sym)
874+ tcc_error("cannot relocate");
875+
861876 if (v & (OP_IM8 | OP_IM8S)) {
862− if (ops[i].e.sym)
863− goto error_relocate;
864877 g(ops[i].e.v);
865878 } else if (v & OP_IM16) {
866− if (ops[i].e.sym)
867− error_relocate:
868− tcc_error("cannot relocate");
869− else
870− gen_le16(ops[i].e.v);
871− } else {
872− if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
873− gen_disp32(&ops[i].e);
874− } else {
879+ gen_le16(ops[i].e.v);
875880 #ifdef TCC_TARGET_X86_64
876− if (v & OP_IM64)
877− gen_expr64(&ops[i].e);
878− else
881+ } else if (v & OP_IM64) {
882+ gen_expr64(&ops[i].e);
879883 #endif
880− gen_expr32(&ops[i].e);
881− }
884+ } else if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
885+ gen_disp32(&ops[i].e);
886+ } else {
887+ gen_expr32(&ops[i].e);
882888 }
883889 }
884890 }
891+
892+ /* after immediate operands, adjust pc-relative address */
893+ if (pc)
894+ *(int*)(text_section->data + pc - 4) -= ind - pc;
885895 }
886896
887897 /* return the constraint priority (we allocate first the lowest
@@ -1189,17 +1199,20 @@ ST_FUNC void subst_asm_operand(CString *add_str, · 301 unmodified lines
11891199 cstr_ccat(add_str, '$');
11901200 if (r & VT_SYM) {
11911201 cstr_cat(add_str, get_tok_str(sv->sym->v, NULL), -1);
1192− if ((uint32_t)sv->c.i != 0) {
1193− cstr_ccat(add_str, '+');
1194− } else {
1195− return;
1196− }
1202+ if ((uint32_t)sv->c.i == 0)
1203+ goto no_offset;
1204+ cstr_ccat(add_str, '+');
11971205 }
11981206 val = sv->c.i;
11991207 if (modifier == 'n')
12001208 val = -val;
12011209 snprintf(buf, sizeof(buf), "%d", (int)sv->c.i);
12021210 cstr_cat(add_str, buf, -1);
1211+ no_offset:;
1212+#ifdef TCC_TARGET_X86_64
1213+ if (r & VT_LVAL)
1214+ cstr_cat(add_str, "(%rip)", -1);
1215+#endif
12031216 } else if ((r & VT_VALMASK) == VT_LOCAL) {
12041217 #ifdef TCC_TARGET_X86_64
12051218 snprintf(buf, sizeof(buf), "%d(%%rbp)", (int)sv->c.i);
@@ -1212,7 +1225,12 @@ ST_FUNC void subst_asm_operand(CString *add_str, · 6 unmodified lines
12121225 if (reg >= VT_CONST)
12131226 tcc_error("internal compiler error");
12141227 snprintf(buf, sizeof(buf), "(%%%s)",
1215− get_tok_str(TOK_ASM_eax + reg, NULL));
1228+#ifdef TCC_TARGET_X86_64
1229+ get_tok_str(TOK_ASM_rax + reg, NULL)
1230+#else
1231+ get_tok_str(TOK_ASM_eax + reg, NULL)
1232+#endif
1233+ );
12161234 cstr_cat(add_str, buf, -1);
12171235 } else {
12181236 /* register case */
@@ -1244,6 +1262,8 @@ ST_FUNC void subst_asm_operand(CString *add_str, · 25 unmodified lines
12441262 size = -1;
12451263 } else if (modifier == 'w') {
12461264 size = 2;
1265+ } else if (modifier == 'k') {
1266+ size = 4;
12471267 #ifdef TCC_TARGET_X86_64
12481268 } else if (modifier == 'q') {
12491269 size = 8;
@@ -1311,7 +1331,8 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, · 61 unmodified lines
13111331 output cases) */
13121332 SValue sv;
13131333 sv = *op->vt;
1314− sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
1334+ sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
1335+ sv.type.t = VT_PTR;
13151336 load(op->reg, &sv);
13161337 } else if (i >= nb_outputs || op->is_rw) {
13171338 /* load value in register */
i386-tok.h+1−0
@@ -35,6 +35,7 @@ · 34 unmodified lines
3535 DEF_ASM(rbp)
3636 DEF_ASM(rsi)
3737 DEF_ASM(rdi)
38+ DEF_ASM(rip)
3839 #endif
3940 DEF_ASM(mm0)
4041 DEF_ASM(mm1)
tccasm.c+4−2
@@ -977,7 +977,8 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 976 unmodified lines
977977 }
978978 modifier = 0;
979979 if (*str == 'c' || *str == 'n' ||
980− *str == 'b' || *str == 'w' || *str == 'h')
980+ *str == 'b' || *str == 'w' ||
981+ *str == 'h' || *str == 'k')
981982 modifier = *str++;
982983 index = find_constraint(operands, nb_operands, str, &str);
983984 if (index < 0)
@@ -1029,7 +1030,8 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr, · 45 unmodified lines
10291030 skip('(');
10301031 gexpr();
10311032 if (is_output) {
1032− test_lvalue();
1033+ if (!(vtop->type.t & VT_ARRAY))
1034+ test_lvalue();
10331035 } else {
10341036 /* we want to avoid LLOCAL case, except when the 'm'
10351037 constraint is used. Note that it may come from
tccrun.c+2−0
@@ -52,6 +52,8 @@ static void *win64_add_function_table(TCCState *s1); · 51 unmodified lines
5252 static void win64_del_function_table(void *);
5353 #endif
5454
55+// #define HAVE_SELINUX
56+
5557 /* ------------------------------------------------------------- */
5658 /* Do all relocations (needed before using tcc_get_symbol())
5759 Returns -1 on error. */
tests/tcctest.c+25−3
@@ -2565,12 +2565,33 @@ static __inline__ unsigned long long inc64(unsigned long long a) · 2564 unmodified lines
25652565 return res;
25662566 }
25672567
2568+struct struct123 {
2569+ int a;
2570+ int b;
2571+};
2572+struct struct1231 {
2573+ unsigned long addr;
2574+};
2575+
2576+unsigned long mconstraint_test(struct struct1231 *r)
2577+{
2578+ unsigned long ret;
2579+ unsigned int a[2];
2580+ a[0] = 0;
2581+ __asm__ volatile ("lea %2,%0; movl 4(%0),%k0; addl %2,%k0; movl $51,%2; movl $52,4%2; movl $63,%1"
2582+ : "=&r" (ret), "=m" (a)
2583+ : "m" (*(struct struct123 *)r->addr));
2584+ return ret + a[0];
2585+}
2586+
25682587 unsigned int set;
25692588
25702589 void asm_test(void)
25712590 {
25722591 char buf[128];
25732592 unsigned int val;
2593+ struct struct123 s1;
2594+ struct struct1231 s2 = { (unsigned long)&s1 };
25742595
25752596 printf("inline asm:\n");
25762597
@@ -2592,6 +2613,10 @@ void asm_test(void) · 15 unmodified lines
25922613 printf("mul64=0x%Lx\n", mul64(0x12345678, 0xabcd1234));
25932614 printf("inc64=0x%Lx\n", inc64(0x12345678ffffffff));
25942615
2616+ s1.a = 42;
2617+ s1.b = 43;
2618+ printf("mconstraint: %d", mconstraint_test(&s2));
2619+ printf(" %d %d\n", s1.a, s1.b);
25952620 set = 0xff;
25962621 sigdelset1(&set, 2);
25972622 sigaddset1(&set, 16);
@@ -2600,9 +2625,6 @@ void asm_test(void) · 2 unmodified lines
26002625 goto label1;
26012626 label2:
26022627 __asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc");
2603−#ifdef __GNUC__ // works strange with GCC 4.3
2604− set=0x1080fd;
2605−#endif
26062628 printf("set=0x%x\n", set);
26072629 val = 0x01020304;
26082630 printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t