tccasm: Implement .set sym, expr

That, as well as "sym = expr", if expr contains symbols.
Slightly tricky because a definition from .set is overridable,
whereas proper definitions aren't.

This doesn't yet allow using this for override tricks from C
and global asm blocks because the symbol tables from C and asm
are separate.
This commit is contained in:
Michael Matz 2016-08-07 04:27:32 +02:00
parent 34fc6435ee
commit c4edfb4e08
3 changed files with 61 additions and 16 deletions

View File

@ -64,7 +64,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
if (!sym || sym->r) {
/* if the last label is defined, then define a new one */
sym = label_push(&s1->asm_labels, label, 0);
sym->type.t = VT_STATIC | VT_VOID;
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
}
}
pe->v = 0;
@ -123,7 +123,7 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
if (!sym) {
sym = label_push(&s1->asm_labels, tok, 0);
/* NOTE: by default, the symbol is global */
sym->type.t = VT_VOID;
sym->type.t = VT_VOID | VT_EXTERN;
}
if (sym->r == SHN_ABS) {
/* if absolute symbol, no need to put a symbol value */
@ -317,14 +317,17 @@ ST_FUNC int asm_int_expr(TCCState *s1)
/* NOTE: the same name space as C labels is used to avoid using too
much memory when storing labels in TokenStrings */
static void asm_new_label1(TCCState *s1, int label, int is_local,
static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
int sh_num, int value)
{
Sym *sym;
sym = label_find(label);
if (sym) {
if (sym->r) {
/* A VT_EXTERN symbol, even if it has a section is considered
overridable. This is how we "define" .set targets. Real
definitions won't have VT_EXTERN set. */
if (sym->r && !(sym->type.t & VT_EXTERN)) {
/* the label is already defined */
if (!is_local) {
tcc_error("assembler label '%s' already defined",
@ -337,15 +340,34 @@ static void asm_new_label1(TCCState *s1, int label, int is_local,
} else {
new_label:
sym = label_push(&s1->asm_labels, label, 0);
sym->type.t = VT_STATIC | VT_VOID;
/* If we need a symbol to hold a value, mark it as
tentative only (for .set). If this is for a real label
we'll remove VT_EXTERN. */
sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
}
sym->r = sh_num;
sym->jnext = value;
return sym;
}
static void asm_new_label(TCCState *s1, int label, int is_local)
static Sym* asm_new_label(TCCState *s1, int label, int is_local)
{
asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
return asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
}
/* Set the value of LABEL to that of some expression (possibly
involving other symbols). LABEL can be overwritten later still. */
static Sym* set_symbol(TCCState *s1, int label)
{
Sym *sym;
long n;
ExprValue e;
next();
asm_expr(s1, &e);
n = e.v;
if (e.sym)
n += e.sym->jnext;
return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n);
}
static void asm_free_labels(TCCState *st)
@ -356,6 +378,7 @@ static void asm_free_labels(TCCState *st)
for(s = st->asm_labels; s != NULL; s = s1) {
s1 = s->prev;
/* define symbol value in object file */
s->type.t &= ~VT_EXTERN;
if (s->r) {
if (s->r == SHN_ABS)
sec = SECTION_ABS;
@ -608,6 +631,15 @@ static void asm_parse_directive(TCCState *s1)
goto zero_pad;
}
break;
case TOK_ASMDIR_set:
next();
tok1 = tok;
next();
/* Also accept '.set stuff', but don't do anything with this.
It's used in GAS to set various features like '.set mips16'. */
if (tok == ',')
set_symbol(s1, tok1);
break;
case TOK_ASMDIR_globl:
case TOK_ASMDIR_global:
case TOK_ASMDIR_weak:
@ -620,7 +652,7 @@ static void asm_parse_directive(TCCState *s1)
sym = label_find(tok);
if (!sym) {
sym = label_push(&s1->asm_labels, tok, 0);
sym->type.t = VT_VOID;
sym->type.t = VT_VOID | VT_EXTERN;
}
if (tok1 != TOK_ASMDIR_hidden)
sym->type.t &= ~VT_STATIC;
@ -743,7 +775,7 @@ static void asm_parse_directive(TCCState *s1)
sym = label_find(tok);
if (!sym) {
sym = label_push(&s1->asm_labels, tok, 0);
sym->type.t = VT_VOID;
sym->type.t = VT_VOID | VT_EXTERN;
}
next();
@ -875,6 +907,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
asm_parse_directive(s1);
} else if (tok == TOK_PPNUM) {
Sym *sym;
const char *p;
int n;
p = tokc.str.data;
@ -882,7 +915,9 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
if (*p != '\0')
expect("':'");
/* new local label */
asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
/* Remove the marker for tentative definitions. */
sym->type.t &= ~VT_EXTERN;
next();
skip(':');
goto redo;
@ -898,18 +933,16 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
sym = label_find(opcode);
if (!sym) {
sym = label_push(&s1->asm_labels, opcode, 0);
sym->type.t = VT_VOID;
sym->type.t = VT_VOID | VT_EXTERN;
}
}
/* new label */
asm_new_label(s1, opcode, 0);
sym = asm_new_label(s1, opcode, 0);
sym->type.t &= ~VT_EXTERN;
next();
goto redo;
} else if (tok == '=') {
int n;
next();
n = asm_int_expr(s1);
asm_new_label1(s1, opcode, 0, SHN_ABS, n);
set_symbol(s1, opcode);
goto redo;
} else {
asm_opcode(s1, opcode);

View File

@ -308,6 +308,7 @@
DEF_ASMDIR(align)
DEF_ASMDIR(balign)
DEF_ASMDIR(p2align)
DEF_ASMDIR(set)
DEF_ASMDIR(skip)
DEF_ASMDIR(space)
DEF_ASMDIR(string)

View File

@ -824,6 +824,17 @@ nop
.skip (-((4b-3b) > 0) * 2) , 0x90
.popsection
.globl overrideme
.weak overrideme
nop
.globl notimplemented
notimplemented:
ret
.set overrideme, notimplemented
overrideme = notimplemented
overrideme:
ret
movd %esi, %mm1
movd %edi, %xmm2
movd (%ebx), %mm3