changeset 299:460d96987670

parse linking scripts
author lost
date Wed, 21 Jan 2009 04:54:32 +0000
parents 96a35a4245f3
children 48945dac8178
files src/Makefile.am src/lwlink.c src/lwlink.h src/main.c src/script.c
diffstat 5 files changed, 269 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.am	Wed Jan 21 03:15:49 2009 +0000
+++ b/src/Makefile.am	Wed Jan 21 04:54:32 2009 +0000
@@ -1,3 +1,3 @@
 bin_PROGRAMS = lwlink
-lwlink_SOURCES = main.c lwlink.c util.c readfiles.c expr.c
+lwlink_SOURCES = main.c lwlink.c util.c readfiles.c expr.c script.c
 EXTRA_DIST = lwlink.h util.h expr.h
--- a/src/lwlink.c	Wed Jan 21 03:15:49 2009 +0000
+++ b/src/lwlink.c	Wed Jan 21 04:54:32 2009 +0000
@@ -38,6 +38,7 @@
 int debug_level = 0;
 int outformat = OUTPUT_DECB;
 char *outfile = NULL;
+char *scriptfile = NULL;
 
 fileinfo_t **inputfiles = NULL;
 int ninputfiles = 0;
--- a/src/lwlink.h	Wed Jan 21 03:15:49 2009 +0000
+++ b/src/lwlink.h	Wed Jan 21 04:54:32 2009 +0000
@@ -80,6 +80,7 @@
 extern char *outfile;
 extern int ninputfiles;
 extern fileinfo_t **inputfiles;
+extern char *scriptfile;
 
 #define __lwlink_E__ extern
 #else
@@ -89,4 +90,24 @@
 __lwlink_E__ void add_input_file(char *fn);
 
 #undef __lwlink_E__
+
+struct scriptline_s
+{
+	char *sectname;				// name of section, NULL for wildcard
+	int loadat;					// address to load at (or -1)
+	int noflags;				// flags to NOT have
+	int yesflags;				// flags to HAVE
+};
+
+typedef struct
+{
+	int nlines;					// number of lines in the script
+	struct scriptline_s *lines;	// the parsed script lines (section)
+	int padsize;				// the size to pad to, -1 for none
+} linkscript_t;
+
+#ifndef __script_c_seen__
+extern linkscript_t linkscript;
+#endif
+
 #endif //__lwlink_h_seen__
--- a/src/main.c	Wed Jan 21 03:15:49 2009 +0000
+++ b/src/main.c	Wed Jan 21 04:54:32 2009 +0000
@@ -46,6 +46,11 @@
 		outfile = arg;
 		break;
 	
+	case 's':
+		// script file
+		scriptfile = arg;
+		break;
+
 	case 'd':
 		// debug
 		debug_level++;
@@ -101,6 +106,8 @@
 				"Generate DECB .bin format output, equivalent of --format=decb"},
 	{ "raw",		'r',	0,		0,
 				"Generate raw binary format output, equivalent of --format=raw"},
+	{ "script",		's',	0,		0,
+				"Specify the linking script (overrides the build in defaults)"},
 	{ 0 }
 };
 
@@ -113,6 +120,7 @@
 };
 
 extern void read_files(void);
+extern void setup_script(void);
 
 // main function; parse command line, set up assembler state, and run the
 // assembler on the first file
@@ -125,6 +133,8 @@
 		exit(1);
 	}
 
+	setup_script();
+
 	// read the input files
 	read_files();
 	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/script.c	Wed Jan 21 04:54:32 2009 +0000
