changeset 387:a741d2e4869f

Various bugfixes; fixed lwobjdump to display symbols with unprintable characters more sensibly; start of a (nonfunctional for now) testing framework
author lost@l-w.ca
date Wed, 14 Jul 2010 20:15:23 -0600
parents af5f2c51db76
children 8991eb507d2d
files lwasm/list.c lwasm/lwasm.c lwasm/lwasm.h lwasm/main.c lwasm/output.c lwasm/pass4.c lwasm/pseudo.c lwasm/section.c lwlib/lw_expr.c lwlib/lw_expr.h lwlink/objdump.c m4/gnulib-cache.m4 test/README test/lwasm.t/README test/runtests.sh
diffstat 15 files changed, 303 insertions(+), 92 deletions(-) [+]
line wrap: on
line diff
--- a/lwasm/list.c	Sun May 16 13:03:17 2010 -0600
+++ b/lwasm/list.c	Wed Jul 14 20:15:23 2010 -0600
@@ -59,7 +59,13 @@
 		}
 		else
 		{
-			fprintf(of, "%04X ", lw_expr_intval(cl -> addr));
+			lw_expr_t te;
+			te = lw_expr_copy(cl -> addr);
+			as -> exportcheck = 1;
+			lwasm_reduce_expr(as, te);
+			as -> exportcheck = 0;
+			fprintf(of, "%04X ", lw_expr_intval(te) & 0xffff);
+			lw_expr_destroy(te);
 			for (i = 0; i < cl -> outputl && i < 8; i++)
 			{
 				fprintf(of, "%02X", cl -> output[i]);
@@ -84,6 +90,8 @@
 				}
 				fprintf(of, "%02X", cl -> output[i]);
 			}
+			if (i % 8)
+				fprintf(of, "\n");
 		}
 	}
 }
--- a/lwasm/lwasm.c	Sun May 16 13:03:17 2010 -0600
+++ b/lwasm/lwasm.c	Wed Jul 14 20:15:23 2010 -0600
@@ -781,3 +781,57 @@
 		fprintf(stderr, "  LINE: %s\n", cl -> ltext);
 	}
 }
+
+/*
+this does any passes and other gymnastics that might be useful
+to see if an expression reduces early
+*/
+extern void do_pass3(asmstate_t *as);
+extern void do_pass4_aux(asmstate_t *as, int force);
+
+void lwasm_interim_reduce(asmstate_t *as)
+{
+	do_pass3(as);
+//	do_pass4_aux(as, 0);
+}
+
+lw_expr_t lwasm_parse_cond(asmstate_t *as, char **p)
+{
+	lw_expr_t e;
+
+	debug_message(as, 250, "Parsing condition");
+	e = lwasm_parse_expr(as, p);
+	debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+	
+	if (!e)
+	{
+		lwasm_register_error(as, as -> cl, "Bad expression");
+		return NULL;
+	}
+
+	/* we need to simplify the expression here */
+	debug_message(as, 250, "Doing interim reductions");
+	lwasm_interim_reduce(as);
+	debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+	debug_message(as, 250, "Reducing expression");
+	lwasm_reduce_expr(as, e);
+	debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+/*	lwasm_reduce_expr(as, e);
+	debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+	lwasm_reduce_expr(as, e);
+	debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+	lwasm_reduce_expr(as, e);
+	debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+*/
+
+	lwasm_save_expr(as -> cl, 4242, e);
+
+	if (!lw_expr_istype(e, lw_expr_type_int))
+	{
+		debug_message(as, 250, "Non-constant expression");
+		lwasm_register_error(as, as -> cl, "Conditions must be constant on pass 1");
+		return NULL;
+	}
+	debug_message(as, 250, "Returning expression");
+	return e;
+}
--- a/lwasm/lwasm.h	Sun May 16 13:03:17 2010 -0600
+++ b/lwasm/lwasm.h	Wed Jul 14 20:15:23 2010 -0600
@@ -275,6 +275,7 @@
 extern void debug_message(asmstate_t *as, int level, const char *fmt, ...);
 extern void dump_state(asmstate_t *as);
 
+extern lw_expr_t lwasm_parse_cond(asmstate_t *as, char **p);
 
 #endif
 
--- a/lwasm/main.c	Sun May 16 13:03:17 2010 -0600
+++ b/lwasm/main.c	Wed Jul 14 20:15:23 2010 -0600
@@ -260,4 +260,6 @@
 	debug_message(&asmstate, 50, "Done assembly");
 	
 	do_list(&asmstate);
+	
+	exit(0);
 }
