Mercurial > hg-old > index.cgi
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); +}