Mercurial > hg > index.cgi
diff lwlink/script.c @ 0:2c24602be78f
Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
author | lost@l-w.ca |
---|---|
date | Wed, 19 Jan 2011 22:27:17 -0700 |
parents | |
children | 7317fbe024af |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwlink/script.c Wed Jan 19 22:27:17 2011 -0700 @@ -0,0 +1,295 @@ +/* +script.c +Copyright © 2009 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 +*/ + +#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 2000\n" + "section code\n" + "section *,!bss\n" + "section *,bss\n" + "entry 2000\n" + ; + +// the built-in RAW target linker script +static char *raw_script = + "section init load 0000\n" + "section code\n" + "section *,!bss\n" + "section *,bss\n" + ; + +static char *lwex0_script = + "section init load 0100\n" + "section .text\n" + "section .data\n" + "section *,!bss\n" + "section *,bss\n" + "entry __start\n" + "stacksize 0100\n" // default 256 byte stack + ; + +// the "simple" script +static char *simple_script = + "section *,!bss\n" + "section *,bss\n" + ; + +linkscript_t linkscript = { 0, NULL, -1 }; + +void setup_script() +{ + char *script, *oscript; + 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; + + case OUTPUT_LWEX0: + script = lwex0_script; + break; + + default: + script = simple_script; + break; + } + + size = strlen(script); + if (nscriptls) + { + char *rscript; + int i; + // prepend the "extra" script lines + for (i = 0; i < nscriptls; i++) + size += strlen(scriptls[i]) + 1; + + rscript = lw_malloc(size + 1); + oscript = rscript; + for (i = 0; i < nscriptls; i++) + { + oscript += sprintf(oscript, "%s\n", scriptls[i]); + } + strcpy(oscript, script); + script = rscript; + } + } + + if (outformat == OUTPUT_LWEX0) + linkscript.stacksize = 0x100; + + oscript = 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, "stacksize")) + { + // stack size for targets that support it + // parse the hex number and stow it + linkscript.padsize = strtol(ptr, NULL, 16); + if (linkscript.stacksize < 0) + linkscript.stacksize = 0x100; + } + else if (!strcmp(line, "entry")) + { + int eaddr; + + eaddr = strtol(ptr, &ptr2, 16); + if (*ptr2) + { + linkscript.execaddr = -1; + linkscript.execsym = lw_strdup(ptr); + } + else + { + linkscript.execaddr = eaddr; + linkscript.execsym = NULL; + } + } + 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); + } + } + if (ptr[0] == '*' && ptr[1] == '\0') + linkscript.lines[linkscript.nlines].sectname = NULL; + else + 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 || nscriptls) + lw_free(oscript); +}