--- a/lwasm/output.c	Sun May 16 13:03:17 2010 -0600
+++ b/lwasm/output.c	Wed Jul 14 20:15:23 2010 -0600
@@ -243,7 +243,7 @@
 	{
 	case lw_expr_type_oper:
 		buf[0] =  0x04;
-		switch (lw_expr_intval(e))
+		switch (lw_expr_whichop(e))
 		{
 		case lw_expr_oper_plus:
 			buf[1] = 0x01;
@@ -301,7 +301,7 @@
 			buf[1] = 0xff;
 		}
 		writebytes(buf, 2, 1, of);
-		break;
+		return 0;
 
 	case lw_expr_type_int:
 		v = lw_expr_intval(e);
@@ -309,7 +309,7 @@
 		buf[1] = (v >> 8) & 0xff;
 		buf[2] = v & 0xff;
 		writebytes(buf, 3, 1, of);
-		break;
+		return 0;
 		
 	case lw_expr_type_special:
 		v = lw_expr_specint(e);
@@ -321,9 +321,9 @@
 				sectiontab_t *se;
 				se = lw_expr_specptr(e);
 				
-				writebytes("\x03\x02", 1, 1, of);
+				writebytes("\x03\x02", 2, 1, of);
 				writebytes(se -> name, strlen(se -> name) + 1, 1, of);
-				break;
+				return 0;
 			}	
 		case lwasm_expr_import:
 			{
@@ -332,7 +332,7 @@
 				buf[0] = 0x02;
 				writebytes(buf, 1, 1, of);
 				writebytes(ie -> symbol, strlen(ie -> symbol) + 1, 1, of);
-				break;
+				return 0;
 			}
 		case lwasm_expr_syment:
 			{
@@ -347,13 +347,13 @@
 					writebytes(buf, strlen(buf), 1, of);
 				}
 				writebytes("", 1, 1, of);
-				break;
+				return 0;
 			}
-			break;
 		}
 			
 	default:
 		// unrecognized term type - replace with integer 0
+//		fprintf(stderr, "Unrecognized term type: %s\n", lw_expr_print(e));
 		buf[0] = 0x01;
 		buf[1] = 0x00;
 		buf[2] = 0x00;
@@ -408,7 +408,7 @@
 			if (l -> outputl > 0)
 				for (i = 0; i < l -> outputl; i++)
 					write_code_obj_sbadd(l -> csect, l -> output[i]);
-			else if (l -> outputl == 0)
+			else if (l -> outputl == 0 || l -> outputl == -1)
 				for (i = 0; i < l -> len; i++)
 					write_code_obj_sbadd(l -> csect, 0);
 		}
@@ -432,6 +432,8 @@
 		// a symbol for section base address
 		writebytes("\x02", 1, 1, of);
 		writebytes(s -> name, strlen(s -> name) + 1, 1, of);
+		// address 0; "\0" is not an error
+		writebytes("\0", 2, 1, of);
 		for (se = as -> symtab.head; se; se = se -> next)
 		{
 			// ignore symbols not in this section
@@ -525,7 +527,7 @@
 				writebytes(buf, 2, 1, of);
 			}
 			
-			te = lw_expr_copy(ex -> se -> value);
+			te = lw_expr_copy(re -> offset);
 			lwasm_reduce_expr(as, te);
 			if (!lw_expr_istype(te, lw_expr_type_int))
 			{
--- a/lwasm/pass4.c	Sun May 16 13:03:17 2010 -0600
+++ b/lwasm/pass4.c	Wed Jul 14 20:15:23 2010 -0600
@@ -36,7 +36,7 @@
 Force resolution of instruction sizes.
 
 */
-void do_pass4(asmstate_t *as)
+void do_pass4_aux(asmstate_t *as, int force)
 {
 	int rc;
 	int cnt;
@@ -76,7 +76,7 @@
 		if (sl -> len == -1 && sl -> insn >= 0 && instab[sl -> insn].resolve)
 		{
 			(instab[sl -> insn].resolve)(as, sl, 1);
-			if (sl -> len == -1)
+			if (force && sl -> len == -1)
 			{
 				lwasm_register_error(as, sl, "Instruction failed to resolve.");
 				return;
@@ -122,3 +122,8 @@
 		} while (rc > 0);
 	}
 }
+
+void do_pass4(asmstate_t *as)
+{
+	do_pass4_aux(as, 1);
+}
--- a/lwasm/pseudo.c	Sun May 16 13:03:17 2010 -0600
+++ b/lwasm/pseudo.c	Wed Jul 14 20:15:23 2010 -0600
@@ -657,18 +657,8 @@
 		return;
 	}
 
