Mercurial > hg-old > index.cgi
view src/link.c @ 316:ba58dbe39c67 1.0
Branched for release 1.0
author | lost |
---|---|
date | Tue, 27 Jan 2009 05:51:54 +0000 |
parents | c275e7e328d4 |
children |
line wrap: on
line source
/* link.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/>. Resolve section and symbol addresses; handle incomplete references */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdio.h> #include <stdlib.h> #include "expr.h" #include "lwlink.h" #include "util.h" struct section_list *sectlist = NULL; int nsects = 0; // work out section load order and resolve base addresses for each section // make a list of sections to load in order void resolve_sections(void) { int laddr = 0; int ln, sn, fn; for (ln = 0; ln < linkscript.nlines; ln++) { // printf("Linker script line %d: '%s', %04X, %d, %d\n", ln, linkscript.lines[ln].sectname, linkscript.lines[ln].loadat, linkscript.lines[ln].yesflags, linkscript.lines[ln].noflags); if (linkscript.lines[ln].sectname) { int f = 0; // named section // look for all instances of a section by the specified name // and resolve base addresses and add to the list for (fn = 0; fn < ninputfiles; fn++) { for (sn = 0; sn < inputfiles[fn] -> nsections; sn++) { // printf(" Considering %s:%s\n", inputfiles[fn]->filename, inputfiles[fn]->sections[sn].name); if (!strcmp(linkscript.lines[ln].sectname, inputfiles[fn] -> sections[sn].name)) { // we have a match sectlist = lw_realloc(sectlist, sizeof(struct section_list) * (nsects + 1)); sectlist[nsects].ptr = &(inputfiles[fn] -> sections[sn]); inputfiles[fn] -> sections[sn].processed = 1; if (!f && linkscript.lines[ln].loadat >= 0) { f = 1; sectlist[nsects].forceaddr = 1; laddr = linkscript.lines[ln].loadat; } else { sectlist[nsects].forceaddr = 0; } inputfiles[fn] -> sections[sn].loadaddress = laddr; laddr += inputfiles[fn] -> sections[sn].codesize; nsects++; } } } } else { // wildcard section // look for all sections not yet processed that match flags int f = 0; int fn0, sn0; char *sname; // named section // look for all instances of a section by the specified name // and resolve base addresses and add to the list for (fn0 = 0; fn0 < ninputfiles; fn0++) { for (sn0 = 0; sn0 < inputfiles[fn0] -> nsections; sn0++) { // ignore if the "no flags" bit says to if (linkscript.lines[ln].noflags && (inputfiles[fn0] -> sections[sn0].flags & linkscript.lines[ln].noflags)) continue; // ignore unless the yes flags tell us not to if (linkscript.lines[ln].yesflags && (inputfiles[fn0] -> sections[sn0].flags & linkscript.lines[ln].yesflags == 0)) continue; if (inputfiles[fn0] -> sections[sn0].processed == 0) { sname = inputfiles[fn0] -> sections[sn0].name; for (fn = 0; fn < ninputfiles; fn++) { for (sn = 0; sn < inputfiles[fn] -> nsections; sn++) { if (!strcmp(sname, inputfiles[fn] -> sections[sn].name)) { // we have a match sectlist = lw_realloc(sectlist, sizeof(struct section_list) * (nsects + 1)); sectlist[nsects].ptr = &(inputfiles[fn] -> sections[sn]); inputfiles[fn] -> sections[sn].processed = 1; if (!f && linkscript.lines[ln].loadat >= 0) { f = 1; sectlist[nsects].forceaddr = 1; laddr = linkscript.lines[ln].loadat; } else { sectlist[nsects].forceaddr = 0; } inputfiles[fn] -> sections[sn].loadaddress = laddr; laddr += inputfiles[fn] -> sections[sn].codesize; nsects++; } } } } } } } } // theoretically, all the base addresses are set now } // resolve all incomplete references now // anything that is unresolvable at this stage will throw an error // because we know the load address of every section now lw_expr_stack_t *resolve_sym(char *sym, int symtype, void *state) { section_t *sect = state; lw_expr_term_t *term; int val = 0, i, fn; lw_expr_stack_t *s; symtab_t *se; if (symtype == 1) { // local symbol if (!sym) { val = sect -> loadaddress; goto out; } // start with this section for (se = sect -> localsyms; se; se = se -> next) { if (!strcmp(se -> sym, sym)) { val = se -> offset + sect -> loadaddress; goto out; } } // not in this section - check all sections in this file for (i = 0; i < sect -> file -> nsections; i++) { for (se = sect -> file -> sections[i].localsyms; se; se = se -> next) { if (!strcmp(se -> sym, sym)) { val = se -> offset + sect -> file -> sections[i].loadaddress; goto out; } } } // not found fprintf(stderr, "Local symbol %s not found in %s:%s\n", sym, sect -> file -> filename, sect -> name); exit(1); } else { // external symbol // read all files in order until found (or not found) for (fn = 0; fn < ninputfiles; fn++) { for (i = 0; i < inputfiles[fn] -> nsections; i++) { for (se = inputfiles[fn] -> sections[i].exportedsyms; se; se = se -> next) { if (!strcmp(sym, se -> sym)) { val = se -> offset + inputfiles[fn] -> sections[i].loadaddress; goto out; } } } } if (sect) { fprintf(stderr, "External symbol %s not found in %s:%s\n", sym, sect -> file -> filename, sect -> name); } else { fprintf(stderr, "External symbol %s not found\n", sym); } exit(1); } fprintf(stderr, "Shouldn't ever get here!!!\n"); exit(88); out: s = lw_expr_stack_create(); term = lw_expr_term_create_int(val & 0xffff); lw_expr_stack_push(s, term); lw_expr_term_free(term); return s; } void resolve_references(void) { int sn; reloc_t *rl; int rval; // resolve entry point if required // this must resolve to an *exported* symbol and will resolve to the // first instance of that symbol if (linkscript.execsym) { lw_expr_stack_t *s; s = resolve_sym(linkscript.execsym, 0, NULL); linkscript.execaddr = lw_expr_get_value(s); lw_expr_stack_free(s); } for (sn = 0; sn < nsects; sn++) { for (rl = sectlist[sn].ptr -> incompletes; rl; rl = rl -> next) { // do a "simplify" on the expression rval = lw_expr_reval(rl -> expr, resolve_sym, sectlist[sn].ptr); // is it constant? error out if not if (rval != 0 || !lw_expr_is_constant(rl -> expr)) { fprintf(stderr, "Incomplete reference at %s:%s:%02X\n", sectlist[sn].ptr -> file -> filename, sectlist[sn].ptr -> name, rl -> offset); exit(1); } // put the value into the relocation address rval = lw_expr_get_value(rl -> expr); sectlist[sn].ptr -> code[rl -> offset] = (rval >> 8) & 0xff; sectlist[sn].ptr -> code[rl -> offset + 1] = rval & 0xff; } } }