scc

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

commit ffe76c7c9ca25412638fc552cf6e5c68be1d61ce
parent dd5fa13571a7ac1f16c88b3590502e1ed4e8b359
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sat,  9 Sep 2017 06:39:29 +0200

[as] Add support for data definitions

Add DB, DW, DD and DQ

Diffstat:
Mas/as.h | 21+++++++++++++++------
Aas/common.dat | 6++++++
Mas/emit.c | 19++++---------------
Mas/ins.c | 46++++++++++++++++++++++++++++++++++++++++++++++
Mas/ins.h | 2+-
Mas/main.c | 99++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mas/target/amd64/ins.c | 1+
Mas/target/amd64/target.mk | 6++++--
Mas/target/i386/ins.c | 1+
Mas/target/i386/target.mk | 7+++++--
Aas/target/x86/args.h | 7+++++++
Mas/target/x86/gen.awk | 31+++++++++++++++++++++++++++----
12 files changed, 193 insertions(+), 53 deletions(-)

diff --git a/as/as.h b/as/as.h @@ -5,16 +5,23 @@ enum secflags { SFILE, }; +enum args { + AIMM = 1, + AMAX, + AREP = 1 << 7, +}; + +enum endianess { + BIG_ENDIAN = -1, + LITTLE_ENDIAN = 1 +}; + typedef struct ins Ins; typedef struct op Op; typedef struct arg Arg; typedef void Format(Op *, Arg *); typedef struct section Section; -enum { - BITS16, -}; - struct ins { int begin, end; char *str; @@ -25,11 +32,11 @@ struct op { int size; void (*format)(Op *, Arg *); char *bytes; - char *args; + unsigned char *args; }; struct arg { - int type; + unsigned char type; TUINT val; }; @@ -48,6 +55,7 @@ extern void isections(void); extern void writeout(char *name); extern void emit(Section *sec, char *bytes, int nbytes); extern Section *section(char *name); +extern void incpc(int siz); extern Section *cursec; extern int nr_ins; @@ -55,3 +63,4 @@ extern Ins instab[]; extern Op optab[]; extern int pass; extern TUINT maxaddr; +extern int endian; diff --git a/as/common.dat b/as/common.dat @@ -0,0 +1,6 @@ +# Tab 16, tabs 16, :set ts=16 +# op args size bytes format +DB imm8* 0 none defb +DW imm16* 0 none defw +DD imm32* 0 none defd +DQ imm64* 0 none defq diff --git a/as/emit.c b/as/emit.c @@ -43,13 +43,6 @@ isect(Section *sec) } Section * -addsect(char *name, TUINT base, int flags) -{ - Section *sec; - -} - -Section * section(char *name) { Section *sec; @@ -78,15 +71,11 @@ isections(void) } void -emit(Section *sec, char *bytes, int nbytes) +emit(Section *sec, char *bytes, int n) { - TUINT addr; - - if (!sec->mem) - return; - - for (addr = sec->pc - sec->base; nbytes--; addr++) - sec->mem[addr] = *bytes++; + if (sec->mem) + memcpy(&sec->mem[sec->pc - sec->base], bytes, n); + incpc(n); } void diff --git a/as/ins.c b/as/ins.c @@ -8,3 +8,49 @@ direct(Op *op, Arg *args) { emit(cursec, op->bytes, op->size); } + +char * +pack(TUINT v, int n, int inc) +{ + static char buf[sizeof(TUINT)]; + int idx; + + idx = (inc < 0) ? n-1 : 0; + while (n--) { + buf[idx] = v; + idx += inc; + v >>= 8; + } + return buf; +} + +void +def(Arg *args, int siz) +{ + for ( ; args->type; ++args) + emit(cursec, pack(args->val, siz, endian), siz); +} + +void +defb(Op *op, Arg *args) +{ + def(args, 1); +} + +void +defw(Op *op, Arg *args) +{ + def(args, 2); +} + +void +defd(Op *op, Arg *args) +{ + def(args, 4); +} + +void +defq(Op *op, Arg *args) +{ + def(args, 8); +} diff --git a/as/ins.h b/as/ins.h @@ -1,2 +1,2 @@ -Format direct; +Format direct, defb, defw, defd, defq; diff --git a/as/main.c b/as/main.c @@ -1,4 +1,5 @@ +#include <ctype.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -8,6 +9,8 @@ #include "as.h" #define MAXLINE 100 +#define NARGS 20 + int nerrors; void @@ -28,7 +31,6 @@ cmp(const void *f1, const void *f2) { const Ins *ins = f2; - return strcmp(f1, ins->str); } @@ -38,10 +40,81 @@ match(Op *op, Arg *args) return 1; } +Arg +number(char *s, int base) +{ + Arg arg; + TUINT n; + + /* TODO: Check overflow here */ + arg.type = AIMM; + for (n = 0; *s; n += *s++ - '0') + n *= base; + arg.val = n; + + return arg; +} + Arg * -getargs(char *text) +getargs(char *s) { - return NULL; + char *t; + int ch, len; + Arg *ap; + static Arg args[NARGS]; + + for (ap = args; ; ++ap) { + while (isspace(*s)) + ++s; + if (*s == '\0') + break; + if (ap == &args[NARGS-1]) + die("too many arguments in one instruction"); + + for (t = s; *s && *s != ','; s++) + /* nothing */; + len = t - s; + if (len == 0) + goto wrong_operand; + + if (*s) + *s++ = '\0'; + + ch = *t; + if (isdigit(ch)) { + *ap = number(t, (s[len-1] == 'H') ? 16 : 10); + continue; + } +wrong_operand: + error("wrong operand '%s'", t); + } + ap->type = 0; + + return args; +} + +void +incpc(int siz) +{ + TUINT pc, curpc; + pc = cursec->pc; + curpc = cursec->curpc; + + cursec->curpc += siz; + cursec->pc += siz; + + if (pass == 2) + return; + + if (cursec->pc > cursec->max) + cursec->max = cursec->pc; + + if (pc > cursec->pc || + curpc > cursec->curpc || + cursec->curpc > maxaddr || + cursec->pc > maxaddr) { + die("address overflow"); + } } void @@ -50,7 +123,6 @@ as(char *text, char *xargs) Ins *ins; Op *op, *lim; Arg *args; - TUINT pc, curpc; ins = bsearch(text, instab, nr_ins, sizeof(Ins), cmp); @@ -70,25 +142,6 @@ as(char *text, char *xargs) return; } (*op->format)(op, args); - - pc = cursec->pc; - curpc = cursec->curpc; - - cursec->curpc += op->size; - cursec->pc += op->size; - - if (pass == 2) - return; - - if (cursec->pc > cursec->max) - cursec->max = cursec->pc; - - if (pc > cursec->pc || - curpc > cursec->curpc || - cursec->curpc > maxaddr || - cursec->pc > maxaddr) { - die("address overflow"); - } } int diff --git a/as/target/amd64/ins.c b/as/target/amd64/ins.c @@ -4,3 +4,4 @@ #include "ins.h" TUINT maxaddr = 0xFFFFFFFFFFFFFFFF; +int endian = LITTLE_ENDIAN; diff --git a/as/target/amd64/target.mk b/as/target/amd64/target.mk @@ -1,8 +1,10 @@ -AMD64_TBL = target/x86/i386.dat target/x86/amd64.dat +AMD64_TBL = common.dat \ + target/x86/i386.dat \ + target/x86/amd64.dat target/amd64/instbl.o: target/amd64/ins.h -target/amd64/instbl.c: target/x86/gen.awk $(AMD64_SHDEP) +target/amd64/instbl.c: target/x86/gen.awk $(AMD64_TBL) set -e ;\ rm -f $@;\ trap "rm -f $$$$.c" 0 2 3; \ diff --git a/as/target/i386/ins.c b/as/target/i386/ins.c @@ -4,3 +4,4 @@ #include "ins.h" TUINT maxaddr = 0xFFFFFFFF; +int endian = LITTLE_ENDIAN; diff --git a/as/target/i386/target.mk b/as/target/i386/target.mk @@ -1,12 +1,15 @@ +I386_TBL = common.dat \ + target/x86/i386.dat target/i386/ins.o: target/i386/ins.h target/i386/instbl.o: target/i386/ins.h -target/i386/instbl.c: target/x86/gen.awk target/x86/i386.dat +target/i386/instbl.c: target/x86/gen.awk $(I386_TBL) set -e ;\ rm -f $@;\ trap "rm -f $$$$.c" 0 2 3; \ - awk -f target/x86/gen.awk < target/x86/i386.dat > $$$$.c && mv $$$$.c $@ + cat $(I386_TBL) | \ + awk -f target/x86/gen.awk > $$$$.c && mv $$$$.c $@ OBJ-i386 = $(OBJ) \ target/i386/instbl.o \ diff --git a/as/target/x86/args.h b/as/target/x86/args.h @@ -0,0 +1,7 @@ + +enum args_x86 { + AIMM8 = AMAX, + AIMM16, + AIMM32, + AIMM64, +}; diff --git a/as/target/x86/gen.awk b/as/target/x86/gen.awk @@ -4,6 +4,7 @@ BEGIN { printf "#include \"../../../inc/scc.h\"\n"\ "#include \"../../as.h\"\n"\ "#include \"../../ins.h\"\n"\ + "#include \"../x86/args.h\"\n"\ "#include \"ins.h\"\n\n" nop = 0; nvar = 0 } @@ -17,7 +18,7 @@ BEGIN { opcount[$1]++ opargs[nvar] = $2 opsize[nvar] = $3 - opbytes[nvar] = $4 + opbytes[nvar] = ($4 == "none") ? "" : $4 opformat[nvar++] = $5 } END { @@ -39,14 +40,36 @@ END { "\t\t.bytes = (char []) {%s},\n"\ "\t\t.size = %d,\n"\ "\t\t.format = %s,\n"\ - "\t\t.args = \"%s\"\n"\ + "\t\t.args = (char []) {%s}\n"\ "\t},\n", opbytes[i], opsize[i], opformat[i], str2args(opargs[i]) } print "};" } -function str2args(s) +function str2args(s, args, i, out) { - return "" + split(s, args, /,/) + for (i in args) { + if (args[i] == "none") + break + else if (args[i] ~ /imm8/) + out = "AIMM8" + else if (args[i] ~ /imm16/) + out = "AIMM16" + else if (args[i] ~ /imm32/) + out = "AIMM32" + else if (args[i] ~ /imm64/) + out = "AIMM64" + else { + print "wrong arg", args[i] + exit 1 + } + if (args[i] ~ /\*$/) + return out "|AREP" + out = out "," + } + out = out "0" + + return out }