-	e = lwasm_parse_expr(as, p);
-	if (!e)
-	{
-		lwasm_register_error(as, l, "Bad expression");
-		return;
-	}
-	if (!lw_expr_istype(e, lw_expr_type_int))
-	{
-		lwasm_register_error(as, l, "Conditions must be constant on pass 1");
-		return;
-	}
-	if (lw_expr_intval(e) != 0)
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) != 0)
 	{
 		as -> skipcond = 1;
 		as -> skipcount = 1;
@@ -688,18 +678,8 @@
 		return;
 	}
 
-	e = lwasm_parse_expr(as, p);
-	if (!e)
-	{
-		lwasm_register_error(as, l, "Bad expression");
-		return;
-	}
-	if (!lw_expr_istype(e, lw_expr_type_int))
-	{
-		lwasm_register_error(as, l, "Conditions must be constant on pass 1");
-		return;
-	}
-	if (lw_expr_intval(e) == 0)
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) == 0)
 	{
 		as -> skipcond = 1;
 		as -> skipcount = 1;
@@ -720,18 +700,8 @@
 		return;
 	}
 
-	e = lwasm_parse_expr(as, p);
-	if (!e)
-	{
-		lwasm_register_error(as, l, "Bad expression");
-		return;
-	}
-	if (!lw_expr_istype(e, lw_expr_type_int))
-	{
-		lwasm_register_error(as, l, "Conditions must be constant on pass 1");
-		return;
-	}
-	if (lw_expr_intval(e) <= 0)
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) <= 0)
 	{
 		as -> skipcond = 1;
 		as -> skipcount = 1;
@@ -751,18 +721,8 @@
 		return;
 	}
 
-	e = lwasm_parse_expr(as, p);
-	if (!e)
-	{
-		lwasm_register_error(as, l, "Bad expression");
-		return;
-	}
-	if (!lw_expr_istype(e, lw_expr_type_int))
-	{
-		lwasm_register_error(as, l, "Conditions must be constant on pass 1");
-		return;
-	}
-	if (lw_expr_intval(e) < 0)
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) < 0)
 	{
 		as -> skipcond = 1;
 		as -> skipcount = 1;
@@ -782,18 +742,8 @@
 		return;
 	}
 
-	e = lwasm_parse_expr(as, p);
-	if (!e)
-	{
-		lwasm_register_error(as, l, "Bad expression");
-		return;
-	}
-	if (!lw_expr_istype(e, lw_expr_type_int))
-	{
-		lwasm_register_error(as, l, "Conditions must be constant on pass 1");
-		return;
-	}
-	if (lw_expr_intval(e) >= 0)
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) >= 0)
 	{
 		as -> skipcond = 1;
 		as -> skipcount = 1;
@@ -813,18 +763,8 @@
 		return;
 	}
 
-	e = lwasm_parse_expr(as, p);
-	if (!e)
-	{
-		lwasm_register_error(as, l, "Bad expression");
-		return;
-	}
-	if (!lw_expr_istype(e, lw_expr_type_int))
-	{
-		lwasm_register_error(as, l, "Conditions must be constant on pass 1");
-		return;
-	}
-	if (lw_expr_intval(e) > 0)
+	e = lwasm_parse_cond(as, p);
+	if (e && lw_expr_intval(e) > 0)
 	{
 		as -> skipcond = 1;
 		as -> skipcount = 1;
--- a/lwasm/section.c	Sun May 16 13:03:17 2010 -0600
+++ b/lwasm/section.c	Wed Jul 14 20:15:23 2010 -0600
@@ -48,6 +48,8 @@
 		return;
 	}
 
