home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Crawly Crypt Collection 1
/
crawlyvol1.bin
/
program
/
compiler
/
sozobon
/
scsrc20
/
ld
/
syms.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-22
|
12KB
|
708 lines
/*
* Copyright (c) 1991 by Sozobon, Limited. Author: Johann Ruegg
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*/
#include <stdio.h>
#include "syms.h"
#include "structs.h"
char *mlmalloc(), *mmalloc();
extern int only8;
#ifdef NHASH
/* NHASH must be a power of 2 */
struct sinfo *ushead[NHASH];
struct sinfo *dshead[NHASH];
int hashv;
#define USHEAD ushead[hashv]
#define DSHEAD dshead[hashv]
#else
struct sinfo *ushead, *dshead;
#define USHEAD ushead
#define DSHEAD dshead
#endif
extern int vflag;
getsyms(fd, size, spp)
long size;
struct symchunk **spp;
{
struct symchunk *chp;
long n;
int k;
n = size / SYMSIZE;
if (n == 0) {
*spp = 0;
return;
}
do {
if (n > CHUNKMAX)
k = CHUNKMAX;
else
k = n;
chp = (struct symchunk *)mmalloc(sizeof(struct symchunk) +
((k-1)*sizeof(struct sym)));
rread(fd, &chp->s[0], k * SYMSIZE);
#ifdef UNIXHOST
symhacki(&chp->s[0], k);
#endif
commhack(&chp->s[0], k);
chp->nsyms = k;
*spp = chp;
spp = &chp->next;
n -= k;
} while (n);
chp->next = 0;
}
commhack(sp, n)
struct sym *sp;
{
int i;
/* Common def with value of 0 is really an external ref */
for (i=0; i<n; i++) {
if (sp->flags == COMMDEF && sp->value == 0)
sp->flags = EXTREF;
sp++;
}
}
symfree(chp)
struct symchunk *chp;
{
struct symchunk *next;
while (chp) {
next = chp->next;
free(chp);
chp = next;
}
}
chkx(chp)
struct symchunk *chp;
{
struct sym *sp;
if (only8)
return 0;
if (chp == 0)
return 0;
sp = &chp->s[0];
if (sp->flags == XFLAGS && sp->value == XVALUE &&
strncmp(sp->name, XNAME, 8) == 0)
return 1;
return 0;
}
struct sinfo *
xlookup(head, s, x)
struct sinfo *head;
char *s, *x;
{
while (head) {
if (smatch(head->name, s, x))
return head;
head = head->next;
}
return 0;
}
smatch(old, s, x)
char *old, *s, *x;
{
int ol;
ol = strlen(old);
if (ol < 8)
return strcmp(old, s) == 0;
if (strncmp(old, s, 8) != 0)
return 0;
if (strcmp(&old[8], x) == 0)
return 1;
else if (x[0] == '*')
return 1;
else if (old[8] == '*')
return 2;
return 0;
}
struct sinfo *
newsinfo(s, xp)
char *s, *xp;
{
int slen, xlen;
struct sinfo *sp;
slen = strnlen(s, 8);
if (slen == 8 && xp)
xlen = strlen(xp);
else
xlen = 0;
sp = (struct sinfo *)mmalloc(slen+xlen+sizeof(struct sinfo));
bcopy(s, sp->name, slen);
sp->name[slen] = 0;
if (xlen)
strcpy(&sp->name[8], xp);
sp->flags = sp->mark = 0;
sp->value = 0;
sp->obj = 0;
return sp;
}
sundeff(s)
char *s;
{
hashv = hash(s);
if (strlen(s) > 8)
undeff(s, &s[8], 0L);
else
undeff(s, 0L, 0L);
}
undeff(s, xp, op) /* hashv set by caller */
char *s;
char *xp;
struct oinfo *op;
{
struct sinfo *sp;
sp = newsinfo(s, xp);
sp->flags = EXTREF;
sp->obj = op;
listins(&USHEAD, sp);
if (vflag > 1)
printf("und %s\n", sp->name);
}
char *
exten(chp, sp)
struct symchunk *chp;
struct sym *sp;
{
static int maxlen = 0;
static char *cp = 0;
int k, i, n, slen;
struct symchunk *nchp;
struct sym *nsp;
if (maxlen == 0) {
maxlen = 100;
cp = mmalloc(maxlen);
}
again:
k = chp->nsyms;
i = sp - &chp->s[0];
slen = 0;
cp[slen] = 0;
nchp = chp; nsp = sp;
while (slen+9 < maxlen) {
i++;
if (i < k) {
nsp++;
} else if (nchp->next == NULL) {
return cp;
} else {
nchp = nchp->next;
k = nchp->nsyms;
i = 0;
nsp = &nchp->s[0];
}
if (nsp->flags != XFLAGS || nsp->value != XVALUE) {
return cp;
}
n = strnlen(nsp->name, 8);
bcopy(nsp->name, &cp[slen], n);
slen += n;
cp[slen] = 0;
if (n != 8) {
return cp;
}
}
/* buffer is too small */
free(cp);
maxlen += 100;
cp = mmalloc(maxlen);
goto again;
}
needed(chp, havex)
struct symchunk *chp;
{
unsigned i;
int k;
while (chp) {
k = chp->nsyms;
for (i=0; i<k; i++)
if (need1(&chp->s[i], chp, havex))
return 1;
chp = chp->next;
}
return 0;
}
char *
getext(chp, sp, havex)
struct symchunk *chp;
struct sym *sp;
{
char *extp;
if (havex)
extp = exten(chp, sp);
else if (only8)
extp = "";
else
extp = "*";
return extp;
}
need1(sp, chp, havex)
struct sym *sp;
struct symchunk *chp;
{
char *extp;
struct sinfo *sip;
#ifdef NHASH
hashv = hash(sp->name);
#endif
if (notglob(sp->flags))
return 0;
if (sp->flags == EXTREF || sp->flags == COMMDEF)
return 0;
if (sp->name[7])
extp = getext(chp, sp, havex);
else
extp = 0;
if ((sip = xlookup(USHEAD, sp->name, extp))) {
if (vflag > 1)
printf("Needed %s\n", sip->name);
return 1;
}
return 0;
}
p1syms(chp, havex, op)
struct symchunk *chp;
struct oinfo *op;
{
unsigned i;
int k;
while (chp) {
k = chp->nsyms;
for (i=0; i<k; i++)
ap1sym(&chp->s[i], chp, havex, op);
chp = chp->next;
}
return 0;
}
ap1sym(sp, chp, havex, op)
struct sym *sp;
struct symchunk *chp;
struct oinfo *op;
{
char *extp;
struct sinfo *sip;
if (notglob(sp->flags))
return;
if (sp->name[7])
extp = getext(chp, sp, havex);
else
extp = 0;
#ifdef NHASH
hashv = hash(sp->name);
#endif
if (sp->flags == EXTREF) {
if (xlookup(USHEAD, sp->name, extp))
return;
else if (xlookup(DSHEAD, sp->name, extp))
;
else
undeff(sp->name, extp, op);
} else {
sip = xlookup(USHEAD, sp->name, extp);
if (sip) {
listdel(&USHEAD, sip);
sip->flags = sp->flags;
sip->value = sp->value;
sip->obj = op;
listins(&DSHEAD, sip);
if (vflag > 1)
printf("u->d %s\n", sip->name);
} else {
sip = xlookup(DSHEAD, sp->name, extp);
if (sip)
def2chk(sip, sp);
else
newdef(sp, extp, op);
}
}
return 0;
}
def2chk(sip, sp)
struct sinfo *sip;
struct sym *sp;
{
if (sip->flags == COMMDEF && sp->flags == COMMDEF) {
if (sip->value != sp->value) {
warns("common sizes differ for", sip->name);
if (sp->value > sip->value)
sip->value = sp->value;
}
} else
fatals("double definition of", sip->name);
}
newdef(sp, extp, op) /* hashv set by caller */
struct sym *sp;
char *extp;
struct oinfo *op;
{
struct sinfo *sip;
sip = newsinfo(sp->name, extp);
sip->flags = sp->flags;
sip->value = sp->value;
sip->obj = op;
listins(&DSHEAD, sip);
if (vflag > 1)
printf("def %s\n", sip->name);
}
notglob(flags)
{
if (flags & F_GLBL)
return 0;
if (flags == EXTREF)
return 0;
return 1;
}
special(s)
char *s;
{
if (strcmp(s, "_end") == 0)
return 1;
if (strcmp(s, "_etext") == 0)
return 1;
if (strcmp(s, "_edata") == 0)
return 1;
return 0;
}
end_sym(s, val, flag)
char *s;
long val;
{
struct sinfo *sip;
#ifdef NHASH
hashv = hash(s);
#endif
sip = xlookup(USHEAD, s, 0L);
if (sip) {
listdel(&USHEAD, sip);
sip->flags = flag;
sip->value = val;
sip->obj = 0;
listins(&DSHEAD, sip);
}
}
chk_undefs()
{
struct sinfo *sp;
int any = 0;
#ifdef NHASH
for (hashv=0; hashv < NHASH; hashv++)
#endif
{
sp = USHEAD;
while (sp) {
if (!special(sp->name)) {
any = 1;
printf("undefined symbol %s", sp->name);
if (sp->obj) {
printf(" from %s", sp->obj->finfo->name);
if (sp->obj->aname[0])
printf("(%.14s)", sp->obj->aname);
}
putchar('\n');
}
sp = sp->next;
}
}
if (any)
fatal("load aborted due to undefined symbols");
}
long
mkcomm(where)
long where;
{
struct sinfo *sp;
long size, base, obase;
base = obase = where;
#ifdef NHASH
for (hashv=0; hashv < NHASH; hashv++)
#endif
{
sp = DSHEAD;
while (sp) {
if (sp->flags == COMMDEF) {
size = sp->value;
sp->value = base;
sp->flags = (F_BSS|F_GLBL|F_DEF);
base += size;
}
sp = sp->next;
}
}
return base - obase;
}
adjsyms()
{
struct sinfo *sp;
#ifdef NHASH
for (hashv=0; hashv < NHASH; hashv++)
#endif
{
sp = DSHEAD;
while (sp) {
switch (sp->flags & 7) {
case F_TEXT:
sp->value += sp->obj->tbase;
break;
case F_DATA:
sp->value += sp->obj->dbase;
break;
case F_BSS:
sp->value += sp->obj->bbase;
break;
}
sp = sp->next;
}
}
}
long
countsyms()
{
long n;
struct sinfo *sp;
if (only8)
n = 0;
else
n = 1;
#ifdef NHASH
for (hashv=0; hashv < NHASH; hashv++)
#endif
{
sp = DSHEAD;
while (sp) {
n += count1(sp);
sp = sp->next;
}
}
return n * SYMSIZE;
}
count1(sp)
struct sinfo *sp;
{
int n;
if (only8)
return 1;
n = strlen(sp->name);
if (n == 9 && sp->name[8] == '*')
n = 8;
if (n == 0)
fatal("zero length name");
return (n+7)/8;
}
char zname[8];
#ifndef UNIXHOST
#define FIXSYM(a)
#else
#define FIXSYM(a) fixsym(a)
#endif
wrsyms(fd)
{
struct sinfo *sp;
struct sym s;
if (!only8) {
bcopy(zname, s.name, 8);
strncpy(s.name, XNAME, 8);
s.flags = XFLAGS;
s.mark = 0;
s.value = XVALUE;
FIXSYM(&s);
write(fd, &s, SYMSIZE);
}
#ifdef NHASH
for (hashv=0; hashv < NHASH; hashv++)
#endif
{
sp = DSHEAD;
while (sp) {
bcopy(zname, s.name, 8);
strncpy(s.name, sp->name, 8);
s.flags = sp->flags;
s.mark = 0;
s.value = sp->value;
FIXSYM(&s);
write(fd, &s, SYMSIZE);
if (!only8) {
int n, i;
n = strlen(sp->name);
if (n == 9 && sp->name[8] == '*')
n = 8;
i = 8;
while (n > i) {
bcopy(zname, s.name, 8);
strncpy(s.name, &sp->name[i], 8);
s.flags = XFLAGS;
s.mark = 0;
s.value = XVALUE;
i += 8;
FIXSYM(&s);
write(fd, &s, SYMSIZE);
}
}
sp = sp->next;
}
}
}
struct sym *
chunki(x, chpp)
unsigned x;
struct symchunk **chpp;
{
unsigned k, i;
struct sym *sp;
struct symchunk *chp;
chp = *chpp;
i = 0;
while (chp) {
k = chp->nsyms;
if (x < i+k) {
sp = &chp->s[x-i];
*chpp = chp;
return sp;
}
i += k;
chp = chp->next;
}
fatal("bad relocation index");
}
long
findx(x, chp, havex, relp)
unsigned short x;
struct symchunk *chp;
short *relp;
{
struct sinfo *sip;
struct sym *sp;
char *extp;
x >>= 3;
sp = chunki(x, &chp);
#ifdef NHASH
hashv = hash(sp->name);
#endif
if (sp->mark == 0) {
if (sp->name[7])
extp = getext(chp, sp, havex);
else
extp = 0;
sip = xlookup(DSHEAD, sp->name, extp);
if (sip == 0)
fatal("Cant find symbol");
switch (sip->flags & 7) {
case 1:
sp->mark = 3; break;
case 2:
sp->mark = 2; break;
case 4:
sp->mark = 1; break;
default:
fatal("Bad sym type");
}
sp->value = sip->value;
}
*relp = sp->mark;
return sp->value;
}
#ifdef NHASH
/* only use 1st 8 chars for hash value! */
hash(s)
unsigned char *s;
{
unsigned char c;
register i, n = 0;
for (i=1; i<5; i++) {
c = s[i];
if (!c)
break;
n = (n<<1)|c;
}
return n & (NHASH-1);
}
#endif