History

Support asm goto

this adds generic support for asm goto, but I've tested only on x86.

Michael Matz committed 4 years ago

Commit 98bab411 parent 154c3e77 files · +131 −15Browse files

Unified · Split

7 files
  1. tcc.h +2 −1
  2. tccasm.c +59 −12
  3. tccgen.c +1 −1
  4. tccpp.c +1 −1
  5. tests/tests2/127_asm_goto.c +62 −0
  6. tests/tests2/127_asm_goto.expect +5 −0
  7. tests/tests2/Makefile +1 −0
tcc.h+2−1
@@ -727,7 +727,7 @@ typedef struct ExprValue { · 726 unmodified lines
727 727
728#define MAX_ASM_OPERANDS 30728#define MAX_ASM_OPERANDS 30
729typedef struct ASMOperand {729typedef struct ASMOperand {
730 int id; /* GCC 3 optional identifier (0 if number only supported */730 int id; /* GCC 3 optional identifier (0 if number only supported) */
731 char *constraint;731 char *constraint;
732 char asm_str[16]; /* computed asm string for operand */732 char asm_str[16]; /* computed asm string for operand */
733 SValue *vt; /* C value of the expression */733 SValue *vt; /* C value of the expression */
@@ -738,6 +738,7 @@ typedef struct ASMOperand { · 4 unmodified lines
738 int is_llong; /* true if double register value */738 int is_llong; /* true if double register value */
739 int is_memory; /* true if memory operand */739 int is_memory; /* true if memory operand */
740 int is_rw; /* for '+' modifier */740 int is_rw; /* for '+' modifier */
741 int is_label; /* for asm goto */
741} ASMOperand;742} ASMOperand;
742#endif743#endif
743 744
tccasm.c+59−12
@@ -23,14 +23,20 @@ · 22 unmodified lines
23#ifdef CONFIG_TCC_ASM23#ifdef CONFIG_TCC_ASM
24 24
25static Section *last_text_section; /* to handle .previous asm directive */25static Section *last_text_section; /* to handle .previous asm directive */
26static int asmgoto_n;
26 27
27ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)28static int asm_get_prefix_name(TCCState *s1, const char *prefix, unsigned int n)
28{29{
29 char buf[64];30 char buf[64];
30 snprintf(buf, sizeof(buf), "L..%u", n);31 snprintf(buf, sizeof(buf), "%s%u", prefix, n);
31 return tok_alloc_const(buf);32 return tok_alloc_const(buf);
32}33}
33 34
35ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
36{
37 return asm_get_prefix_name(s1, "L..", n);
38}
39
34static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);40static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
35static Sym* asm_new_label(TCCState *s1, int label, int is_local);41static Sym* asm_new_label(TCCState *s1, int label, int is_local);
36static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value);42static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value);
@@ -1077,7 +1083,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 1040 unmodified lines
1077 modifier = 0;1083 modifier = 0;
1078 if (*str == 'c' || *str == 'n' ||1084 if (*str == 'c' || *str == 'n' ||
1079 *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||1085 *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
1080 *str == 'q' ||1086 *str == 'q' || *str == 'l' ||
1081 /* P in GCC would add "@PLT" to symbol refs in PIC mode,1087 /* P in GCC would add "@PLT" to symbol refs in PIC mode,
1082 and make literal operands not be decorated with '$'. */1088 and make literal operands not be decorated with '$'. */
1083 *str == 'P')1089 *str == 'P')
@@ -1086,13 +1092,17 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 2 unmodified lines
1086 if (index < 0)1092 if (index < 0)
1087 tcc_error("invalid operand reference after %%");1093 tcc_error("invalid operand reference after %%");
1088 op = &operands[index];1094 op = &operands[index];
1089 sv = *op->vt;1095 if (modifier == 'l') {
1090 if (op->reg >= 0) {1096 cstr_cat(out_str, get_tok_str(op->is_label, NULL), -1);
1091 sv.r = op->reg;1097 } else {
1092 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)1098 sv = *op->vt;
1093 sv.r |= VT_LVAL;1099 if (op->reg >= 0) {
1100 sv.r = op->reg;
1101 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
1102 sv.r |= VT_LVAL;
1103 }
1104 subst_asm_operand(out_str, &sv, modifier);
1094 }1105 }
1095 subst_asm_operand(out_str, &sv, modifier);
1096 } else {1106 } else {
1097 add_char:1107 add_char:
1098 cstr_ccat(out_str, c);1108 cstr_ccat(out_str, c);
@@ -1163,18 +1173,20 @@ ST_FUNC void asm_instr(void) · 64 unmodified lines
1163{1173{
1164 CString astr, astr1;1174 CString astr, astr1;
1165 ASMOperand operands[MAX_ASM_OPERANDS];1175 ASMOperand operands[MAX_ASM_OPERANDS];
1166 int nb_outputs, nb_operands, i, must_subst, out_reg;1176 int nb_outputs, nb_operands, i, must_subst, out_reg, nb_labels;
1167 uint8_t clobber_regs[NB_ASM_REGS];1177 uint8_t clobber_regs[NB_ASM_REGS];
1168 Section *sec;1178 Section *sec;
1169 1179
1170 /* since we always generate the asm() instruction, we can ignore1180 /* since we always generate the asm() instruction, we can ignore
1171 volatile */1181 volatile */
1172 if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {1182 while (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3
1183 || tok == TOK_GOTO) {
1173 next();1184 next();
1174 }1185 }
1175 parse_asm_str(&astr);1186 parse_asm_str(&astr);
1176 nb_operands = 0;1187 nb_operands = 0;
1177 nb_outputs = 0;1188 nb_outputs = 0;
1189 nb_labels = 0;
1178 must_subst = 0;1190 must_subst = 0;
1179 memset(clobber_regs, 0, sizeof(clobber_regs));1191 memset(clobber_regs, 0, sizeof(clobber_regs));
1180 if (tok == ':') {1192 if (tok == ':') {
@@ -1193,6 +1205,8 @@ ST_FUNC void asm_instr(void) · 12 unmodified lines
1193 /* XXX: handle registers */1205 /* XXX: handle registers */
1194 next();1206 next();
1195 for(;;) {1207 for(;;) {
1208 if (tok == ':')
1209 break;
1196 if (tok != TOK_STR)1210 if (tok != TOK_STR)
1197 expect("string constant");1211 expect("string constant");
1198 asm_clobber(clobber_regs, tokc.str.data);1212 asm_clobber(clobber_regs, tokc.str.data);
@@ -1204,6 +1218,39 @@ ST_FUNC void asm_instr(void) · 5 unmodified lines
1204 }1218 }
1205 }1219 }
1206 }1220 }
1221 if (tok == ':') {
1222 /* goto labels */
1223 next();
1224 for (;;) {
1225 Sym *csym;
1226 int asmname;
1227 if (nb_operands + nb_labels >= MAX_ASM_OPERANDS)
1228 tcc_error("too many asm operands");
1229 if (tok < TOK_UIDENT)
1230 expect("label identifier");
1231 operands[nb_operands + nb_labels++].id = tok;
1232
1233 csym = label_find(tok);
1234 if (!csym) {
1235 csym = label_push(&global_label_stack, tok,
1236 LABEL_FORWARD);
1237 } else {
1238 if (csym->r == LABEL_DECLARED)
1239 csym->r = LABEL_FORWARD;
1240 }
1241 next();
1242 asmname = asm_get_prefix_name(tcc_state, "LG.",
1243 ++asmgoto_n);
1244 if (!csym->c)
1245 put_extern_sym2(csym, SHN_UNDEF, 0, 0, 1);
1246 get_asm_sym(asmname, csym);
1247 operands[nb_operands + nb_labels - 1].is_label = asmname;
1248
1249 if (tok != ',')
1250 break;
1251 next();
1252 }
1253 }
1207 }1254 }
1208 }1255 }
1209 }1256 }
@@ -1226,7 +1273,7 @@ ST_FUNC void asm_instr(void) · 16 unmodified lines
1226 printf("asm: \"%s\"\n", (char *)astr.data);1273 printf("asm: \"%s\"\n", (char *)astr.data);
1227#endif1274#endif
1228 if (must_subst) {1275 if (must_subst) {
1229 subst_asm_operands(operands, nb_operands, &astr1, &astr);1276 subst_asm_operands(operands, nb_operands + nb_labels, &astr1, &astr);
1230 cstr_free(&astr);1277 cstr_free(&astr);
1231 } else {1278 } else {
1232 astr1 = astr;1279 astr1 = astr;
tccgen.c+1−1
@@ -5677,7 +5677,7 @@ ST_FUNC void unary(void) · 5676 unmodified lines
5677 if (s->r == LABEL_DECLARED)5677 if (s->r == LABEL_DECLARED)
5678 s->r = LABEL_FORWARD;5678 s->r = LABEL_FORWARD;
5679 }5679 }
5680 if (!s->type.t) {5680 if ((s->type.t & VT_BTYPE) != VT_PTR) {
5681 s->type.t = VT_VOID;5681 s->type.t = VT_VOID;
5682 mk_pointer(&s->type);5682 mk_pointer(&s->type);
5683 s->type.t |= VT_STATIC;5683 s->type.t |= VT_STATIC;
tccpp.c+1−1
@@ -1434,7 +1434,7 @@ ST_FUNC Sym *label_find(int v) · 1433 unmodified lines
1434ST_FUNC Sym *label_push(Sym **ptop, int v, int flags)1434ST_FUNC Sym *label_push(Sym **ptop, int v, int flags)
1435{1435{
1436 Sym *s, **ps;1436 Sym *s, **ps;
1437 s = sym_push2(ptop, v, 0, 0);1437 s = sym_push2(ptop, v, VT_STATIC, 0);
1438 s->r = flags;1438 s->r = flags;
1439 ps = &table_ident[v - TOK_IDENT]->sym_label;1439 ps = &table_ident[v - TOK_IDENT]->sym_label;
1440 if (ptop == &global_label_stack) {1440 if (ptop == &global_label_stack) {
tests/tests2/127_asm_goto.c+62−0
@@ -0,0 +1,62 @@
1static int simple_jump(void)
2{
3 asm goto ("jmp %l[label]" : : : : label);
4 return 0;
5label:
6 return 1;
7}
8
9static int three_way_jump(int val, int *addr)
10{
11 *addr = 42;
12 asm goto ("cmp $0, %1\n\t"
13 "jg %l[larger]\n\t"
14 "jl %l[smaller]\n\t"
15 "incl %0\n\t"
16 : "=m" (*addr)
17 : "r" (val)
18 :
19 : smaller, larger);
20 return 1;
21smaller:
22 return 2;
23larger:
24 return 3;
25}
26
27static int another_jump(void)
28{
29 asm goto ("jmp %l[label]" : : : : label);
30 return 70;
31 /* Use the same label name as in simple_jump to check that
32 that doesn't confuse our C/ASM symbol tables */
33label:
34 return 71;
35}
36
37extern int printf (const char *, ...);
38int main(void)
39{
40 int i;
41 if (simple_jump () == 1)
42 printf ("simple_jump: okay\n");
43 else
44 printf ("simple_jump: wrong\n");
45 if (another_jump () == 71)
46 printf ("another_jump: okay\n");
47 else
48 printf ("another_jump: wrong\n");
49 if (three_way_jump(0, &i) == 1 && i == 43)
50 printf ("three_way_jump(0): okay\n");
51 else
52 printf ("three_way_jump(0): wrong (i=%d)\n", i);
53 if (three_way_jump(1, &i) == 3 && i == 42)
54 printf ("three_way_jump(1): okay\n");
55 else
56 printf ("three_way_jump(1): wrong (i=%d)\n", i);
57 if (three_way_jump(-1, &i) == 2 && i == 42)
58 printf ("three_way_jump(-1): okay\n");
59 else
60 printf ("three_way_jump(-1): wrong (i=%d)\n", i);
61 return 0;
62}
tests/tests2/127_asm_goto.expect+5−0
@@ -0,0 +1,5 @@
1simple_jump: okay
2another_jump: okay
3three_way_jump(0): okay
4three_way_jump(1): okay
5three_way_jump(-1): okay
tests/tests2/Makefile+1−0
@@ -25,6 +25,7 @@ ifeq (,$(filter i386 x86_64,$(ARCH))) · 24 unmodified lines
25 SKIP += 85_asm-outside-function.test # x86 asm25 SKIP += 85_asm-outside-function.test # x86 asm
26 SKIP += 124_atomic_counter.test26 SKIP += 124_atomic_counter.test
27 SKIP += 125_atomic_misc.test # currently only x86 supported27 SKIP += 125_atomic_misc.test # currently only x86 supported
28 SKIP += 127_asm_goto.text # hardcodes x86 asm
28endif29endif
29ifeq ($(CONFIG_backtrace),no)30ifeq ($(CONFIG_backtrace),no)
30 SKIP += 113_btdll.test31 SKIP += 113_btdll.test

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