+	l -> len = 0;
+
 	if (as -> csect)
 	{
 		lw_expr_destroy(as -> csect -> offset);
@@ -86,9 +88,13 @@
 	{
 		// create section data structure
 		s = lw_alloc(sizeof(sectiontab_t));
+		s -> oblen = 0;
+		s -> obsize = 0;
+		s -> obytes = NULL;
 		s -> name = lw_strdup(sn);
 		s -> offset = lw_expr_build(lw_expr_type_special, lwasm_expr_secbase, s);
 		s -> flags = section_flag_none;
+		s -> reloctab = NULL;
 		if (!strcasecmp(sn, "bss") || !strcasecmp(sn, ".bss"))
 		{
 			s -> flags |= section_flag_bss;
@@ -140,6 +146,8 @@
 		return;
 	}
 
+	l -> len = 0;
+
 	if (!(as -> csect))
 	{
 		lwasm_register_error(as, l, "ENDSECTION without SECTION");
@@ -171,6 +179,8 @@
 		lwasm_register_error(as, l, "EXPORT only supported for object target");
 		return;
 	}
+
+	l -> len = 0;
 	
 	if (l -> sym)
 	{
@@ -232,6 +242,8 @@
 		return;
 	}
 	
+	l -> len = 0;
+	
 	if (l -> sym)
 	{
 		sym = lw_strdup(l -> sym);
@@ -296,6 +308,8 @@
 		return;
 	}
 	
+	l -> len = 0;
+	
 	if (l -> sym)
 		sym = lw_strdup(l -> sym);
 	
--- a/lwlib/lw_expr.c	Sun May 16 13:03:17 2010 -0600
+++ b/lwlib/lw_expr.c	Wed Jul 14 20:15:23 2010 -0600
@@ -49,6 +49,13 @@
 	return -1;
 }
 
+int lw_expr_whichop(lw_expr_t e)
+{
+	if (e -> type == lw_expr_type_oper)
+		return e -> value;
+	return -1;
+}
+
 int lw_expr_specint(lw_expr_t e)
 {
 	if (e -> type == lw_expr_type_special)
@@ -198,7 +205,12 @@
 	struct lw_expr_opers *o;
 	int c = 0;
 	char buf[256];
-			
+
+	if (!E)
+	{
+		strcpy(buf, "(NULL)");
+		return;
+	}
 	for (o = E -> operands; o; o = o -> next)
 	{
 		c++;
@@ -463,7 +475,9 @@
 	return 1;
 }
 
-void lw_expr_simplify(lw_expr_t E, void *priv)
+void lw_expr_simplify(lw_expr_t E, void *priv);
+
+void lw_expr_simplify_go(lw_expr_t E, void *priv)
 {
 	struct lw_expr_opers *o;
 
@@ -920,8 +934,80 @@
 		}
 		return;
 	}
+	
+	/* handle <int> times <plus> - expand the terms - only with exactly two operands */
+	if (E -> value == lw_expr_oper_times)
+	{
+		lw_expr_t t1;
+		lw_expr_t E2;
+		lw_expr_t E3;
+		if (E -> operands && E -> operands -> next && !(E -> operands -> next -> next))
+		{
+			if (E -> operands -> p -> type  == lw_expr_type_int)
+			{
+				/* <int> TIMES <other> */
+				E2 = E -> operands -> next -> p;
+				E3 = E -> operands -> p;
+				if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus)
+				{
+					lw_free(E -> operands -> next);
+					lw_free(E -> operands);
+					E -> operands = NULL;
+					E -> value = lw_expr_oper_plus;
+					
+					for (o = E2 -> operands; o; o = o -> next)
+					{
+						t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p);
+						lw_expr_add_operand(E, t1);
+					}
+					
+					lw_expr_destroy(E2);
+					lw_expr_destroy(E3);
+				}
+			}
+			else if (E -> operands -> next -> p -> type == lw_expr_type_int)
+			{
+				/* <other> TIMES <int> */
+				E2 = E -> operands -> p;
+				E3 = E -> operands -> next -> p;
+				if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus)
+				{
+					lw_free(E -> operands -> next);
+					lw_free(E -> operands);
+					E -> operands = NULL;
+					E -> value = lw_expr_oper_plus;
+					
+					for (o = E2 -> operands; o; o = o -> next)
+					{
+						t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p);
+						lw_expr_add_operand(E, t1);
+					}
+					
+					lw_expr_destroy(E2);
+					lw_expr_destroy(E3);
+				}
+			}
+		}
+	}
 }
 