@@ -0,0 +1,236 @@
+/*
+script.c
+Copyright © 2008 William Astle
+
+This file is part of LWLINK.
+
+LWLINK is free software: you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+Read and parse linker scripts
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lwlink.h"
+#include "util.h"
+
+// the built-in DECB target linker script
+static char *decb_script =
+	"section init load at 2000\n"
+	"section code\n"
+	"section *,!bss\n"
+	"section *,bss\n"
+	;
+
+// the built-in RAW target linker script
+static char *raw_script = 
+	"section init load at 0000\n"
+	"section code\n"
+	"section *,!bss\n"
+	"section *,bss\n"
+	;
+
+// the "simple" script
+static char *simple_script = 
+	"section *,!bss\n"
+	"section *,bss\n"
+	;
+
+linkscript_t linkscript = { 0, NULL, -1 };
+
+void setup_script()
+{
+	char *script;
+	long size;
+
+	// read the file if needed
+	if (scriptfile)
+	{
+		FILE *f;
+		long bread;
+		
+		f = fopen(scriptfile, "rb");
+		if (!f)
+		{
+			fprintf(stderr, "Can't open file %s:", scriptfile);
+			perror("");
+			exit(1);
+		}
+		fseek(f, 0, SEEK_END);
+		size = ftell(f);
+		rewind(f);
+		
+		script = lw_malloc(size + 2);
+		
+		bread = fread(script, 1, size, f);
+		if (bread < size)
+		{
+			fprintf(stderr, "Short read on file %s (%ld/%ld):", scriptfile, bread, size);
+			perror("");
+			exit(1);
+		}
+		fclose(f);
+		
+		script[size] = '\n';
+		script[size + 1] = '\0';
+	}
+	else
+	{
+		// fetch defaults based on output mode
+		switch (outformat)
+		{
+		case OUTPUT_RAW:
+			script = raw_script;
+			break;
+		
+		case OUTPUT_DECB:
+			script = decb_script;
+			break;
+		
+		default:
+			script = simple_script;
+			break;
+		}
+		
+		size = strlen(script);
+	}
+
+	// now parse the script file
+	while (*script)
+	{
+		char *ptr, *ptr2, *line;
+
+		for (ptr = script; *ptr && *ptr != '\n' && *ptr != '\r'; ptr++)
+			/* do nothing */ ;
+		
+		line = lw_malloc(ptr - script + 1);
+		memcpy(line, script, ptr - script);
+		line[ptr - script] = '\0';
+
+		// skip line terms
+		for (script = ptr + 1; *script == '\n' || *script == '\r'; script++)
+			/* do nothing */ ;
+		
+		// ignore leading whitespace
+		for (ptr = line; *ptr && isspace(*ptr); ptr++)
+			/* do nothing */ ;
+		
+		// ignore blank lines
+		if (!*ptr)
+			continue;
+		
+		for (ptr = line; *ptr && !isspace(*ptr); ptr++)
+			/* do nothing */ ;
+		
+		// now ptr points to the char past the first word
+		// NUL it out
+		if (*ptr)
+			*ptr++ = '\0';
+		
+		// skip spaces after the first word
+		for ( ; *ptr && isspace(*ptr); ptr++)
+			/* do nothing */ ;
+		
+		if (!strcmp(line, "pad"))
+		{
+			// padding
+			// parse the hex number and stow it
+			linkscript.padsize = strtol(ptr, NULL, 16);
+			if (linkscript.padsize < 0)
+				linkscript.padsize = 0;
+		}
+		else if (!strcmp(line, "section"))
+		{
+			// section
+			// parse out the section name and flags
+			for (ptr2 = ptr; *ptr2 && !isspace(*ptr2); ptr2++)
+				/* do nothing */ ;
+			
+			if (*ptr2)
+				*ptr2++ = '\0';
+			
+			while (*ptr2 && isspace(*ptr2))
+				ptr2++;
+				
+			// ptr now points to the section name and flags and ptr2
+			// to the first non-space character following
+			
+			// then look for "load <addr>" clause
+			if (*ptr2)
+			{
+				if (!strncmp(ptr2, "load", 4))
+				{
+					ptr2 += 4;
+					while (*ptr2 && isspace(*ptr2))
+						ptr2++;
+					
+				}
+				else
+				{
+					fprintf(stderr, "%s: bad script\n", scriptfile);
+					exit(1);
+				}
+			}
+			
+			// now ptr2 points to the load address if there is one
+			// or NUL if not
+			linkscript.lines = lw_realloc(linkscript.lines, sizeof(struct scriptline_s) * (linkscript.nlines + 1));
+
+			linkscript.lines[linkscript.nlines].noflags = 0;
+			linkscript.lines[linkscript.nlines].yesflags = 0;
+			if (*ptr2)
+				linkscript.lines[linkscript.nlines].loadat = strtol(ptr2, NULL, 16);
+			else
+				linkscript.lines[linkscript.nlines].loadat = -1;
+			for (ptr2 = ptr; *ptr2 && *ptr2 != ','; ptr2++)
+				/* do nothing */ ;
+			if (*ptr2)
+			{
+				*ptr2++ = '\0';
+				if (!strcmp(ptr2, "!bss"))
+				{
+					linkscript.lines[linkscript.nlines].noflags = SECTION_BSS;
+				}
+				else if (!strcmp(ptr2, "bss"))
+				{
+					linkscript.lines[linkscript.nlines].yesflags = SECTION_BSS;
+				}
+				else
+				{
+					fprintf(stderr, "%s: bad script\n", scriptfile);
+					exit(1);
+				}
+			}
+			linkscript.lines[linkscript.nlines].sectname = lw_strdup(ptr);
+			linkscript.nlines++;
+		}
+		else
+		{
+			fprintf(stderr, "%s: bad script\n", scriptfile);
+			exit(1);
+		}
+		lw_free(line);
+	}
+	
+	if (scriptfile)
+		lw_free(script);
+}