shithub: scc

Download patch

ref: 10e4cba238d4a3003646328e3994bd17db2ef245
parent: 1ef6b829384110fa3ecac471bfd384e11480c532
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Sat Sep 9 02:39:29 EDT 2017

[as] Add support for data definitions

Add DB, DW, DD and DQ

--- a/as/as.h
+++ b/as/as.h
@@ -5,6 +5,17 @@
 	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;
@@ -11,10 +22,6 @@
 typedef void Format(Op *, Arg *);
 typedef struct section Section;
 
-enum {
-	BITS16,
-};
-
 struct ins {
 	int begin, end;
 	char *str;
@@ -25,11 +32,11 @@
 	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 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 Op optab[];
 extern int pass;
 extern TUINT maxaddr;
+extern int endian;
--- /dev/null
+++ b/as/common.dat
@@ -1,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
--- a/as/emit.c
+++ b/as/emit.c
@@ -43,13 +43,6 @@
 }
 
 Section *
-addsect(char *name, TUINT base, int flags)
-{
-	Section *sec;
-
-}
-
-Section *
 section(char *name)
 {
 	Section *sec;
@@ -78,15 +71,11 @@
 }
 
 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
--- a/as/ins.c
+++ b/as/ins.c
@@ -8,3 +8,49 @@
 {
 	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);
+}
--- a/as/ins.h
+++ b/as/ins.h
@@ -1,2 +1,2 @@
 
-Format direct;
+Format direct, defb, defw, defd, defq;
--- 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 @@
 {
 	const Ins *ins = f2;
 
-
 	return strcmp(f1, ins->str);
 }
 
@@ -38,19 +40,89 @@
 	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
 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 @@
 		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
--- 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;
--- 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; \
--- 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;
--- 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 \
--- /dev/null
+++ b/as/target/x86/args.h
@@ -1,0 +1,7 @@
+
+enum args_x86 {
+	AIMM8 = AMAX,
+	AIMM16,
+	AIMM32,
+	AIMM64,
+};
--- a/as/target/x86/gen.awk
+++ b/as/target/x86/gen.awk
@@ -4,6 +4,7 @@
 	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 @@
 	opcount[$1]++
 	opargs[nvar] = $2
 	opsize[nvar] = $3
-	opbytes[nvar] = $4
+	opbytes[nvar] = ($4 == "none") ? "" : $4
 	opformat[nvar++] = $5
 }
 END	{
@@ -39,7 +40,7 @@
 		       "\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])
 	}
@@ -46,7 +47,29 @@
 	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
 }