+void lw_expr_simplify(lw_expr_t E, void *priv)
+{
+	lw_expr_t te;
+	int c;
+	do
+	{
+		te = lw_expr_copy(E);
+		lw_expr_simplify_go(E, priv);
+		c = 0;
+		if (lw_expr_compare(te, E) == 0)
+			c = 1;
+		lw_expr_destroy(te);
+	}
+	while (c);
+}
+
+
 /*
 
 The following two functions are co-routines which evaluate an infix
--- a/lwlib/lw_expr.h	Sun May 16 13:03:17 2010 -0600
+++ b/lwlib/lw_expr.h	Wed Jul 14 20:15:23 2010 -0600
@@ -99,6 +99,7 @@
 extern int lw_expr_intval(lw_expr_t e);
 extern int lw_expr_specint(lw_expr_t e);
 extern void *lw_expr_specptr(lw_expr_t e);
+extern int lw_expr_whichop(lw_expr_t e);
 
 extern int lw_expr_type(lw_expr_t e);
 
--- a/lwlink/objdump.c	Sun May 16 13:03:17 2010 -0600
+++ b/lwlink/objdump.c	Wed Jul 14 20:15:23 2010 -0600
@@ -34,6 +34,42 @@
 void read_lwobj16v0(unsigned char *filedata, long filesize);
 char *program_name;
 
+char *string_cleanup(char *sym)
+{
+	static char symbuf[4096];
+	int optr = 0;
+	while (*sym)
+	{
+		if (*sym < 33 || *sym > 126)
+		{
+			int c;
+			symbuf[optr++] = '\\';
+			c = *sym >> 4;
+			c+= 48;
+			if (c > 57)
+				c += 7;
+			symbuf[optr++] = c;
+			c = *sym & 15;
+			c += 48;
+			if (c > 57)
+				c += 7;
+			symbuf[optr++] = c;
+		}
+		else if (*sym == '\\')
+		{
+			symbuf[optr++] = '\\';
+			symbuf[optr++] = '\\';
+		}
+		else
+		{
+			symbuf[optr++] = *sym;
+		}
+		sym++;
+	}
+	symbuf[optr] = '\0';
+	return symbuf;
+}
+
 /*
 The logic of reading the entire file into memory is simple. All the symbol
 names in the file are NUL terminated strings and can be used directly without
@@ -185,7 +221,7 @@
 			NEXTBYTE();
 			// val is now the symbol value
 			
-			printf("        %s=%04X\n", fp, val);
+			printf("        %s=%04X\n", string_cleanup(fp), val);
 			
 		}
 		// skip terminating NUL
@@ -205,7 +241,7 @@
 			NEXTBYTE();
 			// val is now the symbol value
 			
-			printf("        %s=%04X\n", fp, val);
+			printf("        %s=%04X\n", string_cleanup(fp), val);
 		}
 		// skip terminating NUL
 		NEXTBYTE();
@@ -237,12 +273,12 @@
 				
 				case 0x02:
 					// external symbol reference
-					printf(" ES=%s", CURSTR());
+					printf(" ES=%s", string_cleanup(CURSTR()));
 					break;
 					
 				case 0x03:
 					// internal symbol reference
-					printf(" IS=%s", CURSTR());
+					printf(" IS=%s", string_cleanup(CURSTR()));
 					break;
 				
 				case 0x04:
--- a/m4/gnulib-cache.m4	Sun May 16 13:03:17 2010 -0600
+++ b/m4/gnulib-cache.m4	Wed Jul 14 20:15:23 2010 -0600
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2009 Free Software Foundation, Inc.
+# Copyright (C) 2002-2010 Free Software Foundation, Inc.
 #
 # This file is free software, distributed under the terms of the GNU
 # General Public License.  As a special exception to the GNU General
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/README	Wed Jul 14 20:15:23 2010 -0600
@@ -0,0 +1,11 @@
+This folder contains various schemes for testing LWTOOLS. The tests are
+undocumented and will remain so unless someone wishes to create
+documentation for them. They are also specific to LWTOOLS.
+
+In general, a test should be created every time a bug is discovered; that
+test should fail if the bug is found. No test need be created if another
+test already covers the bug in question.
+
+Before any release is made, the test suite should be run to ensure there are
+no regressions. This will not guarantee that there are no new bugs, but it
+should prevent old bugs from creeping in again.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lwasm.t/README	Wed Jul 14 20:15:23 2010 -0600
@@ -0,0 +1,1 @@
+This directory contains various tests for the lwasm program itself.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtests.sh	Wed Jul 14 20:15:23 2010 -0600
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# run the various tests under the tests/ folder recursively
+
+function runtests()
+{
+	local fn
+	local base="$2"
+	local odir=`pwd`
+	local dir="$1"
+	
+	cd "$dir"
+
+	for fn in *.t; do
+		if [ -d "$fn" ]; then
+			echo "Running tests in $base/$fn"
+			runtests "$fn" "$base/$fn"
+		elif [ -r "$fn" ]; then
+			echo "Running test $fn"
+			testcount=$(($testcount+1))
+			TESTSTATE=failed
+			source "$fn"
+			if [ "$TESTSTATE" = ok ]; then
+				testpassed=$(($testpassed+1))
+			else
+				testfailed=$(($testfailed+1))
+			fi
+		fi
+	done
+	
+	cd "$odir"
+}
+
+testcount=0
+testfailed=0
+testpassed=0
+
+dir="$1"
+if [ "x$dir" = "x" ]; then
+	dir=.
+fi
+
+runtests "$dir" "$dir"
+
+echo "Passed $testpassed tests of $testcount"
+if [ "$testfailed" -ne 0 ]; then
+	echo "Failed $testfailed of $testcount tests!"
+	exit 1
+fi
+exit 0