aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard>2004-10-18 00:19:51 +0000
committerbellard <bellard>2004-10-18 00:19:51 +0000
commit0bd402d2eb3b936521dc71a5bb894ddf4b99ade4 (patch)
treecf8b87c5250c2a01ac2bbb6dae6bc2a20a7013a1
parent9668499b9f1e7f6619082040c9aa179d19173318 (diff)
downloadtinycc-0bd402d2eb3b936521dc71a5bb894ddf4b99ade4.tar.gz
tinycc-0bd402d2eb3b936521dc71a5bb894ddf4b99ade4.tar.bz2
absolute symbols support - .org, .fill and .previous directives
-rw-r--r--tccasm.c225
1 files changed, 189 insertions, 36 deletions
diff --git a/tccasm.c b/tccasm.c
index c3f7e35..f781f20 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -28,6 +28,8 @@ static int asm_get_local_label_name(TCCState *s1, unsigned int n)
return ts->tok;
}
+static void asm_expr(TCCState *s1, ExprValue *pe);
+
/* We do not use the C expression parser to handle symbols. Maybe the
C expression parser could be tweaked to do so. */
@@ -91,6 +93,11 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
pe->sym = NULL;
next();
break;
+ case '(':
+ next();
+ asm_expr(s1, pe);
+ skip(')');
+ break;
default:
if (tok >= TOK_IDENT) {
/* label case : if the label was not found, add one */
@@ -100,8 +107,14 @@ static void asm_expr_unary(TCCState *s1, ExprValue *pe)
/* NOTE: by default, the symbol is global */
sym->type.t = VT_VOID;
}
- pe->v = 0;
- pe->sym = sym;
+ if (sym->r == SHN_ABS) {
+ /* if absolute symbol, no need to put a symbol value */
+ pe->v = (long)sym->next;
+ pe->sym = NULL;
+ } else {
+ pe->v = 0;
+ pe->sym = sym;
+ }
next();
} else {
error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
@@ -241,7 +254,8 @@ static 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_label(TCCState *s1, int label, int is_local)
+static void asm_new_label1(TCCState *s1, int label, int is_local,
+ int sh_num, int value)
{
Sym *sym;
@@ -262,18 +276,29 @@ static void asm_new_label(TCCState *s1, int label, int is_local)
sym = label_push(&s1->asm_labels, label, 0);
sym->type.t = VT_STATIC | VT_VOID;
}
- sym->r = cur_text_section->sh_num;
- sym->next = (void *)ind;
+ sym->r = sh_num;
+ sym->next = (void *)value;
+}
+
+static void asm_new_label(TCCState *s1, int label, int is_local)
+{
+ asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
}
static void asm_free_labels(TCCState *st)
{
Sym *s, *s1;
+ Section *sec;
+
for(s = st->asm_labels; s != NULL; s = s1) {
s1 = s->prev;
/* define symbol value in object file */
if (s->r) {
- put_extern_sym(s, st->sections[s->r], (long)s->next, 0);
+ if (s->r == SHN_ABS)
+ sec = SECTION_ABS;
+ else
+ sec = st->sections[s->r];
+ put_extern_sym(s, sec, (long)s->next, 0);
}
/* remove label */
table_ident[s->v - TOK_IDENT]->sym_label = NULL;
@@ -282,15 +307,20 @@ static void asm_free_labels(TCCState *st)
st->asm_labels = NULL;
}
-static void use_section(TCCState *s1, const char *name)
+static void use_section1(TCCState *s1, Section *sec)
{
- Section *sec;
- sec = find_section(s1, name);
cur_text_section->data_offset = ind;
cur_text_section = sec;
ind = cur_text_section->data_offset;
}
+static void use_section(TCCState *s1, const char *name)
+{
+ Section *sec;
+ sec = find_section(s1, name);
+ use_section1(s1, sec);
+}
+
static void asm_parse_directive(TCCState *s1)
{
int n, offset, v, size, tok1;
@@ -312,6 +342,9 @@ static void asm_parse_directive(TCCState *s1)
error("alignment must be a positive power of two");
offset = (ind + n - 1) & -n;
size = offset - ind;
+ /* the section must have a compatible alignment */
+ if (sec->sh_addralign < n)
+ sec->sh_addralign = n;
} else {
size = n;
}
@@ -320,6 +353,7 @@ static void asm_parse_directive(TCCState *s1)
next();
v = asm_int_expr(s1);
}
+ zero_pad:
if (sec->sh_type != SHT_NOBITS) {
sec->data_offset = ind;
ptr = section_ptr_add(sec, size);
@@ -361,6 +395,61 @@ static void asm_parse_directive(TCCState *s1)
next();
}
break;
+ case TOK_ASM_fill:
+ {
+ int repeat, size, val, i, j;
+ uint8_t repeat_buf[8];
+ next();
+ repeat = asm_int_expr(s1);
+ if (repeat < 0) {
+ error("repeat < 0; .fill ignored");
+ break;
+ }
+ size = 1;
+ val = 0;
+ if (tok == ',') {
+ next();
+ size = asm_int_expr(s1);
+ if (size < 0) {
+ error("size < 0; .fill ignored");
+ break;
+ }
+ if (size > 8)
+ size = 8;
+ if (tok == ',') {
+ next();
+ val = asm_int_expr(s1);
+ }
+ }
+ /* XXX: endianness */
+ repeat_buf[0] = val;
+ repeat_buf[1] = val >> 8;
+ repeat_buf[2] = val >> 16;
+ repeat_buf[3] = val >> 24;
+ repeat_buf[4] = 0;
+ repeat_buf[5] = 0;
+ repeat_buf[6] = 0;
+ repeat_buf[7] = 0;
+ for(i = 0; i < repeat; i++) {
+ for(j = 0; j < size; j++) {
+ g(repeat_buf[j]);
+ }
+ }
+ }
+ break;
+ case TOK_ASM_org:
+ {
+ unsigned long n;
+ next();
+ /* XXX: handle section symbols too */
+ n = asm_int_expr(s1);
+ if (n < ind)
+ error("attempt to .org backwards");
+ v = 0;
+ size = n - ind;
+ goto zero_pad;
+ }
+ break;
case TOK_ASM_globl:
case TOK_ASM_global:
{
@@ -420,9 +509,28 @@ static void asm_parse_directive(TCCState *s1)
pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL));
next();
}
+ if (tok == ',') {
+ /* skip section options */
+ next();
+ if (tok != TOK_STR)
+ expect("string constant");
+ next();
+ }
+ last_text_section = cur_text_section;
use_section(s1, sname);
}
break;
+ case TOK_ASM_previous:
+ {
+ Section *sec;
+ next();
+ if (!last_text_section)
+ error("no previous section referenced");
+ sec = cur_text_section;
+ use_section1(s1, last_text_section);
+ last_text_section = sec;
+ }
+ break;
default:
error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
break;
@@ -471,7 +579,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
- parse_flags = 0;
+ parse_flags = PARSE_FLAG_ASM_COMMENTS;
if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS;
next();
@@ -507,6 +615,12 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
asm_new_label(s1, opcode, 0);
next();
goto redo;
+ } else if (tok == '=') {
+ int n;
+ next();
+ n = asm_int_expr(s1);
+ asm_new_label1(s1, opcode, 0, SHN_ABS, n);
+ goto redo;
} else {
asm_opcode(s1, opcode);
}
@@ -527,6 +641,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
/* Assemble the current file */
static int tcc_assemble(TCCState *s1, int do_preprocess)
{
+ Sym *define_start;
int ret;
preprocess_init(s1);
@@ -535,9 +650,14 @@ static int tcc_assemble(TCCState *s1, int do_preprocess)
cur_text_section = text_section;
ind = cur_text_section->data_offset;
+ define_start = define_stack;
+
ret = tcc_assemble_internal(s1, do_preprocess);
cur_text_section->data_offset = ind;
+
+ free_defines(define_start);
+
return ret;
}
@@ -691,12 +811,14 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
if (is_output) {
test_lvalue();
} else {
- /* we want to avoid LLOCAL case. note that it may come
- from register storage, so we need to convert (reg)
+ /* we want to avoid LLOCAL case, except when the 'm'
+ constraint is used. Note that it may come from
+ register storage, so we need to convert (reg)
case */
if ((vtop->r & VT_LVAL) &&
((vtop->r & VT_VALMASK) == VT_LLOCAL ||
- (vtop->r & VT_VALMASK) < VT_CONST)) {
+ (vtop->r & VT_VALMASK) < VT_CONST) &&
+ !strchr(op->constraint, 'm')) {
gv(RC_INT);
}
}
@@ -712,14 +834,27 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
}
}
+static void parse_asm_str(CString *astr)
+{
+ skip('(');
+ /* read the string */
+ if (tok != TOK_STR)
+ expect("string constant");
+ cstr_new(astr);
+ while (tok == TOK_STR) {
+ /* XXX: add \0 handling too ? */
+ cstr_cat(astr, tokc.cstr->data);
+ next();
+ }
+ cstr_ccat(astr, '\0');
+}
+
/* parse the GCC asm() instruction */
static void asm_instr(void)
{
CString astr, astr1;
ASMOperand operands[MAX_ASM_OPERANDS];
- int nb_inputs, nb_outputs, nb_operands, i;
- uint8_t input_regs_allocated[NB_ASM_REGS];
- uint8_t output_regs_allocated[NB_ASM_REGS];
+ int nb_inputs, nb_outputs, nb_operands, i, must_subst, out_reg;
uint8_t clobber_regs[NB_ASM_REGS];
next();
@@ -728,22 +863,14 @@ static void asm_instr(void)
if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
next();
}
- skip('(');
- /* read the string */
- if (tok != TOK_STR)
- expect("string constant");
- cstr_new(&astr);
- while (tok == TOK_STR) {
- /* XXX: add \0 handling too ? */
- cstr_cat(&astr, tokc.cstr->data);
- next();
- }
- cstr_ccat(&astr, '\0');
+ parse_asm_str(&astr);
nb_operands = 0;
nb_outputs = 0;
+ must_subst = 0;
memset(clobber_regs, 0, sizeof(clobber_regs));
if (tok == ':') {
next();
+ must_subst = 1;
/* output args */
parse_asm_operands(operands, &nb_operands, 1);
nb_outputs = nb_operands;
@@ -780,19 +907,15 @@ static void asm_instr(void)
save_regs(0);
/* compute constraints */
- asm_compute_constraints(input_regs_allocated,
- operands, nb_operands, nb_outputs, 0,
- NULL);
- asm_compute_constraints(output_regs_allocated,
- operands, nb_operands, nb_outputs, 1,
- input_regs_allocated);
+ asm_compute_constraints(operands, nb_operands, nb_outputs,
+ clobber_regs, &out_reg);
/* substitute the operands in the asm string. No substitution is
done if no operands (GCC behaviour) */
#ifdef ASM_DEBUG
printf("asm: \"%s\"\n", (char *)astr.data);
#endif
- if (nb_operands > 0) {
+ if (must_subst) {
subst_asm_operands(operands, nb_operands, nb_outputs, &astr1, &astr);
cstr_free(&astr);
} else {
@@ -803,7 +926,8 @@ static void asm_instr(void)
#endif
/* generate loads */
- asm_gen_code(operands, nb_operands, nb_outputs, 0, clobber_regs);
+ asm_gen_code(operands, nb_operands, nb_outputs, 0,
+ clobber_regs, out_reg);
/* assemble the string with tcc internal assembler */
tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1);
@@ -812,7 +936,8 @@ static void asm_instr(void)
next();
/* store the output values if needed */
- asm_gen_code(operands, nb_operands, nb_outputs, 1, clobber_regs);
+ asm_gen_code(operands, nb_operands, nb_outputs, 1,
+ clobber_regs, out_reg);
/* free everything */
for(i=0;i<nb_operands;i++) {
@@ -824,3 +949,31 @@ static void asm_instr(void)
cstr_free(&astr1);
}
+static void asm_global_instr(void)
+{
+ CString astr;
+
+ next();
+ parse_asm_str(&astr);
+ skip(')');
+ /* NOTE: we do not eat the ';' so that we can restore the current
+ token after the assembler parsing */
+ if (tok != ';')
+ expect("';'");
+
+#ifdef ASM_DEBUG
+ printf("asm_global: \"%s\"\n", (char *)astr.data);
+#endif
+ cur_text_section = text_section;
+ ind = cur_text_section->data_offset;
+
+ /* assemble the string with tcc internal assembler */
+ tcc_assemble_inline(tcc_state, astr.data, astr.size - 1);
+
+ cur_text_section->data_offset = ind;
+
+ /* restore the current C token */
+ next();
+
+ cstr_free(&astr);
+}