Mercurial > hg > index.cgi
view lwlink/script.c @ 418:3832a68d83ef
Fix internal compiler error on "var2 = var1 + 1" patterns
This appears to be the correct fix. It was provided by Tormod Volden
(debian.tormod@gmail.com). The final commit is substantially different from
Tormod's submission mostly due to housecleaning (removing the old patches
and updating the README). Tormod's comments follow.
The original addhi_mem_1 "insn" instruction pattern /matches/ two
memory operands, just with the /constraint/ that these are the same
location. A pattern match tells the compiler "you should be able to use
this, but you might have to work on it to meet the constraints". For
typical constraints on registers the compiler can add "reloads", moving
stuff between registers or from memory, until the constraints are met
and the instruction can be used. However, in this case, no amount of
reloads can make two memory locations the same if they already weren't,
so the compiler breaks down and cries "unable to generate reloads".
It seems this issue only appears if optimization is enabled. The proof
is in gcc's reload.c and is left as an exercise to the reader.
Limiting the matching pattern to identical memory operands avoids
these situations, while allowing the common "var++" cases.
References:
The pattern/constraints difference is explained in
https://gcc.gnu.org/onlinedocs/gccint/Simple-Constraints.html#index-other-register-constraints-3335
author | William Astle <lost@l-w.ca> |
---|---|
date | Tue, 29 Mar 2016 21:21:49 -0600 |
parents | 55c1f9a321e9 |
children | b8e9ac01deda |
line wrap: on
line source
/* 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 <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <lw_alloc.h> #include <lw_string.h> #include "lwlink.h" // the built-in OS9 script // the 000D bit is to handle the module header! static char *os9_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "section code load 000D\n" "section .text\n" "section data\n" "section .data\n" "section bss,bss load 0000\n" "section .bss,bss\n" "stacksize 32\n" "entry __start\n" ; // the built-in DECB target linker script static char *decb_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "section init load 2000\n" "section code\n" "section *,!bss\n" "section *,bss\n" "entry 2000\n" ; // the built-in SREC target linker script static char *srec_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "section init load 0400\n" "section code\n" "section *,!bss\n" "section *,bss\n" "entry __start\n" ; // the built-in RAW target linker script static char *raw_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "section init load 0000\n" "section code\n" "section *,!bss\n" "section *,bss\n" ; static char *lwex0_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "sectopt .ctors padafter 00,00\n" "sectopt .dtors padafter 00,00\n" "section init load 0100\n" "section .text\n" "section .data\n" "section .ctors_start\n" "section .ctors\n" "section .ctors_end\n" "section .dtors_start\n" "section .dtors\n" "section .dtors_end\n" "section *,!bss\n" "section *,bss\n" "entry __start\n" "stacksize 0100\n" // default 256 byte stack ; // the "simple" script static char *simple_script = "define basesympat s_%s\n" "define lensympat l_%s\n" "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_alloc(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_SREC: script = srec_script; break; case OUTPUT_LWEX0: script = lwex0_script; break; case OUTPUT_OS9: script = os9_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_alloc(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; if (outformat == OUTPUT_OS9) { linkscript.modtype = 0x01; linkscript.modlang = 0x01; linkscript.modattr = 0x08; linkscript.modrev = 0x00; linkscript.edition = -1; linkscript.name = NULL; } 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_alloc(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 and comments if (!*ptr || *ptr == '#' || *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, "sectopt")) { char *sn; char *ptr3; sectopt_t *so; for (ptr2 = ptr; *ptr && !isspace(*ptr2); ptr2++) /* do nothing */ ; if (*ptr2) *ptr2++ = '\0'; while (*ptr2 && isspace(*ptr2)) ptr2++; // section name is at ptr // ptr2 is the option type sn = ptr; // now ptr2 points to the section option name for (ptr3 = ptr2; *ptr3 && !isspace(*ptr3); ptr3++) /* do nothing */ ; if (*ptr3) *ptr3++ = 0; while (*ptr3 && isspace(*ptr3)) ptr3++; // now ptr3 points to option value for (so = section_opts; so; so = so -> next) { if (!strcmp(so -> name, sn)) break; } if (!so) { so = lw_alloc(sizeof(sectopt_t)); so -> name = lw_strdup(sn); so -> aftersize = 0; so -> afterbytes = NULL; so -> next = section_opts; section_opts = so; } if (!strcmp(ptr2, "padafter")) { if (so -> afterbytes) lw_free(so -> afterbytes); so -> aftersize = 0; for (;;) { int v; char *ptr4; while (*ptr3 && isspace(*ptr3)) ptr3++; if (!ptr3) break; v = strtoul(ptr3, &ptr4, 16); if (ptr3 == ptr4) break; so -> afterbytes = lw_realloc(so -> afterbytes, so -> aftersize + 1); so -> afterbytes[so -> aftersize] = v; so -> aftersize++; ptr3 = ptr4; while (*ptr3 && isspace(*ptr3)) ptr3++; if (*ptr3 != ',') break; ptr3++; } } else { fprintf(stderr, "%s: bad script line: %s %s\n", scriptfile, line, ptr2); exit(1); } } else if (!strcmp(line, "define")) { // parse out the definition type for (ptr2 = ptr; *ptr2 && !isspace(*ptr2); ptr2++) /* do nothing */ ; if (*ptr2) *ptr2++ = '\0'; while (*ptr2 && isspace(*ptr2)) ptr2++; // now ptr points to the define type if (!strcmp(ptr, "basesympat")) { /* section base symbol pattern */ lw_free(linkscript.basesympat); linkscript.basesympat = lw_strdup(ptr2); } else if (!strcmp(ptr, "lensympat")) { /* section length symbol pattern */ lw_free(linkscript.lensympat); linkscript.lensympat = lw_strdup(ptr2); } else { } } else 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")) { int growsdown = 0; // 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 if (!strncmp(ptr2, "high", 4)) { ptr2 += 4; while (*ptr2 && isspace(*ptr2)) ptr2++; growsdown = 1; } else { fprintf(stderr, "%s: bad script\n", scriptfile); exit(1); } } else { if (linkscript.nlines > 0) growsdown = linkscript.lines[linkscript.nlines - 1].growsdown; } // 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; linkscript.lines[linkscript.nlines].growsdown = growsdown; 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 line: %s\n", scriptfile, line); exit(1); } lw_free(line); } if (scriptfile || nscriptls) lw_free(oscript); if (entrysym) { int eaddr; char *ptr2; lw_free(linkscript.execsym); eaddr = strtol(entrysym, &ptr2, 0); if (*ptr2) { linkscript.execaddr = -1; linkscript.execsym = lw_strdup(entrysym); } else { linkscript.execaddr = eaddr; linkscript.execsym = NULL; } } }