changeset 77:a338d496350e

Checkpointing conversion to allow object target
author lost
date Fri, 09 Jan 2009 04:23:00 +0000
parents 2fe5fd7d65a3
children 121bf4a588ea
files src/insn_gen.c src/insn_rel.c src/lwasm.c src/lwasm.h src/symbol.c
diffstat 5 files changed, 210 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/src/insn_gen.c	Thu Jan 08 02:57:24 2009 +0000
+++ b/src/insn_gen.c	Fri Jan 09 04:23:00 2009 +0000
@@ -39,7 +39,7 @@
 	int f8 = 0;
 	int f16 = 0;
 	int isdp = 0;
-		
+
 	optr2 = *optr;
 	while (*optr2 && !isspace(*optr2) && *optr2 != ',') optr2++
 		/* do nothing */ ;
@@ -62,24 +62,21 @@
 			(*optr)++;
 			f16 = 1;
 		}
-		s = lwasm_evaluate_expr(as, l, *optr, NULL);
-		if (!s)
-		{
-			register_error(as, l, 1, "Bad expression");
-			return;
-		}
-		if (!lwasm_expr_is_constant(s) && as -> passnum == 1)
+		rval = lwasm_expr_result2(as, l, optr, 0, &v1, 0);
+		if (rval != 0)
 		{
 			f16 = 1;
+			v1 = 0;
 			l -> fsize = 2;
-			register_error(as, l, 2, "Incomplete reference");
 		}
-		v1 = lwasm_expr_get_value(s);
-		lwasm_expr_stack_free(s);
 
 		if (((v1 >> 8) & 0xff) == (as -> dpval & 0xff))
 			isdp = 1;
 		
