ref: a90c5a46440cc4c6527b9b2c28d7d03b4553d82c
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);
}
}