ref: 2c616f66467f5e2708b7f8f46d96469181c4c406
dir: /src/cmd/ld/pass1.c/
#include <errno.h> #include <ctype.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <scc/mach.h> #include <scc/scc.h> #include <scc/ar.h> #include "ld.h" enum { OUTLIB, INLIB, }; int bintype = -1; static int is_needed(Obj *obj) { int i; Symbol sym; for (i = 0; getsym(obj, &i, &sym); i++) { if (hasref(sym.name)) return 1; } return 0; } static void newsec(Section *osec, Obj *obj) { int align; Section *sec; unsigned long long base; sec = lookupsec(osec->name); if (sec->type != 'U') { if (sec->type != osec->type || sec->flags != osec->flags || sec->base != osec->base || sec->align != osec->align) { error("incompatible definition of section %s", sec->name); return; } align = osec->align; align -= sec->size & align-1; grow(sec, align); rebase(obj, osec->index, sec->size); } else { sec->type = osec->type; sec->base = osec->base; sec->size = osec->size; sec->flags = osec->flags; } copy(obj, osec, sec); } static void newsym(Symbol *sym, Obj *obj) { int id; Section sec; if (sym->type == 'U' || islower(sym->type)) return; sym = define(sym, obj); id = sym->section; getsec(obj, &id, &sec); sym->value += sec.base; } static void load(FILE *fp, int inlib) { int t, i; Obj *obj; Section sec; Symbol sym; if ((t = objtype(fp, NULL)) < 0) { error("bad format"); return; } if (bintype != -1 && bintype != t) { error("not compatible object file"); return; } bintype = t; if ((obj = newobj(t)) == NULL) { error(strerror(errno)); return; } if (readobj(obj, fp) < 0) { error(strerror(errno)); goto delete; } if (inlib && !is_needed(obj)) goto delete; for (i = 0; getsec(obj, &i, &sec); i++) newsec(&sec, obj); for ( i = 0; getsym(obj, &i, &sym); i++) newsym(&sym, obj); /* TODO: link the object */ return; delete: delobj(obj); return; } static void scanindex(FILE *fp) { int t, added; long n, i, *offs; char **names; Symbol *sym; if (getindex(bintype, &n, &names, &offs, fp) < 0) { error("corrupted index"); return; } for (added = 0; moreundef(); added = 0) { for (i = 0; i < n; i++) { if (!hasref(names[i])) continue; if (fseek(fp, offs[i], SEEK_SET) == EOF) { error(strerror(errno)); goto clean; } load(fp, OUTLIB); added = 1; } if (!added) break; } clean: for (i = 0; i < n; i++) free(names[i]); free(names); free(offs); } void scanlib(FILE *fp) { long cur, off; char memb[SARNAM+1]; if (bintype == -1) { error("an object file is needed before any library"); return; } cur = ftell(fp); if ((off = armember(fp, memb)) < 0) goto corrupted; if (strcmp(memb, "/") == 0 || strcmp(memb, "__.SYMDEF") == 0) { scanindex(fp); return; } fseek(fp, cur, SEEK_SET); for (;;) { cur = ftell(fp); off = armember(fp, memb); switch (off) { case -1: goto corrupted; case 0: return; default: membname = memb; if (objtype(fp, NULL) != -1) load(fp, INLIB); membname = NULL; fseek(fp, cur, SEEK_SET); fseek(fp, off, SEEK_CUR); break; } } corrupted: error(strerror(errno)); error("library corrupted"); } static FILE * openfile(char *name) { size_t pathlen, len; FILE *fp; char **bp; char libname[FILENAME_MAX]; static char buffer[FILENAME_MAX]; extern char *syslibs[]; filename = name; membname = NULL; if (name[0] != '-' || name[1] != 'l') { if ((fp = fopen(name, "rb")) == NULL) error(strerror(errno)); return fp; } len = strlen(name+2) + 3; if (len > FILENAME_MAX-1) { error("library name too long"); return NULL; } strcat(strcpy(buffer, "lib"), name+2); filename = buffer; if ((fp = fopen(buffer, "rb")) != NULL) return fp; for (bp = syslibs; *bp; ++bp) { pathlen = strlen(*bp); if (pathlen + len > FILENAME_MAX-1) continue; memcpy(libname, *bp, pathlen); memcpy(libname+pathlen+1, buffer, len); buffer[pathlen] = '/'; if ((fp = fopen(libname, "rb")) != NULL) return fp; } error("not found"); return NULL; } static void process(char *name) { int t; FILE *fp; if ((fp = openfile(name)) == NULL) return; if (archive(fp)) scanlib(fp); else load(fp, OUTLIB); fclose(fp); } /* * Get the list of object files that are going to be linked */ void pass1(int argc, char *argv[]) { char **ap, *cp, *arg; for (ap = argv+1; *ap; ++ap) { if (ap[0][0] != '-') { process(*ap); continue; } for (cp = &ap[0][1]; *cp; ++cp) { switch (*cp) { case 'l': /* FIXME: we proccess arg again after this */ arg = (cp[1]) ? cp+1 : *++ap; process(arg); continue; case 'u': /* FIXME: we proccess arg again after this */ arg = (cp[1]) ? cp+1 : *++ap; lookupsym(arg); continue; } } } if (moreundef()) { listundef(); exit(EXIT_FAILURE); } }