scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit 88d8273a00a45b5fc2584513f360a3d63de8cb55
parent 3bad86cddca7c1d74b935a4ffda164a24bda4a7a
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Mon, 11 Sep 2017 08:15:21 +0100

[as] Add symbol definition

A symbol is only defined putting it at the beginning of a line
and it takes the value of the current pc in the current segment.
At the same the statement EQU can be used and set an absolute
value in the symbol.

Diffstat:
Mas/as.h | 37++++++++++++++++++++++++++-----------
Mas/emit.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++------------
Mas/ins.c | 9+++++++++
Mas/main.c | 13+++++++++++--
Mas/target/x86/i386.dat | 1+
5 files changed, 96 insertions(+), 25 deletions(-)

diff --git a/as/as.h b/as/as.h @@ -1,16 +1,27 @@ +/* + * First 3 bits of flags in segments and symbols are for the + * type of segment + */ +enum symtype { + TABS = 1, + TTEXT = 2, + TBSS = 3, + TDATA = 4, + TMASK = 7, +}; + enum secflags { - SRELOC, - SREAD, - SWRITE, - SFILE, + SRELOC = 1 << 4, + SREAD = 1 << 5, + SWRITE = 1 << 6, + SFILE = 1 << 7, }; enum symflags { - FUNDEF = 'U', - FABS = 'A', - FCOMMON = 'C', - FBSS = 'B', - FDATA = 'D', + FCOMMON = 1 << 4, + FLOCAL = 1 << 5, + FEXTERN = 1 << 6, + FUNDEF = 1 << 7, }; enum args { @@ -24,6 +35,8 @@ enum endianess { LITTLE_ENDIAN = 1 }; +#define MAXSYM 63 + typedef struct ins Ins; typedef struct op Op; typedef struct arg Arg; @@ -58,7 +71,7 @@ struct arg { struct section { char *name; char *mem; - int flags; + unsigned char flags; TUINT base; TUINT max; TUINT curpc; @@ -68,7 +81,8 @@ struct section { struct symbol { char *name; - char type; + unsigned char flags; + char pass; short desc; TUINT value; struct symbol *next; @@ -83,6 +97,7 @@ extern char *pack(TUINT v, int n, int inc); extern void error(char *msg, ...); extern Arg *getargs(char *s); extern Symbol *lookup(char *name); +extern Symbol *deflabel(char *name); /* Avoid errors in files where stdio is not included */ #ifdef stdin diff --git a/as/emit.c b/as/emit.c @@ -9,26 +9,26 @@ #define HASHSIZ 64 static Section abss = { - .name = "abs", - .flags = SREAD|SWRITE + .name = "abs", + .flags = TABS|SREAD|SWRITE, }; static Section bss = { - .name = "bss", - .flags = SRELOC|SREAD|SWRITE, - .next = &abss + .name = "bss", + .flags = TBSS|SRELOC|SREAD|SWRITE, + .next = &abss, }; static Section data = { - .name = "data", - .next = &bss, - .flags = SRELOC|SREAD|SWRITE|SFILE + .name = "data", + .flags = TDATA|SRELOC|SREAD|SWRITE|SFILE, + .next = &bss, }; static Section text = { - .name = "text", - .next = &data, - .flags = SRELOC|SFILE + .name = "text", + .flags = TTEXT|SRELOC|SFILE, + .next = &data, }; Section *cursec = &text, *headp = &text; @@ -36,6 +36,7 @@ Section *cursec = &text, *headp = &text; int pass; static Symbol *hashtbl[HASHSIZ]; +Symbol *linesym; Symbol * lookup(char *name) @@ -60,7 +61,7 @@ lookup(char *name) sym = xmalloc(sizeof(*sym)); sym->name = xstrdup(name); - sym->type = FUNDEF; + sym->flags = (cursec->flags & TMASK) | FLOCAL | FUNDEF; sym->desc = 0; sym->value = 0; sym->next = *list; @@ -69,6 +70,42 @@ lookup(char *name) return sym; } +Symbol * +deflabel(char *name) +{ + static Symbol *cursym; + Symbol *sym; + char label[MAXSYM+1]; + + if (*name == '.') { + int r; + + if (!cursym) { + error("local label '%s' without global label", name); + return NULL; + } + r = snprintf(label, sizeof(label), + "%s%s", + cursym->name, name); + if (r == sizeof(label)) { + error("local label '%s' in '%s' produces too long symbol", + name, cursym->name); + return NULL; + } + name = label; + } + + sym = lookup(name); + if (pass == 1 && (sym->flags & FUNDEF) == 0) + error("redefinition of label '%s'", name); + sym->flags &= ~FUNDEF; + sym->value = cursec->curpc; + + if (*name != '.') + cursym = sym; + return sym; +} + char * pack(TUINT v, int n, int inc) { diff --git a/as/ins.c b/as/ins.c @@ -38,3 +38,12 @@ defq(Op *op, Arg *args) { def(args, 8); } + +void +equ(Op *op, Arg *args) +{ + if (!linesym) + error("label definition lacks a label"); + else + linesym->value = args->val; +} diff --git a/as/main.c b/as/main.c @@ -82,8 +82,17 @@ dopass(char *fname) die("as: error opening '%s'", fname); isections(); - while (next(fp, &line)) - as(line.op, line.args); + while (next(fp, &line)) { + linesym = NULL; + + if (line.label) + linesym = deflabel(line.label); + + if (line.op) + as(line.op, line.args); + else if (line.args) + error("arguments without an opcode"); + } if (fclose(fp)) die("as: error reading from input file '%s'", fname); diff --git a/as/target/x86/i386.dat b/as/target/x86/i386.dat @@ -1,4 +1,5 @@ # Tab 16, tabs 16, :set ts=16 # op args size bytes format +EQU imm32 0 none equ NOP none 1 0x90 direct RET none 1 0xc3 direct