diff lwasm/lwasm.c @ 432:58cafa61ab40

Add support for undocumented custom module format (for LW) Nothing to see here. Move along. These are not the droids you are looking for.
author William Astle <lost@l-w.ca>
date Fri, 18 Nov 2016 21:25:43 -0700
parents 5dc9f9d47064
children b1adf549d181
line wrap: on
line diff
--- a/lwasm/lwasm.c	Wed Nov 16 19:36:16 2016 -0700
+++ b/lwasm/lwasm.c	Fri Nov 18 21:25:43 2016 -0700
@@ -119,6 +119,10 @@
 		{
 //			sectiontab_t *s = priv;
 			asmstate_t *as = priv;
+			if (((sectiontab_t *)ptr) -> tbase != -1)
+			{
+				return lw_expr_build(lw_expr_type_int, ((sectiontab_t *)ptr) -> tbase);
+			}
 			if (as -> exportcheck && ptr == as -> csect)
 				return lw_expr_build(lw_expr_type_int, 0);
 			if (((sectiontab_t *)ptr) -> flags & section_flag_constant)
@@ -272,6 +276,7 @@
 		case E_SYMBOL_DUPE:				return "Multiply defined symbol";
 		case E_UNKNOWN_OPERATION:		return "Unknown operation";
 		case E_ORG_NOT_FOUND:			return "Previous ORG not found";
+		case E_COMPLEX_INCOMPLETE:      return "Incomplete expression too complex";
 		case E_USER_SPECIFIED:			return "User Specified:";
 
 		case W_ENDSTRUCT_WITHOUT:		return "ENDSTRUCT without STRUCT";
@@ -947,6 +952,47 @@
 		/* do nothing */ ;
 }
 
+struct auxdata {
+	int v;
+	int oc;
+	int ms;
+};
+
+int lwasm_emitexpr_auxlwmod(lw_expr_t expr, void *arg)
+{
+	struct auxdata *ad = arg;
+	if (lw_expr_istype(expr, lw_expr_type_int))
+	{
+		ad -> v = lw_expr_intval(expr);
+		return 0;
+	}
+	if (lw_expr_istype(expr, lw_expr_type_special))
+	{
+		if (lw_expr_specint(expr) == lwasm_expr_secbase)
+		{
+			sectiontab_t *s;
+			s = lw_expr_specptr(expr);
+			if (strcmp(s -> name, "main") == 0)
+			{
+				ad -> ms = 1;
+				return 0;
+			}
+			if (strcmp(s -> name, "bss"))
+				return -1;
+			return 0;
+		}
+		return -1;
+	}
+	if (lw_expr_whichop(expr) == lw_expr_oper_plus)
+	{
+		if (ad -> oc)
+			return -1;
+		ad -> oc = 1;
+		return 0;
+	}
+	return -1;
+}
+
 int lwasm_emitexpr(line_t *l, lw_expr_t expr, int size)
 {
 	int v = 0;
@@ -963,7 +1009,78 @@
 	// handle external/cross-section/incomplete references here
 	else
 	{
-		if (l -> as -> output_format == OUTPUT_OBJ)
+		if (l -> as -> output_format == OUTPUT_LWMOD)
+		{
+			reloctab_t *re;
+			lw_expr_t te;
+			struct auxdata ad;
+			ad.v = 0;
+			ad.oc = 0;
+			ad.ms = 0;
+			
+			if (l -> csect == NULL)
+			{
+				lwasm_register_error(l -> as, l, E_INSTRUCTION_SECTION);
+				return -1;
+			}
+			if (size != 2)
+			{
+				lwasm_register_error(l -> as, l, E_OPERAND_BAD);
+				return -1;
+			}
+			// we have a 16 bit reference here - we need to check to make sure
+			// it's at most a + or - with the BSS section base
+			v = lw_expr_whichop(expr);
+			if (v == -1)
+			{
+				v = 0;
+				if (lw_expr_testterms(expr, lwasm_emitexpr_auxlwmod, &ad) != 0)
+				{
+					lwasm_register_error(l -> as, l, E_COMPLEX_INCOMPLETE);
+					return -1;
+				}
+				v = ad.v;
+			}
+			else if (v == lw_expr_oper_plus)
+			{
+				v = 0;
+				if (lw_expr_operandcount(expr) > 2)
+				{
+					lwasm_register_error(l -> as, l, E_COMPLEX_INCOMPLETE);
+					return -1;
+				}
+				if (lw_expr_testterms(expr, lwasm_emitexpr_auxlwmod, &ad) != 0)
+				{
+					lwasm_register_error(l -> as, l, E_COMPLEX_INCOMPLETE);
+					return -1;
+				}
+				v = ad.v;
+			}
+			else
+			{
+				lwasm_register_error(l -> as, l, E_COMPLEX_INCOMPLETE);
+				return -1;
+			}
+
+			// add "expression" record to section table
+			re = lw_alloc(sizeof(reloctab_t));
+			re -> next = l -> csect -> reloctab;
+			l -> csect -> reloctab = re;
+			te = lw_expr_build(lw_expr_type_int, ol);
+			re -> offset = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, l -> addr, te);
+			lw_expr_destroy(te);
+			lwasm_reduce_expr(l -> as, re -> offset);
+			re -> size = size;
+			if (ad.ms == 1)
+				re -> expr = lw_expr_copy(expr);
+			else
+				re -> expr = NULL;
+
+			lwasm_emit(l, v >> 8);
+			lwasm_emit(l, v & 0xff);
+			return 0;
+		}
+		else if (l -> as -> output_format == OUTPUT_OBJ)
 		{
 			reloctab_t *re;
 			lw_expr_t te;