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
727727
728728 #define MAX_ASM_OPERANDS 30
729729 typedef 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) */
731731 char *constraint;
732732 char asm_str[16]; /* computed asm string for operand */
733733 SValue *vt; /* C value of the expression */
@@ -738,6 +738,7 @@ typedef struct ASMOperand { · 4 unmodified lines
738738 int is_llong; /* true if double register value */
739739 int is_memory; /* true if memory operand */
740740 int is_rw; /* for '+' modifier */
741+ int is_label; /* for asm goto */
741742 } ASMOperand;
742743 #endif
743744
tccasm.c+59−12
@@ -23,14 +23,20 @@ · 22 unmodified lines
2323 #ifdef CONFIG_TCC_ASM
2424
2525 static Section *last_text_section; /* to handle .previous asm directive */
26+static int asmgoto_n;
2627
27−ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
28+static int asm_get_prefix_name(TCCState *s1, const char *prefix, unsigned int n)
2829 {
2930 char buf[64];
30− snprintf(buf, sizeof(buf), "L..%u", n);
31+ snprintf(buf, sizeof(buf), "%s%u", prefix, n);
3132 return tok_alloc_const(buf);
3233 }
3334
35+ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
36+{
37+ return asm_get_prefix_name(s1, "L..", n);
38+}
39+
3440 static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
3541 static Sym* asm_new_label(TCCState *s1, int label, int is_local);
3642 static 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
10771083 modifier = 0;
10781084 if (*str == 'c' || *str == 'n' ||
10791085 *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
1080− *str == 'q' ||
1086+ *str == 'q' || *str == 'l' ||
10811087 /* P in GCC would add "@PLT" to symbol refs in PIC mode,
10821088 and make literal operands not be decorated with '$'. */
10831089 *str == 'P')
@@ -1086,13 +1092,17 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 2 unmodified lines
10861092 if (index < 0)
10871093 tcc_error("invalid operand reference after %%");
10881094 op = &operands[index];
1089− sv = *op->vt;
1090− if (op->reg >= 0) {
1091− sv.r = op->reg;
1092− if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
1093− sv.r |= VT_LVAL;
1095+ if (modifier == 'l') {
1096+ cstr_cat(out_str, get_tok_str(op->is_label, NULL), -1);
1097+ } else {
1098+ sv = *op->vt;
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);
10941105 }
1095− subst_asm_operand(out_str, &sv, modifier);
10961106 } else {
10971107 add_char:
10981108 cstr_ccat(out_str, c);
@@ -1163,18 +1173,20 @@ ST_FUNC void asm_instr(void) · 64 unmodified lines
11631173 {
11641174 CString astr, astr1;
11651175 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;
11671177 uint8_t clobber_regs[NB_ASM_REGS];
11681178 Section *sec;
11691179
11701180 /* since we always generate the asm() instruction, we can ignore
11711181 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) {
11731184 next();
11741185 }
11751186 parse_asm_str(&astr);
11761187 nb_operands = 0;
11771188 nb_outputs = 0;
1189+ nb_labels = 0;
11781190 must_subst = 0;
11791191 memset(clobber_regs, 0, sizeof(clobber_regs));
11801192 if (tok == ':') {
@@ -1193,6 +1205,8 @@ ST_FUNC void asm_instr(void) · 12 unmodified lines
11931205 /* XXX: handle registers */
11941206 next();
11951207 for(;;) {
1208+ if (tok == ':')
1209+ break;
11961210 if (tok != TOK_STR)
11971211 expect("string constant");
11981212 asm_clobber(clobber_regs, tokc.str.data);
@@ -1204,6 +1218,39 @@ ST_FUNC void asm_instr(void) · 5 unmodified lines
12041218 }
12051219 }
12061220 }
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+ }
12071254 }
12081255 }
12091256 }
@@ -1226,7 +1273,7 @@ ST_FUNC void asm_instr(void) · 16 unmodified lines
12261273 printf("asm: \"%s\"\n", (char *)astr.data);
12271274 #endif
12281275 if (must_subst) {
1229− subst_asm_operands(operands, nb_operands, &astr1, &astr);
1276+ subst_asm_operands(operands, nb_operands + nb_labels, &astr1, &astr);
12301277 cstr_free(&astr);
12311278 } else {
12321279 astr1 = astr;
tccgen.c+1−1
@@ -5677,7 +5677,7 @@ ST_FUNC void unary(void) · 5676 unmodified lines
56775677 if (s->r == LABEL_DECLARED)
56785678 s->r = LABEL_FORWARD;
56795679 }
5680− if (!s->type.t) {
5680+ if ((s->type.t & VT_BTYPE) != VT_PTR) {
56815681 s->type.t = VT_VOID;
56825682 mk_pointer(&s->type);
56835683 s->type.t |= VT_STATIC;
tccpp.c+1−1
@@ -1434,7 +1434,7 @@ ST_FUNC Sym *label_find(int v) · 1433 unmodified lines
14341434 ST_FUNC Sym *label_push(Sym **ptop, int v, int flags)
14351435 {
14361436 Sym *s, **ps;
1437− s = sym_push2(ptop, v, 0, 0);
1437+ s = sym_push2(ptop, v, VT_STATIC, 0);
14381438 s->r = flags;
14391439 ps = &table_ident[v - TOK_IDENT]->sym_label;
14401440 if (ptop == &global_label_stack) {
tests/tests2/127_asm_goto.c+62−0
@@ -0,0 +1,62 @@
1+static int simple_jump(void)
2+{
3+ asm goto ("jmp %l[label]" : : : : label);
4+ return 0;
5+label:
6+ return 1;
7+}
8+
9+static 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;
21+smaller:
22+ return 2;
23+larger:
24+ return 3;
25+}
26+
27+static 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 */
33+label:
34+ return 71;
35+}
36+
37+extern int printf (const char *, ...);
38+int 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 @@
1+simple_jump: okay
2+another_jump: okay
3+three_way_jump(0): okay
4+three_way_jump(1): okay
5+three_way_jump(-1): okay
tests/tests2/Makefile+1−0
@@ -25,6 +25,7 @@ ifeq (,$(filter i386 x86_64,$(ARCH))) · 24 unmodified lines
2525 SKIP += 85_asm-outside-function.test # x86 asm
2626 SKIP += 124_atomic_counter.test
2727 SKIP += 125_atomic_misc.test # currently only x86 supported
28+ SKIP += 127_asm_goto.text # hardcodes x86 asm
2829 endif
2930 ifeq ($(CONFIG_backtrace),no)
3031 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