+		// disallow non-explicit DP in obj target
+		if (as -> outformat == OUTPUT_OBJ && !f8)
+			f16 = 1;
+	
 		if (f8 || (!f16 && isdp))
 		{
 			v1 = v1 & 0xffff;
@@ -101,6 +98,7 @@
 			lwasm_emitop(as, l, instab[opnum].ops[2]);
 			if (extra != -1)
 				lwasm_emit(as, l, extra);
+			l -> relocoff = as -> addr - l -> codeaddr;
 			lwasm_emit(as, l, v1 >> 8);
 			lwasm_emit(as, l, v1 & 0xff);
 			return;
@@ -136,13 +134,17 @@
 OPFUNC(insn_gen8)
 {
 	int rval;
+	int r;
 	
 	if (**p == '#')
 	{
 		lwasm_emitop(as, l, instab[opnum].ops[3]);
 		(*p)++;
-		if (lwasm_expr_result(as, l, p, EXPR_PASS2CONST | EXPR_BYTE, &rval) < 0)
+		r = lwasm_expr_result2(as, l, p, EXPR_PASS2CONST | EXPR_BYTE, &rval, 0);
+		if (r != 0)
 			rval = 0;
+		if (r == 1 && as -> passnum == 2)
+			register_error(as, l, 2, "Illegal external or intersegment reference");
 		lwasm_emit(as, l, rval & 0xff);
 		return;
 	}
@@ -152,25 +154,19 @@
 
 OPFUNC(insn_gen16)
 {
-	lwasm_expr_stack_t *s;
-	int rval;
+	int rval, r;
 	
 	if (**p == '#')
 	{
 		lwasm_emitop(as, l, instab[opnum].ops[3]);
 		(*p)++;
-		s = lwasm_evaluate_expr(as, l, *p, NULL);
-		if (!s)
-		{
-			register_error(as, l, 1, "Bad expression");
+
+		r = lwasm_expr_result2(as, l, p, 0, &rval, 0);
+		if (r != 0)
 			rval = 0;
-		}
-		else
+		if (r == 1 && as -> passnum == 2)
 		{
-			if (!lwasm_expr_is_constant(s))
-				register_error(as, l, 2, "Incomplete reference");
-			rval = lwasm_expr_get_value(s);
-			lwasm_expr_stack_free(s);
+			l -> relocoff = as -> addr - l -> codeaddr;
 		}
 		lwasm_emit(as, l, (rval >> 8) & 0xff);
 		lwasm_emit(as, l, rval & 0xff);
@@ -182,26 +178,21 @@
 
 OPFUNC(insn_gen32)
 {
-	lwasm_expr_stack_t *s;
-	int rval;
+	int r, rval;
 	
 	if (**p == '#')
 	{
 		lwasm_emitop(as, l, instab[opnum].ops[3]);
 		(*p)++;
-		s = lwasm_evaluate_expr(as, l, *p, NULL);
-		if (!s)
+
+		r = lwasm_expr_result2(as, l, p, 0, &rval, 0);
+		if (r != 0)
+			rval = 0;
+		if (r == 1 && as -> passnum == 2)
 		{
-			register_error(as, l, 1, "Bad expression");
-			rval = 0;
+			register_error(as, l, 2, "Illegal external or intersegment reference");
 		}
-		else
-		{
-			if (!lwasm_expr_is_constant(s))
-				register_error(as, l, 2, "Incomplete reference");
-			rval = lwasm_expr_get_value(s);
-			lwasm_expr_stack_free(s);
-		}
+
 		lwasm_emit(as, l, (rval >> 24) & 0xff);
 		lwasm_emit(as, l, (rval >> 16) & 0xff);
 		lwasm_emit(as, l, (rval >> 8) & 0xff);
@@ -214,26 +205,19 @@
 
 OPFUNC(insn_imm8)
 {
-	lwasm_expr_stack_t *s;
-	int rval;
+	int r, rval;
 	
 	if (**p == '#')
 	{
 		lwasm_emitop(as, l, instab[opnum].ops[0]);
 		(*p)++;
-		s = lwasm_evaluate_expr(as, l, *p, NULL);
-		if (!s)
-		{
-			register_error(as, l, 1, "Bad expression");
+
+		r = lwasm_expr_result2(as, l, p, EXPR_PASS2CONST | EXPR_BYTE, &rval, 0);
+		if (r != 0)
 			rval = 0;
-		}
-		else
-		{
-			if (!lwasm_expr_is_constant(s))
-				register_error(as, l, 2, "Incomplete reference");
-			rval = lwasm_expr_get_value(s);
-			lwasm_expr_stack_free(s);
-		}
+		if (r == 1 && as -> passnum == 2)
+			register_error(as, l, 2, "Illegal external or intersegment reference");
+
 		if (rval < -128 || rval > 255)
 			register_error(as, l, 2, "Byte overflow");
 		lwasm_emit(as, l, rval & 0xff);
--- a/src/insn_rel.c	Thu Jan 08 02:57:24 2009 +0000
+++ b/src/insn_rel.c	Fri Jan 09 04:23:00 2009 +0000
@@ -33,28 +33,81 @@
 OPFUNC(insn_rel8)
 {
 	int v;
+	lwasm_expr_term_t *t;
+	int r;
 	
 	lwasm_emitop(as, l, instab[opnum].ops[0]);
-	
-	if (lwasm_expr_result(as, l, p, EXPR_PASS2CONST, &v) < 0)
+
+	if ((r = lwasm_expr_result2(as, l, p, EXPR_PASS2CONST | EXPR_NOINTERSECT, &v, 0)) != 0)
+		v = 0;
+	else
 	{
-		v = 0;
+		if (as -> passnum == 1)
+		{
+			// need to adjust the expression
+			v -= as -> addr + 1;
+			if (l -> exprs[0])
+			{
+				t = lwasm_expr_term_create_int(as -> addr + 1);
+				lwasm_expr_stack_push(l -> exprs[0], t);
+				lwasm_expr_term_free(t);
+				t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS);
+				lwasm_expr_stack_push(l -> exprs[0], t);
+				lwasm_expr_term_free(t);
+			}
+			else
+			{
+				l -> exprvals[0] -= as -> addr + 1;
+			}
+		}
 	}
-	v -= as -> addr + 1;
+	if (r == 1 && as -> passnum == 2)
+	{
+		register_error(as, l, 2, "Illegal external or intersegment reference");
+	}
 	if (v < -128 || v > 127)
 		register_error(as, l, 2, "Byte overflow");
 	lwasm_emit(as, l, v & 0xff);
 }
 
+/*
+External and intersegment references are adjusted for the relative addressing mode
+by adjusting the expression on pass 1 and then treated as absolute references later
+*/
 OPFUNC(insn_rel16)
 {
 	int v;
+	int r;
+	lwasm_expr_term_t *t;
 	
 	lwasm_emitop(as, l, instab[opnum].ops[0]);
 	
-	if (lwasm_expr_result(as, l, p, EXPR_PASS2CONST, &v) < 0)
+	r = lwasm_expr_result2(as, l, p, EXPR_PASS2CONST, &v, 0);
+	if (r != 0)
 		v = 0;
-	v -= as -> addr + 2;
+	else
+	{
+		if (as -> passnum == 1)
+		{
+			// need to adjust the expression
+			v -= as -> addr + 1;
+			if (l -> exprs[0])
+			{
+				t = lwasm_expr_term_create_int(as -> addr + 1);
+				lwasm_expr_stack_push(l -> exprs[0], t);
+				lwasm_expr_term_free(t);
+				t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS);
+				lwasm_expr_stack_push(l -> exprs[0], t);
+				lwasm_expr_term_free(t);
+			}
+			else
+			{
+				l -> exprvals[0] -= as -> addr + 2;
+			}
+		}
+	}
+	if (as -> passnum == 2 && r == 1)
+		l -> relocoff = as -> addr - l -> codeaddr;
 	lwasm_emit(as, l, (v >> 8) & 0xff);
 	lwasm_emit(as, l, v & 0xff);
 }
--- a/src/lwasm.c	Thu Jan 08 02:57:24 2009 +0000
+++ b/src/lwasm.c	Fri Jan 09 04:23:00 2009 +0000
@@ -216,7 +216,10 @@
 		se = lwasm_find_symbol(st -> as, sym, -1);
 	debug_message(3, "lwasm_expr_lookup_symbol(): got '%p'", se);
 	if (!se)
+	{
+		register_error(st -> as, st -> l, 2, "Undefined symbol '%s'", sym);
 		return NULL;
+	}
 	if (st -> as -> outformat != OUTPUT_OBJ || se -> sect == NULL || se -> sect == st -> as -> csect)
 	{
 		// global symbol, intrasegment reference, or not an object target
@@ -258,6 +261,17 @@
 	return(lwasm_expr_eval(inp, outp, lwasm_expr_lookup_symbol, &st));
 }
 
+
+int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s)
+{
+	struct symstateinfo st;
+	
+	st.as = as;
+	st.l = l;
+	
+	return(lwasm_expr_reval(s, lwasm_expr_lookup_symbol, &st));
+}
+
 // return 1 if no undefined symbols (externals and incompletes are okay)
 // return 0 if there are undefined symbols
 int lwasm_expr_result_ckconst(asmstate_t *as, lwasm_expr_stack_t *s)
@@ -265,6 +279,14 @@
 	lwasm_expr_stack_node_t *n;
 	lwasm_symbol_ent_t *se;
 	
+	if (as -> outformat != OUTPUT_OBJ)
+	{
+		if (lwasm_expr_is_constant(s))
+			return 1;
+		else
+			return 0;
+	}
+	
 	for (n = s -> head; n; n = n -> next)
 	{
 		if (n -> term -> term_type == LWASM_TERM_SYM)
@@ -289,7 +311,13 @@
 - a symbol defined in another section will remain unresolved
 - external references will also remain unresolved
 
+EXPR_PASS2PASS will cause the result from pass 1 along with the offset to
+the end of the expression to be stored in the line data. There can only be
+one such expression per source line. In this case, the expression is parsed
+and evaluated on pass 1 but the intermediate representation is re-evaluated
+on pass 2.
 */
+/*
 int lwasm_expr_result(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val)
 {
 	lwasm_expr_stack_t *s;
@@ -305,22 +333,40 @@
 	}
 	*inp = (char *)ep;
 	
-	if (flag & EXPR_PASS1CONST && as -> passnum == 1 && !lwasm_expr_is_constant(s))
+	if (flag & EXPR_PASS1CONST && as -> passnum == 1 && !lwasm_expr_result_ckconst(as, s))
 	{
-		register_error(as, l, 1, "Illegal incomplete reference (pass 1)");
+		register_error(as, l, 1, "Undefined reference (pass 1)");
+		*val = 0;
+		lwasm_expr_stack_free(s);
+		return -1;
+	}
+	if (flag & EXPR_PASS2CONST && as -> passnum == 2 && !lwasm_expr_result_ckconst(as, s))
+	{
+		register_error(as, l, 2, "Undefined reference (pass 2)");
 		*val = 0;
 		lwasm_expr_stack_free(s);
 		return -1;
 	}
-	if (flag & EXPR_PASS2CONST && as -> passnum == 2 && !lwasm_expr_is_constant(s))
+	if (flag & EXPR_NOINTERSECT && !lwasm_expr_is_constant(s))
 	{
-		register_error(as, l, 2, "Incomplete reference (pass 2)");
-		*val = 0;
-		lwasm_expr_stack_free(s);
-		return -1;
+		register_error(as, l, 2, "Invalid inter-section reference");
 	}
 	*val = lwasm_expr_get_value(s);
-	lwasm_expr_stack_free(s);
+	if (l -> expr)
+	{
+		lwasm_expr_stack_free(l -> expr);
+		l -> expr = NULL;
+	}
+	if (lwasm_is_constant(s))
+	{
+		// fully resolved value here
+		lwasm_expr_stack_free(s);
+	}
+	else
+	{
+		// incomplete reference here
+		l -> expr = s;
+	}
 
 	if (flag & EXPR_BYTE && as -> passnum == 2 && (*val < -128 || *val > 255))
 	{
@@ -335,6 +381,50 @@
 
 	return 0;
 }
+*/
+int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot)
+{
+	lwasm_expr_stack_t *s;
+	const char *ep;
+	int rval;
+
+	if (as -> passnum == 1)
+	{		
+		s = lwasm_evaluate_expr(as, l, *inp, &ep);
+		l -> exprs[slot] = s;
+		if (!s)
+		{
+			register_error(as, l, 1, "Bad expression");
+			*val = 0;
+			return -1;
+		}
+		*inp = (char *)ep;
+		l -> exprends[slot] = *inp;
+		l -> exprvals[slot] = lwasm_expr_get_value(s);
+	}
+	else if (l -> exprs[slot])
+	{
+		s = l -> exprs[slot];
+		*inp = l -> exprends[slot];
+		lwasm_reevaluate_expr(as, l, s);
+		l -> exprvals[slot] = lwasm_expr_get_value(s);
+	}
+
+	if (s && lwasm_expr_is_constant(s))
+	{
+		lwasm_expr_stack_free(s);
+		l -> exprs[slot] = NULL;
+		s = NULL;
+	}
+
+	if (!s)
+	{
+		*val = l -> exprvals[slot];
+		return 0;
+	}
+	
+	return 1;
+}
 
 void debug_message(int level, const char *fmt, ...)
 {
--- a/src/lwasm.h	Thu Jan 08 02:57:24 2009 +0000
+++ b/src/lwasm.h	Fri Jan 09 04:23:00 2009 +0000
@@ -62,6 +62,10 @@
 };
 
 // structure for keeping track of lines
+// it also as space for 4 expressions which is enough for all known
+// instructions and addressing modes
+// on pass 1, the expressions are parsed, on pass 2 they are re-evaluated
+// to determine constancy
 typedef struct lwasm_line_s lwasm_line_t;
 struct lwasm_line_s {
 	char *text;			// the actual text of the line
@@ -84,8 +88,9 @@
 	// the following are used for obj format - for external references, inter-section
 	// references, and intrasection relocations
 	int relocoff;		// offset into insn where relocation value goes
-	// the incomplete reference expression
-	lwasm_expr_stack_t *expr;
+	lwasm_expr_stack_t *exprs[4];	// non-constant expression values
+	int exprvals[4];	// constant expression values
+	char *exprends[4];	// pointer to character after end of expression
 };
 
 // for keeping track of symbols
@@ -175,8 +180,10 @@
 #define EXPR_PASS2CONST		2	// no undefined references on pass 2
 #define EXPR_BYTE			4	// the result must fit within 8 bits
 #define EXPR_COMPLEX		8	// a non-constant result is permitted (stored in l -> expr)
+#define EXPR_NOINTERSECT	16	// only allow intra-section values (pass 2)
 
 __lwasm_E__ int lwasm_expr_result(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val);
+__lwasm_E__ int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot);
 
 #undef __lwasm_E__
 
--- a/src/symbol.c	Thu Jan 08 02:57:24 2009 +0000
+++ b/src/symbol.c	Fri Jan 09 04:23:00 2009 +0000
@@ -35,6 +35,11 @@
 recognize because the expression evaluator must avoid all ambiguity in order
 to achieve predictable results. The checks here are simply a fuzz check.
 */
+
+/*
+NOTE: complex symbols always take their value from slot 0 on the expression placeholders
+for a line!
+*/
 int lwasm_register_symbol(asmstate_t *as, lwasm_line_t *l, char *sym, int val, int flags)
 {
 	lwasm_symbol_ent_t *se, *se2;
@@ -45,9 +50,9 @@
 	// if the symbol is constant, fall back to simple registration!
 	if (flags & SYMBOL_COMPLEX)
 	{
-		if (lwasm_expr_is_constant(l -> expr))
+		if (l -> exprs[0] == NULL)
 		{
-			val = lwasm_expr_get_value(l -> expr);
+			val = l -> exprvals[0];
 			flags &= ~SYMBOL_COMPLEX;
 		}
 	}
@@ -98,7 +103,7 @@
 		se -> value = val;
 		if (flags & SYMBOL_COMPLEX)
 		{
-			se -> expr = l -> expr;
+			se -> expr = l -> exprs[0];
 		}
 		return;
 	}
@@ -121,7 +126,7 @@
 	}
 	se -> value = val;
 	if (flags & SYMBOL_COMPLEX)
-		se -> expr = l -> expr;
+		se -> expr = l -> exprs[0];
 	se -> sym = lwasm_strdup(sym);
 	se -> context = scontext;
 	se -> sect = as -> csect;