Support asm goto
this adds generic support for asm goto, but I've tested only on x86.
This commit is contained in:
parent
154c3e7450
commit
98bab41cba
7 changed files with 132 additions and 16 deletions
3
tcc.h
3
tcc.h
|
@ -727,7 +727,7 @@ typedef struct ExprValue {
|
|||
|
||||
#define MAX_ASM_OPERANDS 30
|
||||
typedef struct ASMOperand {
|
||||
int id; /* GCC 3 optional identifier (0 if number only supported */
|
||||
int id; /* GCC 3 optional identifier (0 if number only supported) */
|
||||
char *constraint;
|
||||
char asm_str[16]; /* computed asm string for operand */
|
||||
SValue *vt; /* C value of the expression */
|
||||
|
@ -738,6 +738,7 @@ typedef struct ASMOperand {
|
|||
int is_llong; /* true if double register value */
|
||||
int is_memory; /* true if memory operand */
|
||||
int is_rw; /* for '+' modifier */
|
||||
int is_label; /* for asm goto */
|
||||
} ASMOperand;
|
||||
#endif
|
||||
|
||||
|
|
61
tccasm.c
61
tccasm.c
|
@ -23,12 +23,18 @@
|
|||
#ifdef CONFIG_TCC_ASM
|
||||
|
||||
static Section *last_text_section; /* to handle .previous asm directive */
|
||||
static int asmgoto_n;
|
||||
|
||||
static int asm_get_prefix_name(TCCState *s1, const char *prefix, unsigned int n)
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "%s%u", prefix, n);
|
||||
return tok_alloc_const(buf);
|
||||
}
|
||||
|
||||
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "L..%u", n);
|
||||
return tok_alloc_const(buf);
|
||||
return asm_get_prefix_name(s1, "L..", n);
|
||||
}
|
||||
|
||||
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
|
||||
|
@ -1077,7 +1083,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
|||
modifier = 0;
|
||||
if (*str == 'c' || *str == 'n' ||
|
||||
*str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
|
||||
*str == 'q' ||
|
||||
*str == 'q' || *str == 'l' ||
|
||||
/* P in GCC would add "@PLT" to symbol refs in PIC mode,
|
||||
and make literal operands not be decorated with '$'. */
|
||||
*str == 'P')
|
||||
|
@ -1086,6 +1092,9 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
|||
if (index < 0)
|
||||
tcc_error("invalid operand reference after %%");
|
||||
op = &operands[index];
|
||||
if (modifier == 'l') {
|
||||
cstr_cat(out_str, get_tok_str(op->is_label, NULL), -1);
|
||||
} else {
|
||||
sv = *op->vt;
|
||||
if (op->reg >= 0) {
|
||||
sv.r = op->reg;
|
||||
|
@ -1093,6 +1102,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
|||
sv.r |= VT_LVAL;
|
||||
}
|
||||
subst_asm_operand(out_str, &sv, modifier);
|
||||
}
|
||||
} else {
|
||||
add_char:
|
||||
cstr_ccat(out_str, c);
|
||||
|
@ -1163,18 +1173,20 @@ ST_FUNC void asm_instr(void)
|
|||
{
|
||||
CString astr, astr1;
|
||||
ASMOperand operands[MAX_ASM_OPERANDS];
|
||||
int nb_outputs, nb_operands, i, must_subst, out_reg;
|
||||
int nb_outputs, nb_operands, i, must_subst, out_reg, nb_labels;
|
||||
uint8_t clobber_regs[NB_ASM_REGS];
|
||||
Section *sec;
|
||||
|
||||
/* since we always generate the asm() instruction, we can ignore
|
||||
volatile */
|
||||
if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
|
||||
while (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3
|
||||
|| tok == TOK_GOTO) {
|
||||
next();
|
||||
}
|
||||
parse_asm_str(&astr);
|
||||
nb_operands = 0;
|
||||
nb_outputs = 0;
|
||||
nb_labels = 0;
|
||||
must_subst = 0;
|
||||
memset(clobber_regs, 0, sizeof(clobber_regs));
|
||||
if (tok == ':') {
|
||||
|
@ -1193,6 +1205,8 @@ ST_FUNC void asm_instr(void)
|
|||
/* XXX: handle registers */
|
||||
next();
|
||||
for(;;) {
|
||||
if (tok == ':')
|
||||
break;
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
asm_clobber(clobber_regs, tokc.str.data);
|
||||
|
@ -1204,6 +1218,39 @@ ST_FUNC void asm_instr(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (tok == ':') {
|
||||
/* goto labels */
|
||||
next();
|
||||
for (;;) {
|
||||
Sym *csym;
|
||||
int asmname;
|
||||
if (nb_operands + nb_labels >= MAX_ASM_OPERANDS)
|
||||
tcc_error("too many asm operands");
|
||||
if (tok < TOK_UIDENT)
|
||||
expect("label identifier");
|
||||
operands[nb_operands + nb_labels++].id = tok;
|
||||
|
||||
csym = label_find(tok);
|
||||
if (!csym) {
|
||||
csym = label_push(&global_label_stack, tok,
|
||||
LABEL_FORWARD);
|
||||
} else {
|
||||
if (csym->r == LABEL_DECLARED)
|
||||
csym->r = LABEL_FORWARD;
|
||||
}
|
||||
next();
|
||||
asmname = asm_get_prefix_name(tcc_state, "LG.",
|
||||
++asmgoto_n);
|
||||
if (!csym->c)
|
||||
put_extern_sym2(csym, SHN_UNDEF, 0, 0, 1);
|
||||
get_asm_sym(asmname, csym);
|
||||
operands[nb_operands + nb_labels - 1].is_label = asmname;
|
||||
|
||||
if (tok != ',')
|
||||
break;
|
||||
next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1226,7 +1273,7 @@ ST_FUNC void asm_instr(void)
|
|||
printf("asm: \"%s\"\n", (char *)astr.data);
|
||||
#endif
|
||||
if (must_subst) {
|
||||
subst_asm_operands(operands, nb_operands, &astr1, &astr);
|
||||
subst_asm_operands(operands, nb_operands + nb_labels, &astr1, &astr);
|
||||
cstr_free(&astr);
|
||||
} else {
|
||||
astr1 = astr;
|
||||
|
|
2
tccgen.c
2
tccgen.c
|
@ -5677,7 +5677,7 @@ ST_FUNC void unary(void)
|
|||
if (s->r == LABEL_DECLARED)
|
||||
s->r = LABEL_FORWARD;
|
||||
}
|
||||
if (!s->type.t) {
|
||||
if ((s->type.t & VT_BTYPE) != VT_PTR) {
|
||||
s->type.t = VT_VOID;
|
||||
mk_pointer(&s->type);
|
||||
s->type.t |= VT_STATIC;
|
||||
|
|
2
tccpp.c
2
tccpp.c
|
@ -1434,7 +1434,7 @@ ST_FUNC Sym *label_find(int v)
|
|||
ST_FUNC Sym *label_push(Sym **ptop, int v, int flags)
|
||||
{
|
||||
Sym *s, **ps;
|
||||
s = sym_push2(ptop, v, 0, 0);
|
||||
s = sym_push2(ptop, v, VT_STATIC, 0);
|
||||
s->r = flags;
|
||||
ps = &table_ident[v - TOK_IDENT]->sym_label;
|
||||
if (ptop == &global_label_stack) {
|
||||
|
|
62
tests/tests2/127_asm_goto.c
Normal file
62
tests/tests2/127_asm_goto.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
static int simple_jump(void)
|
||||
{
|
||||
asm goto ("jmp %l[label]" : : : : label);
|
||||
return 0;
|
||||
label:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int three_way_jump(int val, int *addr)
|
||||
{
|
||||
*addr = 42;
|
||||
asm goto ("cmp $0, %1\n\t"
|
||||
"jg %l[larger]\n\t"
|
||||
"jl %l[smaller]\n\t"
|
||||
"incl %0\n\t"
|
||||
: "=m" (*addr)
|
||||
: "r" (val)
|
||||
:
|
||||
: smaller, larger);
|
||||
return 1;
|
||||
smaller:
|
||||
return 2;
|
||||
larger:
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int another_jump(void)
|
||||
{
|
||||
asm goto ("jmp %l[label]" : : : : label);
|
||||
return 70;
|
||||
/* Use the same label name as in simple_jump to check that
|
||||
that doesn't confuse our C/ASM symbol tables */
|
||||
label:
|
||||
return 71;
|
||||
}
|
||||
|
||||
extern int printf (const char *, ...);
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
if (simple_jump () == 1)
|
||||
printf ("simple_jump: okay\n");
|
||||
else
|
||||
printf ("simple_jump: wrong\n");
|
||||
if (another_jump () == 71)
|
||||
printf ("another_jump: okay\n");
|
||||
else
|
||||
printf ("another_jump: wrong\n");
|
||||
if (three_way_jump(0, &i) == 1 && i == 43)
|
||||
printf ("three_way_jump(0): okay\n");
|
||||
else
|
||||
printf ("three_way_jump(0): wrong (i=%d)\n", i);
|
||||
if (three_way_jump(1, &i) == 3 && i == 42)
|
||||
printf ("three_way_jump(1): okay\n");
|
||||
else
|
||||
printf ("three_way_jump(1): wrong (i=%d)\n", i);
|
||||
if (three_way_jump(-1, &i) == 2 && i == 42)
|
||||
printf ("three_way_jump(-1): okay\n");
|
||||
else
|
||||
printf ("three_way_jump(-1): wrong (i=%d)\n", i);
|
||||
return 0;
|
||||
}
|
5
tests/tests2/127_asm_goto.expect
Normal file
5
tests/tests2/127_asm_goto.expect
Normal file
|
@ -0,0 +1,5 @@
|
|||
simple_jump: okay
|
||||
another_jump: okay
|
||||
three_way_jump(0): okay
|
||||
three_way_jump(1): okay
|
||||
three_way_jump(-1): okay
|
|
@ -25,6 +25,7 @@ ifeq (,$(filter i386 x86_64,$(ARCH)))
|
|||
SKIP += 85_asm-outside-function.test # x86 asm
|
||||
SKIP += 124_atomic_counter.test
|
||||
SKIP += 125_atomic_misc.test # currently only x86 supported
|
||||
SKIP += 127_asm_goto.text # hardcodes x86 asm
|
||||
endif
|
||||
ifeq ($(CONFIG_backtrace),no)
|
||||
SKIP += 113_btdll.test
|
||||
|
|
Loading…
Reference in a new issue