aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2016-08-07 04:27:32 +0200
committerMichael Matz <matz@suse.de>2016-12-15 17:47:10 +0100
commitc4edfb4e0804aa005ee9e199420a17828076120a (patch)
tree4fd3b5db597dce06a0ce603ccfaa73eea6f7834a
parent34fc6435ee17e6d2bbfffc367532cf340cf730a2 (diff)
downloadtinycc-c4edfb4e0804aa005ee9e199420a17828076120a.tar.gz
tinycc-c4edfb4e0804aa005ee9e199420a17828076120a.tar.bz2
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.
-rw-r--r--tccasm.c65
-rw-r--r--tcctok.h1
-rw-r--r--tests/asmtest.S11
3 files changed, 61 insertions, 16 deletions
diff --git a/tccasm.c b/tccasm.c
index cef3f1c..0bf6456 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -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);
diff --git a/tcctok.h b/tcctok.h
index 9bbe879..775b338 100644
--- a/tcctok.h
+++ b/tcctok.h
@@ -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)
diff --git a/tests/asmtest.S b/tests/asmtest.S
index 10ec2ee..dbc6c15 100644
--- a/tests/asmtest.S
+++ b/tests/asmtest.S
@@ -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