diff lwasm/output.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 9f0448022f1f
children 999ae00d0919
line wrap: on
line diff
--- a/lwasm/output.c	Wed Nov 16 19:36:16 2016 -0700
+++ b/lwasm/output.c	Fri Nov 18 21:25:43 2016 -0700
@@ -42,6 +42,7 @@
 void write_code_hex(asmstate_t *as, FILE *of);
 void write_code_srec(asmstate_t *as, FILE *of);
 void write_code_ihex(asmstate_t *as, FILE *of);
+void write_code_lwmod(asmstate_t *as, FILE *of);
 
 // this prevents warnings about not using the return value of fwrite()
 // r++ prevents the "set but not used" warnings; should be optimized out
@@ -103,6 +104,10 @@
 		write_code_ihex(as, of);
 		break;
 
+	case OUTPUT_LWMOD:
+		write_code_lwmod(as, of);
+		break;
+
 	default:
 		fprintf(stderr, "BUG: unrecognized output format when generating output file\n");
 		fclose(of);
@@ -1000,3 +1005,241 @@
 	// the "" is NOT an error
 	writebytes("", 1, 1, of);
 }
+
+
+void write_code_lwmod(asmstate_t *as, FILE *of)
+{
+	line_t *l;
+	sectiontab_t *s;
+	reloctab_t *re;
+	int initsize, bsssize, mainsize, callsnum, namesize;
+	unsigned char *initcode, *maincode, *callscode, *namecode;
+	int relocsize;
+	unsigned char *reloccode;
+	int tsize, bssoff;
+	int initaddr = -1;
+
+	int i;
+	unsigned char buf[16];
+
+	// the magic number
+	buf[0] = 0x8f;
+	buf[1] = 0xcf;
+	
+	// run through the entire system and build the byte streams for each
+	// section; we will make sure we only have simple references for
+	// any undefined references. That means at most an ADD (or SUB) operation
+	// with a single BSS symbol reference and a single constant value.
+	// We will use the constant value in the code stream and record the
+	// offset in a separate code stream for the BSS relocation table.
+	
+	// We build everything in memory here because we need to calculate the
+	// sizes of everything before we can output the complete header.
+	
+	for (l = as -> line_head; l; l = l -> next)
+	{
+		if (l -> csect)
+		{
+			// we're in a section - need to output some bytes
+			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 || l -> outputl == -1)
+				for (i = 0; i < l -> len; i++)
+					write_code_obj_sbadd(l -> csect, 0);
+		}
+	}
+	
+	// now run through sections and set various parameters
+	initsize = 0;
+	bsssize = 0;
+	mainsize = 0;
+	callsnum = 0;
+	callscode = NULL;
+	maincode = NULL;
+	initcode = NULL;
+	namecode = NULL;
+	namesize = 0;
+	relocsize = 0;
+	for (s = as -> sections; s; s = s -> next)
+	{
+		if (!strcmp(s -> name, "bss"))
+		{
+			bsssize = s -> oblen;
+		}
+		else if (!strcmp(s -> name, "main"))
+		{
+			maincode = s -> obytes;
+			mainsize = s -> oblen;
+		}
+		else if (!strcmp(s -> name, "init"))
+		{
+			initcode = s -> obytes;
+			initsize = s -> oblen;
+		}
+		else if (!strcmp(s -> name, "calls"))
+		{
+			callscode = s -> obytes;
+			callsnum = s -> oblen / 2;
+		}
+		else if (!strcmp(s -> name, "modname"))
+		{
+			namecode = s -> obytes;
+			namesize = 0;
+		}
+		for (re = s -> reloctab; re; re = re -> next)
+		{
+			if (re -> expr == NULL)
+				relocsize += 2;
+		}
+	}
+	if (namesize == 0)
+	{
+		namecode = (unsigned char *)(as -> output_file);
+	}
+	else
+	{
+		if (namecode[namesize - 1] != '\0')
+		{
+			namecode[namesize - 1] = '\0';
+		}
+		if (!*namecode)
+			namecode = (unsigned char *)(as -> output_file);
+	}
+	namesize = strlen((char *)namecode);
+
+	tsize = namesize + 1 + initsize + mainsize + callsnum * 2 + relocsize + 11;
+	bssoff = namesize + 1 + mainsize + callsnum * 2 + 11;
+	// set up section base addresses
+	for (s = as -> sections; s; s = s -> next)
+	{
+		if (!strcmp(s -> name, "main"))
+		{
+			s -> tbase = 11 + namesize + 1 + callsnum * 2;
+		}
+		else if (!strcmp(s -> name, "init"))
+		{
+			s -> tbase = bssoff + relocsize;
+		}
+		else if (!strcmp(s -> name, "calls"))
+		{
+			s -> tbase = 11;
+		}
+		else if (!strcmp(s -> name, "modname"))
+		{
+			s -> tbase = 11 + callsnum * 2;
+		}
+	}
+
+	// resolve the "init" address
+	if (as -> execaddr_expr)
+	{
+		// need to resolve address with proper section bases
+		lwasm_reduce_expr(as, as -> execaddr_expr);
+		initaddr = lw_expr_intval(as -> execaddr_expr);
+	}
+	else
+	{
+		initaddr = as -> execaddr;
+	}
+	
+	// build relocation data
+	reloccode = NULL;
+	if (relocsize)
+	{
+		unsigned char *tptr;
+		reloccode = lw_alloc(relocsize);
+		tptr = reloccode;
+		
+		for (s = as -> sections; s; s = s -> next)
+		{
+			for (re = s -> reloctab; re; re = re -> next)
+			{
+				lw_expr_t te;
+				line_t tl;
+				int offset;
+			
+				tl.as = as;
+				as -> cl = &tl;
+				as -> csect = s;
+//				as -> exportcheck = 1;
+
+				if (re -> expr)
+				{
+					int val;
+					int x;
+					
+					te = lw_expr_copy(re -> expr);
+					lwasm_reduce_expr(as, te);
+					if (!lw_expr_istype(te, lw_expr_type_int))
+					{
+						val = 0;
+					}
+					else
+					{
+						val = lw_expr_intval(te);
+					}
+					lw_expr_destroy(te);
+					x = s -> tbase;
+					s -> tbase = 0;
+					te = lw_expr_copy(re -> offset);
+					lwasm_reduce_expr(as, te);
+					offset = lw_expr_intval(te);
+					lw_expr_destroy(te);
+					s -> tbase = x;
+					// offset *should* be the offset in the section
+					s -> obytes[offset] = val >> 8;
+					s -> obytes[offset + 1] = val & 0xff;
+					continue;
+				}
+				
+				offset = 0;
+				te = lw_expr_copy(re -> offset);
+				lwasm_reduce_expr(as, te);
+				if (!lw_expr_istype(te, lw_expr_type_int))
+				{
+					lw_expr_destroy(te);
+					offset = 0;
+					continue;
+				}
+				offset = lw_expr_intval(te);
+				lw_expr_destroy(te);
+				//offset += sbase;
+				
+				*tptr++ = offset >> 8;
+				*tptr++ = offset & 0xff;
+			}
+		}
+	}
+
+	// total size
+	buf[2] = tsize >> 8;
+	buf[3] = tsize & 0xff;
+	// offset to BSS relocs
+	buf[4] = bssoff >> 8;
+	buf[5] = bssoff & 0xff;
+	// BSS size
+	buf[6] = bsssize >> 8;
+	buf[7] = bsssize & 0xff;
+	// init routine offset
+	buf[8] = initaddr >> 8;
+	buf[9] = initaddr & 0xff;
+	// number of call entries
+	buf[10] = callsnum;
+	// write the header
+	writebytes(buf, 11, 1, of);
+	// call data
+	if (callsnum)
+		writebytes(callscode, callsnum * 2, 1, of);
+	// module name
+	writebytes(namecode, namesize + 1, 1, of);
+	// main code
+	if (mainsize)
+		writebytes(maincode, mainsize, 1, of);
+	// bss relocs
+	if (relocsize)
+		writebytes(reloccode, relocsize, 1, of);
+	// init stuff
+	if (initsize)
+		writebytes(initcode, initsize, 1, of);
+}