changeset 148:08fb11004df9

Initial pass at OS9 module support for lwlink
author lost@l-w.ca
date Fri, 26 Aug 2011 23:26:00 -0600
parents 9cf1796259b2
children 729a9c70934e
files lwlink/link.c lwlink/lwlink.h lwlink/main.c lwlink/output.c lwlink/script.c
diffstat 5 files changed, 260 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/lwlink/link.c	Thu Aug 25 22:29:58 2011 -0600
+++ b/lwlink/link.c	Fri Aug 26 23:26:00 2011 -0600
@@ -30,6 +30,8 @@
 #include "expr.h"
 #include "lwlink.h"
 
+void check_os9(void);
+
 struct section_list *sectlist = NULL;
 int nsects = 0;
 static int nforced = 0;
@@ -390,6 +392,9 @@
 	
 	if (symerr)
 		exit(1);
+	
+	if (outformat == OUTPUT_OS9)
+		check_os9();	
 }
 
 /*
@@ -460,3 +465,106 @@
 		fprintf(stderr, "Warning: %s (%d) does not resolve any symbols\n", inputfiles[fn] -> filename, fn);
 	}
 }
+void find_section_by_name_once_aux(char *name, fileinfo_t *fn, section_t **rval, int *found);
+void find_section_by_name_once_aux(char *name, fileinfo_t *fn, section_t **rval, int *found)
+{
+	int sn;
+	
+	if (fn -> forced == 0)
+		return;
+
+	for (sn = 0; sn < fn -> nsections; sn++)
+	{
+		if (!strcmp(name, (char *)(fn -> sections[sn].name)))
+		{
+			(*found)++;
+			*rval = &(fn -> sections[sn]);
+		}
+	}
+	for (sn = 0; sn < fn -> nsubs; sn++)
+	{
+		find_section_by_name_once_aux(name, fn -> subs[sn], rval, found);
+	}
+}
+
+section_t *find_section_by_name_once(char *name)
+{
+	int fn;
+	int found = 0;
+	section_t *rval = NULL;
+	
+	for (fn = 0; fn < ninputfiles; fn++)
+	{
+		find_section_by_name_once_aux(name, inputfiles[fn], &rval, &found);
+	}
+	if (found != 1)
+	{
+		rval = NULL;
+		fprintf(stderr, "Warning: multiple instances of section %s found; ignoring all of them which is probably not what you want\n", name);
+	}
+	return rval;
+}
+
+void check_os9(void)
+{
+	section_t *s;
+	symtab_t *sym;
+	
+	s = find_section_by_name_once("__os9");
+	linkscript.name = outfile;
+	
+	if (!s)
+	{
+		// use defaults if not found
+		return;
+	}	
+
+	// this section is special
+	// several symbols may be defined as LOCAL symbols:
+	// type: module type
+	// lang: module language
+	// attr: module attributes
+	// rev: module revision
+	//
+	// the symbols are not case sensitive
+	//
+	// any unrecognized symbols are ignored
+	
+	// the contents of the actual data to the first NUL
+	// is assumed to be the module name unless it is an empty string
+	if (s -> codesize > 0 && (s -> flags & SECTION_BSS) == 0 && s -> code[0] != 0)
+	{
+		linkscript.name = (char *)(s -> code);
+	}
+	
+	for (sym = s -> localsyms; s; sym = sym -> next)
+	{
+		char *sm = (char *)(sym -> sym);
+		if (!strcasecmp(sm, "type"))
+		{
+			linkscript.modtype = sym -> offset;
+		}
+		else if (!strcasecmp(sm, "lang"))
+		{
+			linkscript.modlang = sym -> offset;
+		}
+		else if (!strcasecmp(sm, "attr"))
+		{
+			linkscript.modlang = sym -> offset;
+		}
+		else if (!strcasecmp(sm, "rev"))
+		{
+			linkscript.modrev = sym -> offset;
+		}
+	}
+	if (linkscript.modtype > 15)
+		linkscript.modtype = linkscript.modtype >> 4;
+	
+	if (linkscript.modattr > 15)
+		linkscript.modattr = linkscript.modattr >> 4;
+	
+	linkscript.modlang &= 15;
+	linkscript.modtype &= 15;
+	linkscript.modrev &= 15;
+	linkscript.modattr &= 15;
+}
--- a/lwlink/lwlink.h	Thu Aug 25 22:29:58 2011 -0600
+++ b/lwlink/lwlink.h	Fri Aug 26 23:26:00 2011 -0600
@@ -29,6 +29,7 @@
 #define OUTPUT_DECB		0	// DECB multirecord format
 #define OUTPUT_RAW		1	// raw sequence of bytes
 #define OUTPUT_LWEX0	2	// LWOS LWEX binary version 0
+#define OUTPUT_OS9		3	// OS9 object code module
 
 typedef struct symtab_s symtab_t;
 struct symtab_s
@@ -147,6 +148,11 @@
 	char *execsym;				// entry point symbol
 	int execaddr;				// execution address (entry point)
 	int stacksize;				// stack size
+	int modtype;				// module type
+	int modlang;				// module language
+	int modattr;				// module attributes
+	int modrev;					// module revision
+	char *name;					// module name
 } linkscript_t;
 
 #ifndef __script_c_seen__
--- a/lwlink/main.c	Thu Aug 25 22:29:58 2011 -0600
+++ b/lwlink/main.c	Fri Aug 26 23:26:00 2011 -0600
@@ -74,6 +74,8 @@
 			outformat = OUTPUT_RAW;
 		else if (!strcasecmp(arg, "lwex0") || !strcasecmp(arg, "lwex"))
 			outformat = OUTPUT_LWEX0;
+		else if (!strcasecmp(arg, "os9"))
+			outformat = OUTPUT_OS9;
 		else
 		{
 			fprintf(stderr, "Invalid output format: %s\n", arg);
@@ -119,7 +121,7 @@
 	{ "debug",		'd',	0,		0,
 				"Set debug mode"},
 	{ "format",		'f',	"TYPE",	0,
-				"Select output format: decb, raw, lwex"},
+				"Select output format: decb, raw, lwex, os9"},
 	{ "decb",		'b',	0,		0,
 				"Generate DECB .bin format output, equivalent of --format=decb"},
 	{ "raw",		'r',	0,		0,
--- a/lwlink/output.c	Thu Aug 25 22:29:58 2011 -0600
+++ b/lwlink/output.c	Fri Aug 26 23:26:00 2011 -0600
@@ -32,6 +32,7 @@
 // better in the future
 #define writebytes(s, l, c, f)	do { int r; r = fwrite((s), (l), (c), (f)); } while (0)
 
+void do_output_os9(FILE *of);
 void do_output_decb(FILE *of);
 void do_output_raw(FILE *of);
 void do_output_lwex0(FILE *of);
@@ -62,6 +63,10 @@
 		do_output_lwex0(of);
 		break;
 	
+	case OUTPUT_OS9:
+		do_output_os9(of);
+		break;
+		
 	default:
 		fprintf(stderr, "Unknown output format doing output!\n");
 		exit(111);
@@ -213,3 +218,118 @@
 		writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of);
 	}
 }
+
+void os9crc(unsigned char crc[3], unsigned char b)
+{
+	b ^= crc[0];
+	crc[0] = crc[1];
+	crc[1] = crc[2];
+	crc[1] ^= b >> 7;
+	crc[2] = b << 1;
+	crc[1] ^= b >> 2;
+	crc[2] ^= b << 6;
+	b ^= b << 1;
+	b ^= b << 2;
+	b ^= b << 4;
+	if (b & 0x80)
+	{
+		crc[0] ^= 0x80;
+		crc[2] ^= 0x21;
+	}
+}
+ 
+
+void do_output_os9(FILE *of)
+{
+	int sn;
+	int codedatasize = 0;
+	int bsssize = 0;
+	int i;
+		
+	unsigned char buf[16];
+	unsigned char crc[3];
+	
+	// calculate items for the file header
+	for (sn = 0; sn < nsects; sn++)
+	{
+		if (sectlist[sn].ptr -> flags & SECTION_BSS)
+		{
+			// no output for a BSS section
+			bsssize += sectlist[sn].ptr -> codesize;
+			continue;
+		}
+		codedatasize += sectlist[sn].ptr -> codesize;
+	}
+
+	// now bss size is the data size for the module
+	// and codesize is the length of the module minus the module header
+	// and CRC
+
+	codedatasize += 16; // add in headers
+	codedatasize += strlen(linkscript.name); // add in name length
+	
+	// output the file header
+	buf[0] = 0x87;
+	buf[1] = 0xCD;
+	buf[2] = (codedatasize >> 8) & 0xff;
+	buf[3] = codedatasize & 0xff;
+	buf[4] = 0;
+	buf[5] = 13;
+	buf[6] = (linkscript.modtype << 4) | (linkscript.modlang);
+	buf[7] = (linkscript.modattr << 4) | (linkscript.modrev);
+	buf[8] = (~(buf[0] ^ buf[1] ^ buf[2] ^ buf[3] ^ buf[4] ^ buf[5] ^ buf[6] ^ buf[7])) & 0xff;
+	buf[9] = (linkscript.execaddr >> 8) & 0xff;
+	buf[10] = linkscript.execaddr & 0xff;
+	buf[11] = (bsssize >> 8) & 0xff;
+	buf[12] = bsssize & 0xff;
+	
+	crc[0] = 0xff;
+	crc[1] = 0xff;
+	crc[2] = 0xff;
+	
+	os9crc(crc, buf[0]);
+	os9crc(crc, buf[1]);
+	os9crc(crc, buf[2]);
+	os9crc(crc, buf[3]);
+	os9crc(crc, buf[4]);
+	os9crc(crc, buf[5]);
+	os9crc(crc, buf[6]);
+	os9crc(crc, buf[7]);
+	os9crc(crc, buf[8]);
+	os9crc(crc, buf[9]);
+	os9crc(crc, buf[10]);
+	os9crc(crc, buf[11]);
+	os9crc(crc, buf[12]);
+	
+	
+	writebytes(buf, 1, 13, of);
+	
+	// output the name
+	for (i = 0; linkscript.name[i + 1]; i++)
+	{
+		writebytes(linkscript.name + i, 1, 1, of);
+		os9crc(crc, linkscript.name[i]);
+	}
+	buf[0] = linkscript.name[i] | 0x80;
+	writebytes(buf, 1, 1, of);
+	os9crc(crc, buf[0]);
+	
+	// output the data
+	// NOTE: disjoint load addresses will not work correctly!!!!!
+	for (sn = 0; sn < nsects; sn++)
+	{
+		if (sectlist[sn].ptr -> flags & SECTION_BSS)
+		{
+			// no output for a BSS section
+			continue;
+		}
+		writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of);
+		for (i = 0; i < sectlist[sn].ptr -> codesize; i++)
+			os9crc(crc, sectlist[sn].ptr -> code[i]);
+	}
+	
+	crc[0] ^= 0xff;
+	crc[1] ^= 0xff;
+	crc[2] ^= 0xff;
+	writebytes(crc, 1, 3, of);
+}
--- a/lwlink/script.c	Thu Aug 25 22:29:58 2011 -0600
+++ b/lwlink/script.c	Fri Aug 26 23:26:00 2011 -0600
@@ -32,6 +32,16 @@
 
 #include "lwlink.h"
 
+// the built-in OS9 script
+static char *os9_script =
+	"section code load 0000\n"
+	"section .text\n"
+	"section data\n"
+	"section .data\n"
+	"section bss,bss load 0000\n"
+	"section .bss,bss\n"
+	;
+
 // the built-in DECB target linker script
 static char *decb_script =
 	"section init load 2000\n"
@@ -125,6 +135,10 @@
 		case OUTPUT_LWEX0:
 			script = lwex0_script;
 			break;
+		
+		case OUTPUT_OS9:
+			script = os9_script;
+			break;
 			
 		default:
 			script = simple_script;
@@ -154,6 +168,15 @@
 	if (outformat == OUTPUT_LWEX0)
 		linkscript.stacksize = 0x100;
 
+	if (outformat == OUTPUT_OS9)
+	{
+		linkscript.modtype = 0x01;
+		linkscript.modlang = 0x01;
+		linkscript.modattr = 0x08;
+		linkscript.modrev = 0x00;
+		linkscript.name = NULL;
+	}
+
 	oscript = script;
 	// now parse the script file
 	while (*script)