shithub: scc

Download patch

ref: f7ecd7063b03eb0604490bb2e3d335cbf3873813
parent: c1a3310fbbad48582811bb35438f194bbab27c3e
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Sep 11 04:15:21 EDT 2017

[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.

--- 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 @@
 	LITTLE_ENDIAN = 1
 };
 
+#define MAXSYM 63
+
 typedef struct ins Ins;
 typedef struct op Op;
 typedef struct arg Arg;
@@ -58,7 +71,7 @@
 struct section {
 	char *name;
 	char *mem;
-	int flags;
+	unsigned char flags;
 	TUINT base;
 	TUINT max;
 	TUINT curpc;
@@ -68,7 +81,8 @@
 
 struct symbol {
 	char *name;
-	char type;
+	unsigned char flags;
+	char pass;
 	short desc;
 	TUINT value;
 	struct symbol *next;
@@ -83,6 +97,7 @@
 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
--- 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 @@
 int pass;
 
 static Symbol *hashtbl[HASHSIZ];
+Symbol *linesym;
 
 Symbol *
 lookup(char *name)
@@ -60,12 +61,48 @@
 
 	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;
 	*list = sym;
 
+	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;
 }
 
--- a/as/ins.c
+++ b/as/ins.c
@@ -38,3 +38,12 @@
 {
 	def(args, 8);
 }
+
+void
+equ(Op *op, Arg *args)
+{
+	if (!linesym)
+		error("label definition lacks a label");
+	else
+		linesym->value = args->val;
+}
--- a/as/main.c
+++ b/as/main.c
@@ -82,8 +82,17 @@
 		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);
--- 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