P8000/WEGA/contrib/lcc/cmd/lld.c

2249 lines
51 KiB
C

/*
* lld - string table version for P8000
*/
#include <sys/param.h>
#include <signal.h>
#include <stdio.h>
#include <ctype.h>
#include <ar.h>
#include <s.out.h>
#include <sys/stat.h>
#include <sys/file.h>
#define SARMAG 2L
#define MAXPATHLEN 256
#define O_RDONLY 000
/*
* Macros which take exec structures as arguments and tell whether
* the file has a reasonable magic number or offsets to text|symbols|strings.
*/
#define N_BADMAG(x) \
(((x).s_magic)!=S_MAGIC3 && ((x).s_magic)!=S_MAGIC1)
#define N_TXTOFF(x) \
(sizeof (struct s_exec) + (x).s_segt )
#define N_SYMOFF(x) \
(N_TXTOFF(x) + (x).s_imsize + (((x).s_flag & SF_STRIP) == 0 ? \
(x).s_imsize : 0 ))
/*
* Internal data structures
*
* All internal data structures are segmented and dynamically extended.
* The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT)
* referenced library members, and 100 (NSYMPR) private (local) symbols
* per object module. For large programs and/or modules, these structures
* expand to be up to 40 (NSEG) times as large as this as necessary.
*/
#define NSEG 40 /* Number of segments, each data structure */
#define NSYM 1103 /* Number of symbols per segment */
#define NROUT 250 /* Number of library references per segment */
#define NSYMPR 100 /* Number of private symbols per segment */
/*
* Structure describing each symbol table segment.
* Each segment has its own hash table. We record the first
* address in and first address beyond both the symbol and hash
* tables, for use in the routine symx and the lookup routine respectively.
* The symfree routine also understands this structure well as it used
* to back out symbols from modules we decide that we don't need in pass 1.
*
* Csymseg points to the current symbol table segment;
* csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated,
* (unless csymseg->sy_used == NSYM in which case we will allocate another
* symbol table segment first.)
*/
struct symseg {
struct nlist *sy_first; /* base of this alloc'ed segment */
struct nlist *sy_last; /* end of this segment, for sn_strx */
int sy_used; /* symbols used in this seg */
struct nlist **sy_hfirst; /* base of hash table, this seg */
struct nlist **sy_hlast; /* end of hash table, this seg */
} symseg[NSEG], *csymseg;
/*
* The lookup routine uses quadratic rehash. Since a quadratic rehash
* only probes 1/2 of the buckets in the table, and since the hash
* table is segmented the same way the symbol table is, we make the
* hash table have twice as many buckets as there are symbol table slots
* in the segment. This guarantees that the quadratic rehash will never
* fail to find an empty bucket if the segment is not full and the
* symbol is not there.
*/
#define HSIZE (NSYM*2)
/*
* Xsym converts symbol table indices (ala x) into symbol table pointers.
* Symx (harder, but never used in loops) inverts pointers into the symbol
* table into indices using the symseg[] structure.
*/
#define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM))
/* symx() is a function, defined below */
struct nlist {
long n_value;
char n_type;
char n_segt;
union {
char *n_name;
char w_name[8];
}n_un;
int n_hash;
};
#define LIBF 0x80 /* internes Bit in n_type
zeigt an, dass Fkt. aus einer Bibl. kommt */
struct nlist cursym; /* current symbol */
struct nlist *lastsym; /* last symbol entered */
struct nlist *nextsym; /* next available symbol table entry */
struct nlist *addsym; /* first sym defined during incr load */
int nsym; /* pass2: number of local symbols in a.out */
/* nsym + symx(nextsym) is the symbol table size during pass2 */
struct nlist **lookup(), **slookup();
struct nlist *p_etext, *p_edata, *p_end, *entrypt, *p_stkseg;
#define STKSEG 0x7f000000
#define N_COMM 0x05
/*
* Definitions of segmentation for library member table.
* For each library we encounter on pass 1 we record pointers to all
* members which we will load on pass 2. These are recorded as offsets
* into the archive in the library member table. Libraries are
* separated in the table by the special offset value -1.
*/
off_t li_init[NROUT];
struct libseg {
off_t *li_first;
int li_used;
int li_used2;
} libseg[NSEG] = {
li_init, 0, 0,
}, *clibseg = libseg;
/*
* In processing each module on pass 2 we must relocate references
* relative to external symbols. These references are recorded
* in the relocation information as relative to local symbol numbers
* assigned to the external symbols when the module was created.
* Thus before relocating the module in pass 2 we create a table
* which maps these internal numbers to symbol table entries.
* A hash table is constructed, based on the local symbol table indices,
* for quick lookup of these symbols.
*/
#define LHSIZ 31
struct local {
int l_index; /* index to symbol in file */
struct nlist *l_symbol; /* ptr to symbol table */
struct local *l_link; /* hash link */
} *lochash[LHSIZ], lhinit[NSYMPR];
struct locseg {
struct local *lo_first;
int lo_used;
} locseg[NSEG] = {
lhinit, 0
}, *clocseg;
/*
* We open each input file or library only once, but in pass2 we
* (historically) read from such a file at 2 different places at the
* same time. These structures are remnants from those days,
* and now serve only to catch ``Premature EOF''.
* In order to make I/O more efficient, we provide routines which
* use the optimal block size returned by stat().
*/
#define BLKSIZE 512
typedef struct {
short *fakeptr;
int bno;
int nibuf;
int nuser;
char *buff;
int bufsize;
} PAGE;
PAGE page[2];
int p_blksize;
int p_blkshift;
int p_blkmask;
struct {
short *fakeptr;
int bno;
int nibuf;
int nuser;
} fpage;
typedef struct {
char *ptr;
int bno;
int nibuf;
long size;
long pos;
PAGE *pno;
} STREAM;
STREAM text;
STREAM reloc;
/*
* Libraries are typically built with a table of contents,
* which is the first member of a library with special file
* name __.SYMDEF and contains a list of symbol names
* and with each symbol the offset of the library member which defines
* it. The loader uses this table to quickly tell which library members
* are (potentially) useful. The alternative, examining the symbol
* table of each library member, is painfully slow for large archives.
*
* See <ranlib.h> for the definition of the ranlib structure and an
* explanation of the __.SYMDEF file format.
*/
struct ranlib {
long ran_off;
char ran_name[8];
};
int tnum; /* number of symbols in table of contents */
struct ranlib *tab; /* the table of contents (dynamically allocated) */
/*
* Header from the a.out and the archive it is from (if any).
*/
struct s_exec filhdr;
struct ar_hdr archdr;
#define OARMAG 0177545
unsigned fsyms;
/*
* Options.
*/
int trace;
int Mflag; /* print rudimentary load map */
int sflag;
int rflag;
int wflag; /* no warning for redefined */
char **ytab; /* the symbols */
/*
* These are the cumulative sizes, set in pass 1, which
* appear in the a.out header when the loader is finished.
*/
off_t tsize, dsize, bsize, trsize, drsize, ssize;
/*
* Symbol relocation: c?rel is a scale factor which is
* added to an old relocation to convert it to new units;
* i.e. it is the difference between segment origins.
* (Thus if we are loading from a data segment which began at location
* 4 in a .o file into an a.out where it will be loaded starting at
* 1024, cdrel will be 1020.)
*/
long ctrel, cdrel, cbrel;
/*
* Textbase is the start address of all text, 0 unless given by -T.
* Database is the base of all data, computed before and used during pass2.
*/
long textbase, database;
/*
* The base addresses for the loaded text, data and bss from the
* current module during pass2 are given by torigin, dorigin and borigin.
*/
long torigin, dorigin, borigin;
/*
* Structuren und Konstanten fuer die Segmentzuordnung
* und fuer die Adressberechnung
*/
#define MAXSEG 31 /* max. Anzahl der Segmente */
#define TEXTBASE 0x00000000
#define DATABASE 0x20000000
#define BSSBASE 0x40000000
#define FIRSTTSEG 0x00
#define FIRSTDSEG 0x20
#define FIRSTBSEG 0x40
#define LASTTSEG 0x1f
#define LASTDSEG 0x3f
#define LASTBSEG 0x5f
#define SEGSIZE 0x0000fffe /* Groesse eines Segmentes */
/* Segmentzuordnungstabellen
mit der Nummer des Segmenttabelleneintrages und
einer relativen Adresse fuer Text, Daten und BSS */
struct szt {
char tseg;
long trel;
char dseg;
long drel;
char bseg;
long brel;
};
struct segt *tptr; /* Zeiger auf Anfang der Text-Segmenttabellen */
struct segt *dptr; /* Zeiger auf Anfang der Daten-Segmenttabellen */
struct segt *bptr; /* Zeiger auf Anfang der BSS-Segmenttabellen */
struct segt *ctptr; /* Aktuelle Segmenttabelle mit Text */
struct segt *cdptr; /* Aktuelle Segmenttabelle mit Daten */
struct segt *cbptr; /* Aktuelle Segmenttabelle mit BSS */
struct segt *cptr; /* Naechste verfuegbare leere Segmenttabelle */
struct szt *szstr; /* Zeiger auf erste Struktur der Segmentzuordnungs-
tabellen */
char ctnr, cdnr, cbnr, cnr; /* Segmentnummern */
/*
* Errlev is nonzero when errors have occured.
* Delarg is an implicit argument to the routine delexit
* which is called on error. We do ``delarg = errlev'' before normal
* exits, and only if delarg is 0 (i.e. errlev was 0) do we make the
* result file executable.
*/
int errlev;
int delarg = 4;
/*
* The biobuf structure and associated routines are used to write
* into one file at several places concurrently. Calling bopen
* with a biobuf structure sets it up to write ``biofd'' starting
* at the specified offset. You can then use ``bwrite'' and/or ``bputc''
* to stuff characters in the stream, much like ``fwrite'' and ``fputc''.
* Calling bflush drains all the buffers and MUST be done before exit.
*/
struct biobuf {
short b_nleft; /* Number free spaces left in b_buf */
/* Initialize to be less than b_bufsize initially, to boundary align in file */
char *b_ptr; /* Next place to stuff characters */
char *b_buf; /* Pointer to the buffer */
int b_bufsize; /* Size of the buffer */
off_t b_off; /* Current file offset */
struct biobuf *b_link; /* Link in chain for bflush() */
} *biobufs;
#define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \
: bflushc(b, c))
int biofd;
off_t boffset;
struct biobuf *tout, *dout, *trout, *drout, *sout, *strout;
/*
* Offset is the current offset in the string file.
* Its initial value reflects the fact that we will
* eventually stuff the size of the string table at the
* beginning of the string table (i.e. offset itself!).
*/
off_t offset = sizeof (off_t);
int ofilfnd; /* -o given; otherwise move l.out to a.out */
char *ofilename = "l.out";
int ofilemode; /* respect umask even for unsucessful ld's */
int infil; /* current input file descriptor */
char *filname; /* and its name */
#define NDIRS 25
#define NDEFDIRS 3 /* number of default directories in dirs[] */
char *dirs[NDIRS]; /* directories for library search */
int ndir; /* number of directories */
/*
* Base of the string table of the current module (pass1 and pass2).
*/
char *curstr;
/*
* System software page size, as returned by getpagesize.
*/
long pagesize;
char get();
int delexit();
char *savestr();
char *malloc();
long calloc();
long round();
main(argc, argv)
char **argv;
{
register int c, i;
int num;
register char *ap, **p;
char save;
if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
signal(SIGINT, delexit);
signal(SIGTERM, delexit);
}
if (argc == 1)
exit(4);
/*pagesize = (long)getpagesize();*/
pagesize = 256L;
/*
* Pull out search directories.
*/
for (c = 1; c < argc; c++) {
ap = argv[c];
if (ap[0] == '-' && ap[1] == 'L') {
if (ap[2] == 0)
error(1, "-L: pathname missing");
if (ndir >= NDIRS - NDEFDIRS)
error(1, "-L: too many directories");
dirs[ndir++] = &ap[2];
}
}
/* add default search directories */
dirs[ndir++] = "/z/LCC/lib";
p = argv+1;
/*
* Scan files once to find where symbols are defined.
*/
for (c=1; c<argc; c++) {
filname = 0;
ap = *p++;
if (*ap != '-') {
if (trace)
printf("%s:\n", ap);
load1arg(ap);
continue;
}
for (i=1; ap[i]; i++) switch (ap[i]) {
case 'o':
if (++c >= argc)
error(1, "-o where?");
ofilename = *p++;
ofilfnd++;
continue;
case 'e':
if (++c >= argc)
error(1, "-e: arg missing");
enter(slookup(*p++));
if (ap[i]=='e')
entrypt = lastsym;
continue;
case 'l':
if (trace)
printf("%s:\n", ap);
save = ap[--i];
ap[i]='-';
load1arg(&ap[i]);
ap[i]=save;
goto next;
case 'M':
Mflag++;
continue;
case 't':
trace++;
printf("*** pass1 ***\n");
continue;
case 's':
sflag++;
continue;
case 'w':
wflag++;
continue;
case 'L':
goto next;
case 'x':
case 'X':
case 'z':
case 'i':
continue; /* kompatible sld */
default:
filname = savestr("-x"); /* kludge */
filname[1] = ap[i]; /* kludge */
archdr.ar_name[0] = 0; /* kludge */
error(1, "bad flag");
}
next:
;
}
endload(argc, argv);
exit(0);
}
delexit()
{
struct stat stbuf;
long size;
char c = 0;
bflush();
unlink("l.out");
/*
* We have to insure that the last block of the data segment
* is allocated a full pagesize block. If the underlying
* file system allocates frags that are smaller than pagesize,
* a full zero filled pagesize block needs to be allocated so
* that when it is demand paged, the paged in block will be
* appropriately filled with zeros.
*/
fstat(biofd, &stbuf);
size = round(stbuf.st_size, pagesize);
if (delarg==0)
(void) chmod(ofilename, ofilemode);
exit (delarg);
}
/*
* Scan file to find defined symbols.
*/
load1arg(cp)
register char *cp;
{
register struct ranlib *tp;
off_t nloc;
int kind;
char *p;
kind = getfile(cp);
if (Mflag)
printf("%s\n", filname);
switch (kind) {
/*
* Plain file.
*/
case 0:
load1(0, 0L);
break;
/*
* Archive without table of contents.
* (Slowly) process each member.
*/
case 1:
nloc = SARMAG;
while (step(nloc))
nloc += sizeof(archdr) +
round(archdr.ar_size, (long)(sizeof (short)));
break;
/*
* Archive with table of contents.
* Read the table of contents and its associated string table.
* Pass through the library resolving symbols until nothing changes
* for an entire pass (i.e. you can get away with backward references
* when there is a table of contents!)
*/
case 2:
if(Mflag)
printf("Archive with table of contents\n");
nloc = SARMAG + sizeof (archdr);
tab = (struct ranlib *)malloc((int)archdr.ar_size+1);
if (tab==0)
error(1,"ran out of memory (tab)");
dseek(&text,nloc,archdr.ar_size);
mget((char *)tab,archdr.ar_size,&text);
p= (char *)tab + archdr.ar_size;
*p=0;
tnum = archdr.ar_size / sizeof(struct ranlib);
while (ldrand())
continue;
free((char *)tab);
nextlibp(-1L);
break;
/*
* Table of contents is out of date, so search
* as a normal library (but skip the __.SYMDEF file).
*/
case 3:
error(-1,"warning: table of contents is out of date\n");
nloc = SARMAG;
do
nloc += sizeof(archdr) + round(archdr.ar_size, (long)(sizeof(short)));
while (step(nloc));
break;
}
close(infil);
}
/*
* Advance to the next archive member, which
* is at offset nloc in the archive. If the member
* is useful, record its location in the liblist structure
* for use in pass2. Mark the end of the archive in libilst with a -1.
*/
step(nloc)
off_t nloc;
{
dseek(&text, nloc, (long) sizeof archdr);
if (text.size <= 0) {
nextlibp(-1L);
return (0);
}
getarhdr();
if (strncmp(archdr.ar_name,"Library.SC",sizeof(archdr.ar_name))==0)
return(1);
if (load1(1, nloc + (sizeof archdr)))
nextlibp(nloc);
return (1);
}
/*
* Record the location of a useful archive member.
* Recording -1 marks the end of files from an archive.
* The liblist data structure is dynamically extended here.
*/
nextlibp(val)
off_t val;
{
if (clibseg->li_used == NROUT) {
if (++clibseg == &libseg[NSEG])
error(1, "too many files loaded from libraries");
clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t));
if (clibseg->li_first == 0)
error(1, "ran out of memory (nextlibp)");
}
clibseg->li_first[clibseg->li_used++] = val;
if (val != -1 && Mflag)
printf("\t%s\n", archdr.ar_name);
}
/*
* One pass over an archive with a table of contents.
* Remember the number of symbols currently defined,
* then call step on members which look promising (i.e.
* that define a symbol which is currently externally undefined).
* Indicate to our caller whether this process netted any more symbols.
*/
ldrand()
{
register struct nlist *sp, **hp;
register struct ranlib *tp, *tplast;
off_t loc;
int nsymt = symx(nextsym);
char str[150];
tplast = &tab[tnum-1];
for (tp = tab; tp <= tplast; tp++) {
if ((hp = slookup(tp->ran_name)) == 0 || *hp == 0)
continue;
sp = *hp;
if ((sp->n_type & 0x3f) != N_EXT+N_UNDF){ /*segmented bit
ausblenden ?? */
if(((sp->n_type & 0x80) == 0) && wflag==0){
sprintf(str,"- warning symbol (%s) redefined",sp->n_un.n_name);
error(-1,str);
}
continue;
}
step(tp->ran_off);
loc = tp->ran_off;
while (tp < tplast && (tp+1)->ran_off == loc){
tp++;
}
}
return (symx(nextsym) != nsymt);
}
/*
* Examine a single file or archive member on pass 1.
*/
load1(libflg, loc)
off_t loc;
{
register struct nlist *sp;
struct nlist *savnext;
int ndef, nlocal, size, nsymt, x;
char type;
register int i;
off_t maxoff;
struct stat stb;
char *p;
char *savecur;
char *curptr, *segstr;
struct szt *zp;
struct segt *cp;
char ctseg, cdseg, cbseg;
unsigned curt, curd, curb;
int segcnt;
long cr;
char str[150];
/* reservieren des Speicherplatzes fuer die gesamte Segmenttabelle*/
if ( tptr == 0 ) {
tptr=(struct segt *)calloc(MAXSEG-1, sizeof (struct segt));
dptr=(struct segt *)calloc(MAXSEG-1, sizeof (struct segt));
bptr=(struct segt *)calloc(MAXSEG-1, sizeof (struct segt));
if (tptr == 0 || dptr == 0 || bptr == 0)
error(1, "ran out of space for segmenttable");
/* initialisieren der ersten Segmente */
ctptr=tptr;
ctptr->sg_atr=SG_CODE;
ctptr->sg_segno = ctnr = FIRSTTSEG;
cdptr = dptr;
cdptr->sg_atr=SG_DATA;
cdptr->sg_segno = cdnr = FIRSTDSEG;
cbptr = bptr;
cbptr->sg_atr=SG_BSS;
cbptr->sg_segno = cbnr = FIRSTBSEG;
}
curt = ctptr->sg_code;
curd = cdptr->sg_data;
curb = cbptr->sg_bss;
ctseg = ctnr;
cdseg = cdnr;
cbseg = cbnr;
readhdr(loc);
if (filhdr.s_syms == 0) {
if (filhdr.s_imsize == 0)
return (0);
error(1, "no namelist");
}
if (libflg)
maxoff = archdr.ar_size;
else {
fstat(infil, &stb);
maxoff = stb.st_size;
}
/* reservieren des Speicherplatzes fuer die Segmenttabelle der
aktuellen Datei */
segstr=(char *)malloc(filhdr.s_segt);
if(segstr == NULL)
error(1,"no space for segmenttable");
loc += (long)sizeof(struct s_exec);
dseek(&text, loc, (long)filhdr.s_segt);
mget((char *)segstr,(long)filhdr.s_segt, &text);
segcnt = filhdr.s_segt >> 4; /*Anzahl der Segmente*/
szstr= (struct szt *)calloc(segcnt,sizeof(struct szt));
if (szstr == 0)
error(1,"no space for segmenttable");
cp = (struct segt *)segstr;
zp = (struct szt *)szstr;
for ( x=0 ; x<segcnt ; cp++ , x++ , zp++) {
if(cp->sg_code) {
if((long)curt+(long)cp->sg_code > SEGSIZE) {
curt = 0 ; ctseg++ ;
}
zp->trel = (long)curt - ((long)cp->sg_coff<<8);
zp->tseg = ctseg;
curt += cp->sg_code;
}
if(cp->sg_data) {
if((long)curd+(long)cp->sg_data > SEGSIZE) {
curd = 0 ; cdseg++;
}
zp->drel = (long)curd - ((long)cp->sg_doff<<8);
zp->dseg = cdseg;
curd += cp->sg_data;
}
if(cp->sg_bss) {
if((long)curb+(long)cp->sg_bss > SEGSIZE) {
curb = 0 ; cbseg++;
}
zp->brel = (long)curb - ((long)cp->sg_boff<<8);
zp->bseg = cbseg;
curb += cp->sg_bss;
}
}
ndef = 0;
nlocal = sizeof(cursym);
savnext = nextsym;
loc += filhdr.s_segt+filhdr.s_imsize+((filhdr.s_flag & SF_STRIP)==0 ? filhdr.s_imsize : 0 );
dseek(&text, loc, (long)filhdr.s_syms);
curstr = (char *)malloc(filhdr.s_syms);
if (curstr == NULL)
error(1, "no space for string table");
curptr=curstr;
while (text.size > 0) {
mget((char *)&cursym, 14L , &text);
savecur=curptr;
p = (char *) &cursym.n_un.n_name;
if( *p & LONGBIT) {
/* Long name */
x= *p & LONGMASK;
for(i=0;i<7;i++)
*(curptr++) = *(++p);
for(i=14; i < (x-7); i += 14);
mget((char *)curptr,(long)i,&text);
curptr += i;
}
else /* short name */ {
for(i=0;i<8;i++){
if(p[i]==0) break;
*(curptr++)=p[i];
}
}
*(curptr++)=0;
cursym.n_un.n_name=savecur;
type = cursym.n_type;
if(libflg && (type&0x3f)!=N_EXT+N_UNDF)
cursym.n_type |=0x80;
cursym.n_hash = 0;
if ((type&N_EXT)==0) {
nlocal += sizeof cursym;
continue;
}
symreloc();
if (enter(lookup()))
continue;
if (((sp = lastsym)->n_type & 0x3f) != N_EXT+N_UNDF){
/* segmented bit ausblenden ? */
if(((cursym.n_type&0x3f) != N_EXT+N_UNDF)&&libflg&&((sp->n_type&0x80)==0)&&wflag==0) {
sprintf(str,"- warning symbol (%s) redefined in archive",cursym.n_un.n_name);
error(-1,str);
}
continue;
}
if ((cursym.n_type & 0x3f) == N_EXT+N_UNDF) {
/* segmented bit ausbl. ?? */
if (cursym.n_value > sp->n_value)
sp->n_value = cursym.n_value;
continue;
}
if (sp->n_value != 0 && (cursym.n_type & 0x3f) == N_EXT+N_CODE)
/* seg. bit ausbl. ? */
continue;
ndef++;
if(libflg) cursym.n_type |= 0x80;
sp->n_type = cursym.n_type;
sp->n_value = cursym.n_value;
}
if (libflg==0 || ndef) {
cp = (struct segt *)segstr;
for ( x=0 ; x<segcnt ; cp++ , x++ ) {
if(cp->sg_code) {
if((long)ctptr->sg_code+(long)cp->sg_code > SEGSIZE) {
cr=round((long)ctptr->sg_code,pagesize);
if(cr > SEGSIZE)
cr = SEGSIZE;
tsize += cr-(long)ctptr->sg_code;
ctptr->sg_code=(int)cr;
ctptr++;
ctptr->sg_atr=SG_CODE;
ctptr->sg_segno= ++ctnr;
if(ctnr>LASTTSEG)
error(1,"too many text segments");
}
ctptr->sg_code += cp->sg_code;
tsize += cp->sg_code;
}
if(cp->sg_data) {
if((long)cdptr->sg_data+(long)cp->sg_data > SEGSIZE) {
cr=round((long)cdptr->sg_data,pagesize);
if(cr > SEGSIZE)
cr = SEGSIZE;
dsize += cr-(long)cdptr->sg_data;
cdptr->sg_data=(int)cr;
cdptr++;
cdptr->sg_atr=SG_DATA;
cdptr->sg_segno= ++cdnr;
if(cdnr > LASTDSEG)
error(1,"too many data segments");
}
cdptr->sg_data += cp->sg_data;
dsize += cp->sg_data;
}
if(cp->sg_bss) {
if((long)cbptr->sg_bss+(long)cp->sg_bss > SEGSIZE) {
cr=round((long)cbptr->sg_bss,pagesize);
if(cr > SEGSIZE)
cr = SEGSIZE;
bsize += cr-(long)cbptr->sg_bss;
cbptr->sg_bss=(int)cr;
cbptr++;
cbptr->sg_atr=SG_BSS;
cbptr->sg_segno= ++cbnr;
if(cbnr>LASTBSEG)
error(1,"too many bss segments");
}
cbptr->sg_bss += cp->sg_bss;
bsize += cp->sg_bss;
}
}
ssize += nlocal;
nsymt = symx(nextsym);
for (i = symx(savnext); i < nsymt; i++) {
sp = xsym(i);
sp->n_un.n_name = savestr(sp->n_un.n_name);
}
free(curstr);
free(segstr);
free(szstr);
return (1);
}
/*
* No symbols defined by this library member.
* Rip out the hash table entries and reset the symbol table.
*/
symfree(savnext);
free(curstr);
free(segstr);
free(szstr);
return(0);
}
endload(argc, argv)
int argc;
char **argv;
{
register int c, i;
long dnum;
register char *ap, **p;
clibseg = libseg;
filname = 0;
middle();
setupout();
p = argv+1;
if(trace)
printf("*** pass2 ***\n");
for (c=1; c<argc; c++) {
ap = *p++;
if (*ap != '-') {
if (trace)
printf("%s:\n",ap);
load2arg(ap);
continue;
}
for (i=1; ap[i]; i++) switch (ap[i]) {
case 'o':
case 'e':
++c;
++p;
default:
continue;
case 'l':
if (trace)
printf("%s:\n",ap);
ap[--i]='-';
load2arg(&ap[i]);
goto next;
}
next:
;
}
if(trace)
printf("tsize = %lx\ndsize = %lx\nbsize = %lx\n",tsize,dsize,bsize);
finishout();
}
middle()
{
register struct nlist *sp;
long csize, t, corigin, ocsize, cr;
int nund, rnd;
char s;
register int i;
int nsymt;
/*
torigin = 0;
dorigin = 0;
borigin = 0;
p_etext = *slookup("_etext");
p_edata = *slookup("_edata");
p_end = *slookup("_end");
*/
p_stkseg = *slookup("_stkseg");
p_stkseg->n_type = N_EXT+N_ABS;
p_stkseg->n_value = STKSEG;
/*
* If there are any undefined symbols, save the relocation bits.
*/
nsymt = symx(nextsym);
/*
for (i = 0; i < nsymt; i++) {
sp = xsym(i);
if ((sp->n_type & 0x3f)==N_EXT+N_UNDF && sp->n_value==0 && sp!=p_stkseg ) {
rflag++;
printf("undefined: %s\n",sp->n_un.n_name);
}
}
if (rflag)
error(1,"undefined symbols");
*/
/*
* Assign common locations.
*/
csize = 0;
addsym = symseg[0].sy_first;
for (i = symx(addsym); i < nsymt; i++) {
sp = xsym(i);
if ((s=(sp->n_type&0x3f) == N_EXT+N_UNDF) && ((t = sp->n_value&0xffff)!=0)) {
/*
if (t >= sizeof (double))
rnd = sizeof (double);
else if (t >= sizeof (long))
rnd = sizeof (long);
else
rnd = sizeof (short);
*/
csize = (long)cbptr->sg_bss;
if(t >= (long)sizeof(int))
/* wenn >= 2byte wird auf gerades byte aufgerundet */
csize = round(csize, (long)sizeof(int));
if((csize + t) > SEGSIZE) {
cr=round((long)cbptr->sg_bss,pagesize);
if(cr > SEGSIZE)
cr = SEGSIZE;
bsize += cr-(long)cbptr->sg_bss;
cbptr->sg_bss=(int)cr;
csize = 0;
cbptr++;
cbptr->sg_atr = SG_BSS;
cbptr->sg_segno = ++cbnr;
if(cbnr > LASTBSEG)
error(1,"too many bss segments");
}
bsize += csize - (long)cbptr->sg_bss;
sp->n_value = (long)cbnr <<24;
sp->n_value += csize;
sp->n_type = N_EXT+N_COMM;
cbptr->sg_bss = (int)csize + (int)t;
bsize += t;
}
}
/*
* Now set symbols to their final value
*/
torigin = TEXTBASE;
dorigin = ((long)ctnr+1)<<24;
borigin = dorigin+(((long)(cdnr&0x1f)+1)<<24);
cr=round((long)ctptr->sg_code,pagesize);
if (cr > SEGSIZE)
cr = SEGSIZE;
tsize += cr-(long)ctptr->sg_code;
ctptr->sg_code=(int)cr;
cr=round((long)cdptr->sg_data,pagesize);
if (cr > SEGSIZE)
cr = SEGSIZE;
dsize += cr-(long)cdptr->sg_data;
cdptr->sg_data=(int)cr;
cr=round((long)cbptr->sg_bss,pagesize);
if (cr > SEGSIZE)
cr = SEGSIZE;
bsize += cr-(long)cbptr->sg_bss;
cbptr->sg_bss=(int)cr;
nund=0;
nsymt = symx(nextsym);
for (i = symx(addsym); i<nsymt; i++) {
sp = xsym(i);
switch (sp->n_type & (N_TYPE+N_EXT)) {
case N_EXT+N_UNDF:
if (nund==0)
printf("Undefined:\n");
nund++;
printf("%s\n", sp->n_un.n_name);
continue;
case N_EXT+N_ABS:
default:
continue;
case N_EXT+N_CODE:
continue;
case N_EXT+N_DATA:
sp->n_value = (sp->n_value&0x1fffffff) + dorigin;
continue;
case N_EXT+N_COMM:
sp->n_type = (N_EXT+N_BSS);
case N_EXT+N_BSS:
sp->n_value = (sp->n_value&0x1fffffff) + borigin;
continue;
}
}
if(nund)
error(1,"");
nsym = 0;
}
fixspec(sym,offset)
struct nlist *sym;
long offset;
{
if(symx(sym) < symx(addsym) && sym!=0)
sym->n_value += offset;
}
ldrsym(sp, val, type)
register struct nlist *sp;
long val;
char type;
{
if (sp == 0)
return;
if (((sp->n_type&0x3f) != N_EXT+N_UNDF || sp->n_value)) {
printf("%s: ", sp->n_un.n_name);
error(0, "user attempt to redfine loader-defined symbol");
return;
}
sp->n_type = type;
sp->n_value = val;
}
load2arg(acp)
char *acp;
{
register char *cp;
off_t loc;
cp = acp;
if (getfile(cp) == 0) {
while (*cp)
cp++;
while (cp >= acp && *--cp != '/');
mkfsym(++cp);
load2(0L);
} else { /* scan archive members referenced */
for (;;) {
if (clibseg->li_used2 == clibseg->li_used) {
if (clibseg->li_used < NROUT)
error(1, "libseg botch");
clibseg++;
}
loc = clibseg->li_first[clibseg->li_used2++];
if (loc == -1)
break;
dseek(&text, loc, (long)sizeof(archdr));
getarhdr();
mkfsym(archdr.ar_name);
load2(loc + (long)sizeof(archdr));
}
}
close(infil);
}
load2(loc)
long loc;
{
int size;
register struct segt *cp;
register struct szt *zp;
struct nlist *sp;
struct local *lp;
register int symno,xsymno, i;
int x;
int type;
char cdseg,ctseg,cbseg;
unsigned curt,curd,curb;
char *segstr, *savecur, *curptr, *p;
struct nlist *savnext;
int ndef, segcnt;
int nlocal;
long loc1;
readhdr(loc);
/*
* Reread the symbol table, recording the numbering
* of symbols for fixing external references.
*/
for (i = 0; i < LHSIZ; i++)
lochash[i] = 0;
clocseg = locseg;
clocseg->lo_used = 0;
symno = -1;
curt = (unsigned)(torigin & 0xffff);
curd = (unsigned)(dorigin & 0xffff);
curb = (unsigned)(borigin & 0xffff);
ctseg = (char)((torigin >> 24) & 0xff);
cdseg = (char)((dorigin >> 24) & 0xff);
cbseg = (char)((borigin >> 24) & 0xff);
/* reservieren des Speicherplatzes fuer die Segmenttabelle der
aktuellen Datei */
segstr=(char *)malloc(filhdr.s_segt);
if(segstr == NULL)
error(1,"no space for segmenttable");
loc += (long)sizeof(struct s_exec);
dseek(&text, loc, (long)filhdr.s_segt);
mget((char *)segstr,(long)filhdr.s_segt, &text);
segcnt = filhdr.s_segt >> 4; /*Anzahl der Segmente*/
szstr= (struct szt *)calloc(segcnt,sizeof(struct szt));
if (szstr == 0)
error(1,"no space for segmenttable");
cp = (struct segt *)segstr;
zp = (struct szt *)szstr;
for ( x=0 ; x<segcnt ; cp++ , x++ , zp++) {
if(cp->sg_code) {
if((long)curt+(long)cp->sg_code >= SEGSIZE) {
curt = 0 ; ctseg++ ;
}
zp->trel = (long)curt - ((long)cp->sg_coff<<8);
zp->tseg = ctseg;
curt += cp->sg_code;
}
if(cp->sg_data) {
if((long)curd+(long)cp->sg_data >= SEGSIZE) {
curd = 0 ; cdseg++;
}
zp->drel = (long)curd - ((long)cp->sg_doff<<8);
zp->dseg = cdseg;
curd += cp->sg_data;
}
if(cp->sg_bss) {
if((long)curb+(long)cp->sg_bss >= SEGSIZE) {
curb = 0 ; cbseg++;
}
zp->brel = (long)curb - ((long)cp->sg_boff<<8);
zp->bseg = cbseg;
curb += cp->sg_bss;
}
}
ndef = 0;
nlocal = sizeof(cursym);
savnext = nextsym;
loc += filhdr.s_segt;
loc1=loc + filhdr.s_imsize +((filhdr.s_flag & SF_STRIP)==0 ? filhdr.s_imsize : 0);
dseek(&text, loc1, (long)filhdr.s_syms);
curstr = (char *)malloc(filhdr.s_syms);
if (curstr == NULL)
error(1, "no space for string table");
curptr=curstr;
xsymno = 0;
while (text.size > 0) {
symno++;
symno += xsymno;
xsymno = 0;
mget((char *)&cursym, 14L , &text);
savecur=curptr;
p = (char *) &cursym.n_un.n_name;
if( *p & LONGBIT) {
/* Long name */
x= *p & LONGMASK;
for(i=0;i<7;i++)
*(curptr++) = *(++p);
x -= 7;
while(x>0){
mget((char *)curptr, 14L, &text);
curptr += 14;
x -= 14;
xsymno++;
}
}
else /* short name */ {
for(i=0;i<8;i++){
if(p[i]==0) break;
*(curptr++)=p[i];
}
}
*(curptr++)=0;
cursym.n_un.n_name=savecur;
symreloc();
type = cursym.n_type;
if ((type&N_EXT) == 0) {
/*
symwrite(&cursym, sout);
*/
continue;
}
if ((sp = *lookup()) == 0)
error(1, "internal error: symbol not found");
if ((cursym.n_type&0x3f) == N_EXT+N_UNDF) {
if (clocseg->lo_used == NSYMPR) {
if (++clocseg == &locseg[NSEG])
error(1, "local symbol overflow");
clocseg->lo_used = 0;
}
if (clocseg->lo_first == 0) {
clocseg->lo_first = (struct local *)
malloc(NSYMPR * sizeof (struct local));
if (clocseg->lo_first == 0)
error(1, "out of memory (clocseg)");
}
lp = &clocseg->lo_first[clocseg->lo_used++];
lp->l_index = symno;
lp->l_symbol = sp;
lp->l_link = lochash[symno % LHSIZ];
lochash[symno % LHSIZ] = lp;
continue;
}
if (((cursym.n_type&0x3f) != (sp->n_type&0x3f) || cursym.n_value!=sp->n_value)&&wflag==0) {
printf(" %s: ", cursym.n_un.n_name);
error(-1, " - warning: multiply defined");
}
}
curt = (unsigned)(torigin & 0xffff);
curd = (unsigned)(dorigin & 0xffff);
ctseg = (char)((torigin >> 24) & 0xff);
cdseg = (char)((dorigin >> 24) & 0xff);
cp = (struct segt *)segstr;
zp = (struct szt *)szstr;
for(x=0; x<segcnt ; x++,cp++,zp++){
if(cp->sg_code){
if((long)curt+(long)cp->sg_code >= SEGSIZE) {
while((curt&(pagesize-1))&&((long)curt<SEGSIZE)){
bputc(0,tout);
curt++;
}
curt=0;
ctseg++;
}
dseek(&text,loc,(long)cp->sg_code);
dseek(&reloc,loc+filhdr.s_imsize,(long)cp->sg_code);
load2td(zp,tout,trout,curt,ctseg);
curt += cp->sg_code;
loc += (long)cp->sg_code;
}
if(cp->sg_data){
if((long)curd+(long)cp->sg_data >= SEGSIZE) {
while((curd&(pagesize-1))&&((long)curd<SEGSIZE)){
bputc(0,dout);
curd++;
}
curd=0;
cdseg++;
}
dseek(&text,loc,(long)cp->sg_data);
dseek(&reloc,loc+filhdr.s_imsize,(long)cp->sg_data);
load2td(zp,dout,drout,curd,cdseg);
curd += cp->sg_data;
loc += (long)cp->sg_data;
}
}
torigin = (long)curt + ((long)ctseg << 24);
dorigin = (long)curd + ((long)cdseg << 24);
borigin = (long)curb + ((long)cbseg << 24);
free(curstr);
free(segstr);
free(szstr);
}
#define R_EXT 0x0008
#define R_TYPE 0x0007
#define R_OFF 0
#define R_SEG 1
#define R_SSEG 2
#define R_R12 3
#define R_R16 4
/*
* This routine relocates the single text or data segment argument.
* Offsets from external symbols are resolved by adding the value
* of the external symbols. Non-external reference are updated to account
* for the relative motion of the segments (ctrel, cdrel, ...). If
* a relocation was pc-relative, then we update it to reflect the
* change in the positioning of the segments by adding the displacement
* of the referenced segment and subtracting the displacement of the
* current segment (creloc).
*
* If we are saving the relocation information, then we increase
* each relocation datum address by our base position in the new segment.
*/
load2td(zp, b1, b2,curadr,curseg)
struct szt *zp;
struct biobuf *b1, *b2;
long curadr;
char curseg;
{
register int *rp, *cp;
register int c;
struct nlist *sp;
struct local *lp;
long tw;
int *rpend, *relp;
int *codep;
int num;
long relsz, codesz;
int i;
struct szt *sz;
relsz = reloc.size;
relp = (int *)malloc((unsigned)relsz);
rpend = &relp[(unsigned)relsz / sizeof(int)];
codesz = text.size;
codep = (int *)malloc((unsigned)codesz);
if(relp == 0 || codep == 0)
error(1,"out of memory(load2td)");
mget(relp,relsz,&reloc);
mget(codep,codesz,&text);
for(rp=relp,cp=codep;rp<rpend;rp++,cp++){
curadr += 2;
c = *rp;
if(c == 0)
continue;
if(c & R_EXT) {
/* externe referenz */
num = c>>4;
lp = lochash[num % LHSIZ];
while(lp->l_index != num) {
lp = lp->l_link;
if( lp == 0 )
error(1,"local symbol botch");
}
sp = lp->l_symbol;
if(((sp->n_type)&0x3f) == N_EXT+N_UNDF)
error(1,"undefined symbol");
switch(c & R_TYPE) {
case R_SEG:
c= (int)((sp->n_value & 0x7f000000) >> 16);
*cp = (*cp&0x8000) | c;
break;
case R_OFF:
c= (int)(sp->n_value & 0x0ffff);
*cp += c;
break;
case R_SSEG:
c = (int)(sp->n_value & 0xff) + (int)((sp->n_value & 0x7f000000) >>16);
*cp = (*cp&0x0ff) + c;
break;
case R_R12:
printf("extern 12bit rel. adr. %s\n",sp->n_un.n_name);
c = (char)((sp->n_value & 0x7f000000) >>24);
if(c != curseg)
error(1,"external relativ adress(12) to another segment");
c = (int)(sp->n_value&0x0ffff) - curadr;
if(c>=2048 || c<= -2048)
error(1,"relativ adress(12) to large");
*cp += (c&0x0fff);
break;
case R_R16:
printf("extern 16bit rel. adr. %s\n",sp->n_un.n_name);
c = (char)((sp->n_value & 0x7f000000) >>24);
if(c != curseg)
error(1,"external relativ adress(16) to another segment");
c = (int)(sp->n_value&0x0ffff) - curadr;
*cp += c;
break;
}
}
/* aufgeloeste referenz */
else {
if((c & 0x06)==0)
continue;
if((c & 0x01)==0)
error(1,"nonsegmented referenz");
sz =szstr;
for (i=0;i < (c>>8); i++ ,sz++);
switch((c&0x70)>>4) {
case R_SEG:
switch (c& 0x06){
case 0x02 :
c = ((int)sz->tseg)<<8;
break;
case 0x04 :
c = ((int)sz->dseg)<<8;
break;
case 0x06 :
c =((int)sz->bseg)<<8;
break;
}
*cp = (*cp & 0x8000)+c;
break;
case R_OFF:
switch (c& 0x06){
case 0x02 :
c = (int)sz->trel;
break;
case 0x04 :
c = (int)sz->drel;
break;
case 0x06 :
c =(int)sz->brel;
break;
}
*cp += c;
break;
case R_SSEG:
printf("aufgeloeste short seg adress\n");
case R_R12:
printf("aufgeloeste 12bit rel. adress\n");
case R_R16:
printf("aufgeloeste 16bit rel.adress\n");
}
}
}
bwrite(codep,(unsigned)codesz,b1);
free(codep);
free(relp);
}
finishout()
{
register int i;
int nsymt;
unsigned curt,curd;
/*
if (sflag==0) {
nsymt = symx(nextsym);
for (i = 0; i < nsymt; i++)
symwrite(xsym(i), sout);
bwrite(&offset, sizeof offset, sout);
}
*/
/*die letzen segmente werden mit 0 gefuellt */
curt = (unsigned)(torigin & 0xffff);
curd = (unsigned)(dorigin & 0xffff);
while((curt & (pagesize-1)) && ((long)curt<SEGSIZE)){
bputc(0,tout);
curt++;
}
while((curd & (pagesize-1))&&((long)curd<SEGSIZE)){
bputc(0,dout);
curd++;
}
if(sflag == 0) {
lseek(biofd,12L,0); /* Groesse der Symboltabelle */
write(biofd,&fsyms,2); /* korrektur der Symboltabellengroesse */
boffset = 14;
}
if (!ofilfnd) {
unlink("a.out");
if (link("l.out", "a.out") < 0)
error(1, "cannot move l.out to a.out");
ofilename = "a.out";
}
delarg = errlev;
delexit();
}
mkfsym(s)
char *s;
{
int x;
if (sflag)
return;
if (trace)
printf("load2arg: %s\n", s);
cursym.n_un.n_name = s;
cursym.n_type = N_FN;
cursym.n_value = torigin;
x = symwrite(&cursym, sout);
fsyms += x;
}
struct {
struct s_nlist bol;
char longname[128];
}sym;
symwrite(sp,bp)
struct nlist *sp;
struct biobuf *bp;
{
register int len;
register char *str;
char *tp, *s;
int i;
sym.bol.sn_value = sp->n_value;
sym.bol.sn_type = sp->n_type & 0x7f; /* LIBF wird zurueck */
sym.bol.sn_segt = sp->n_segt;
switch(sym.bol.sn_segt & 0x60) {
case 0 :
break;
case 0x20 :
sym.bol.sn_segt += ctnr+1;
break;
case 0x40 :
sym.bol.sn_segt += ctnr+1+(cdnr&0x1f)+1;
break;
}
str=sp->n_un.n_name;
tp = (char *)sym.bol.sn_name;
len=strlen(str);
if(len>8)
*tp++ = ((char)len + 1) | 0x80;
strcpy(tp,str);
tp += len;
i=0;
for(s=(char *)&sym ; s<tp ;) {
s += 14; i += 14;
}
while(tp <= s) *tp++ = 0;
bwrite((char *)&sym, i, bp);
return(i);
}
off_t wroff;
struct biobuf toutb;
setupout()
{
int bss;
struct stat stbuf;
extern char *sys_errlist[];
extern int errno;
int i, x, nsymt;
struct segt *pt;
char p;
ofilemode = 0777 & ~umask(0);
biofd = creat(ofilename, 0666 & ofilemode);
if (biofd < 0) {
filname = ofilename; /* kludge */
archdr.ar_name[0] = 0; /* kludge */
error(1, sys_errlist[errno]); /* kludge */
}
fstat(biofd, &stbuf); /* suppose file exists, wrong*/
if (stbuf.st_mode & 0111) { /* mode, ld fails? */
chmod(ofilename, stbuf.st_mode & 0666);
ofilemode = stbuf.st_mode;
}
filhdr.s_magic = S_MAGIC3;
filhdr.s_imsize = tsize + dsize;
filhdr.s_bss = bsize;
filhdr.s_syms = 0;
filhdr.s_segt = (unsigned)((ctnr&0x1f) + (cdnr&0x1f) + (cbnr&0x1f) +3) <<4;
if (entrypt) {
if ((entrypt->n_type&0x3f)!=N_EXT+N_CODE)
error(0, "entry point not in text");
else
filhdr.s_entry = entrypt->n_value;
} else
filhdr.s_entry = 0;
filhdr.s_flag = SF_7FSTK + SF_STRIP;
filhdr.s_codesz = filhdr.s_lines = 0;
tout = &toutb;
bopen(tout, 0L, p_blksize);
wroff = N_TXTOFF(filhdr) + tsize;
outb(&dout, dsize , p_blksize);
if(sflag==0) {
outb(&sout,filhdr.s_syms,p_blksize);
nsymt = symx(nextsym);
for(i=0;i<nsymt;i++) {
x=symwrite(xsym(i),sout);
filhdr.s_syms += x;
}
fsyms = filhdr.s_syms;
}
bwrite((char *)&filhdr, sizeof (filhdr), tout);
/*Schreiben der segmenttabelle */
bwrite(tptr,(((unsigned)ctnr&0x1f)+1) <<4,tout);
for(pt=dptr,p=0; p<=(cdnr&0x1f); pt++,p++)
pt->sg_segno = ctnr+p+1;
bwrite(dptr,(((unsigned)cdnr&0x1f)+1) <<4,tout);
for(pt=bptr,p=0; p<=(cbnr&0x1f); pt++,p++)
pt->sg_segno = ctnr+(cdnr&0x1f)+p+2;
bwrite(bptr,(((unsigned)cbnr&0x1f)+1) <<4,tout);
}
outb(bp, inc, bufsize)
register struct biobuf **bp;
long inc;
{
*bp = (struct biobuf *)malloc(sizeof (struct biobuf));
if (*bp == 0)
error(1, "ran out of memory (outb)");
bopen(*bp, wroff, bufsize);
wroff += inc;
}
struct nlist **
lookup()
{
register long sh;
register struct nlist **hp;
register char *cp, *cp1;
register struct symseg *gp;
register int i;
sh = 0;
for (cp = cursym.n_un.n_name; *cp;)
sh = (sh<<1) + *cp++;
sh = (sh & 0x7fffffff) % HSIZE;
for (gp = symseg; gp < &symseg[NSEG]; gp++) {
if (gp->sy_first == 0) {
gp->sy_first = (struct nlist *)
calloc(NSYM, sizeof (struct nlist));
gp->sy_hfirst = (struct nlist **)
calloc(HSIZE, sizeof (struct nlist *));
if (gp->sy_first == 0 || gp->sy_hfirst == 0)
error(1, "ran out of space for symbol table");
gp->sy_last = gp->sy_first + NSYM;
gp->sy_hlast = gp->sy_hfirst + HSIZE;
}
if (gp > csymseg)
csymseg = gp;
hp = gp->sy_hfirst + sh;
i = 1;
do {
if (*hp == 0) {
if (gp->sy_used == NSYM)
break;
return (hp);
}
cp1 = (*hp)->n_un.n_name;
for (cp = cursym.n_un.n_name; *cp == *cp1++;)
if (*cp++ == 0)
return (hp);
hp += i;
i += 2;
if (hp >= gp->sy_hlast)
hp -= HSIZE;
} while (i < HSIZE);
if (i > HSIZE)
error(1, "hash table botch");
}
error(1, "symbol table overflow");
/*NOTREACHED*/
}
symfree(saved)
struct nlist *saved;
{
register struct symseg *gp;
register struct nlist *sp;
for (gp = csymseg; gp >= symseg; gp--, csymseg--) {
sp = gp->sy_first + gp->sy_used;
if (sp == saved) {
nextsym = sp;
return;
}
for (sp--; sp >= gp->sy_first; sp--) {
gp->sy_hfirst[sp->n_hash] = 0;
gp->sy_used--;
if (sp == saved) {
nextsym = sp;
return;
}
}
}
if (saved == 0)
return;
error(1, "symfree botch");
}
struct nlist **
slookup(s)
char *s;
{
cursym.n_un.n_name = s;
cursym.n_type = N_EXT+N_UNDF; /* segmented bit ?? */
cursym.n_value = 0;
return (lookup());
}
enter(hp)
register struct nlist **hp;
{
register struct nlist *sp;
if (*hp==0) {
if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast)
error(1, "enter botch");
*hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used;
csymseg->sy_used++;
sp->n_un.n_name = cursym.n_un.n_name;
sp->n_type = cursym.n_type;
sp->n_hash = hp - csymseg->sy_hfirst;
sp->n_value = cursym.n_value;
nextsym = lastsym + 1;
return(1);
} else {
lastsym = *hp;
return(0);
}
}
symx(sp)
struct nlist *sp;
{
register struct symseg *gp;
if (sp == 0)
return (0);
for (gp = csymseg; gp >= symseg; gp--)
/* <= is sloppy so nextsym will always work */
if (sp >= gp->sy_first && sp <= gp->sy_last)
return ((gp - symseg) * NSYM + sp - gp->sy_first);
error(1, "symx botch");
/*NOTREACHED*/
}
symreloc()
{
register struct szt *sp;
register long val;
int i;
sp=szstr;
for(i=0 ; i < (int)cursym.n_segt ; i++ ) sp++;
switch (cursym.n_type & 0x3f) {
case N_CODE:
case N_EXT+N_CODE:
cursym.n_segt = sp->tseg;
val = ((long)sp->tseg)<<24;
val += cursym.n_value&0xffff;
cursym.n_value = val + sp->trel;
break;
case N_DATA:
case N_EXT+N_DATA:
cursym.n_segt = sp->dseg;
val = ((long)sp->dseg)<<24;
val += cursym.n_value&0xffff;
cursym.n_value = val + sp->drel;
break;
case N_BSS:
case N_EXT+N_BSS:
cursym.n_segt = sp->bseg;
val = ((long)sp->bseg)<<24;
val += cursym.n_value&0xffff;
cursym.n_value = val + sp->brel;
break;
case N_EXT+N_UNDF:
break;
default:
if (cursym.n_type&N_EXT)
cursym.n_type = N_EXT+N_ABS;
break;
}
}
getarhdr()
{
register char *cp;
mget((char *)&archdr,(long) sizeof (archdr), &text);
for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];)
if (*cp++ == ' ') {
cp[-1] = 0;
return;
}
}
mget(loc, n, sp)
register STREAM *sp;
long n;
register char *loc;
{
register char *p;
register long take;
top:
if (n == 0)
return;
if (sp->size && sp->nibuf) {
p = sp->ptr;
take = sp->size;
if (take > (long)sp->nibuf)
take = (long)sp->nibuf;
if (take > n)
take = n;
n -= take;
sp->size -= take;
sp->nibuf -= (int)take;
sp->pos += take;
do
*loc++ = *p++;
while (--take > 0);
sp->ptr = p;
goto top;
}
if (n > (long)p_blksize) {
take = n - n % (long)p_blksize;
lseek(infil, (long)(sp->bno+1)<<p_blkshift, 0);
if (take > sp->size || read(infil, loc,(int)take) != (unsigned)take)
error(1, "premature EOF");
loc += take;
n -= take;
sp->size -= take;
sp->pos += take;
dseek(sp, (long)(sp->bno+1+(take>>p_blkshift))<<p_blkshift, -1L);
goto top;
}
*loc++ = get(sp);
--n;
goto top;
}
dseek(sp, loc, s)
register STREAM *sp;
long loc, s;
{
register PAGE *p;
register long b, o;
int n;
b = loc>>p_blkshift;
o = loc&(long)p_blkmask;
if (o&01)
error(1, "loader error; odd offset");
--sp->pno->nuser;
if(((p = &page[0])->bno != b) && (p = &page[1])->bno!=b)
if (p->nuser==0 || (p = &page[0])->nuser==0) {
if (page[0].nuser==0 && page[1].nuser==0)
if (page[0].bno < page[1].bno)
p = &page[0];
p->bno = (int)b;
lseek(infil, loc & ~(long)p_blkmask, 0);
if ((n = read(infil, p->buff, p_blksize)) < 0)
n = 0;
p->nibuf = n;
} else
error(1, "botch: no pages");
++p->nuser;
sp->bno = (int)b;
sp->pno = p;
if (s != -1) {sp->size = s; sp->pos = 0;}
sp->ptr = (char *)(p->buff + o);
if ((sp->nibuf = p->nibuf-(int)o) <= 0)
sp->size = 0;
}
char
get(asp)
STREAM *asp;
{
register STREAM *sp;
sp = asp;
if ((sp->nibuf -= (int)sizeof(char)) < 0) {
dseek(sp, ((long)(sp->bno+1)<<p_blkshift), (long)-1);
sp->nibuf -= sizeof(char);
}
if ((sp->size -= (long)sizeof(char)) <= 0) {
if (sp->size < 0)
error(1, "premature EOF");
++fpage.nuser;
--sp->pno->nuser;
sp->pno = (PAGE *) &fpage;
}
sp->pos += sizeof(char);
return(*sp->ptr++);
}
getfile(acp)
char *acp;
{
register int c;
char arcmag[SARMAG+1];
struct stat stb;
int mag;
archdr.ar_name[0] = '\0';
filname = acp;
if (filname[0] == '-' && filname[1] == 'l')
infil = libopen(filname + 2, O_RDONLY);
else
infil = open(filname, O_RDONLY);
if (infil < 0)
error(1, "cannot open");
fstat(infil, &stb);
page[0].bno = page[1].bno = -1;
page[0].nuser = page[1].nuser = 0;
/*c = stb.st_blksize; bei WEGA nicht vorhanden*/
c = BLKSIZE;
if (c == 0 || (c & (c - 1)) != 0) {
/* use default size if not a power of two */
c = BLKSIZE;
}
if (p_blksize != c) {
p_blksize = c;
p_blkmask = c - 1;
for (p_blkshift = 0; c > 1 ; p_blkshift++)
c >>= 1;
if (page[0].buff != NULL)
free(page[0].buff);
page[0].buff = (char *)malloc(p_blksize);
if (page[0].buff == NULL)
error(1, "ran out of memory (getfile)");
if (page[1].buff != NULL)
free(page[1].buff);
page[1].buff = (char *)malloc(p_blksize);
if (page[1].buff == NULL)
error(1, "ran out of memory (getfile)");
}
text.pno = reloc.pno = (PAGE *) &fpage;
fpage.nuser = 2;
dseek(&text, 0L, SARMAG);
if (text.size <= 0)
error(1, "premature EOF");
mget((char *)arcmag,2L, &text);
mag=ARMAG;
if (strncmp(arcmag,&mag,2))
return (0);
dseek(&text, SARMAG, (long)sizeof archdr);
if (text.size <= 0)
return (1);
getarhdr();
if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0)
return (1);
return (stb.st_mtime > archdr.ar_date ? 3 : 2);
}
/*
* Search for a library with given name
* using the directory search array.
*/
libopen(name, oflags)
char *name;
int oflags;
{
register char *p, *cp;
register int i;
static char buf[MAXPATHLEN+1];
int fd = -1;
if (*name == '\0') /* backwards compat */
name = "a";
for (i = 0; i < ndir && fd == -1; i++) {
p = buf;
for (cp = dirs[i]; *cp; *p++ = *cp++)
;
*p++ = '/';
for (cp = "Llib"; *cp; *p++ = *cp++)
;
for (cp = name; *cp; *p++ = *cp++)
;
cp = ".a";
while (*p++ = *cp++)
;
fd = open(buf, oflags);
}
if (fd != -1)
filname = buf;
return (fd);
}
error(n, s)
char *s;
{
if (errlev==0)
printf("lld:");
if (filname) {
printf("%s", filname);
if (n != -1 && archdr.ar_name[0])
printf("(%s)", archdr.ar_name);
printf(": ");
}
printf("%s\n", s);
if (n == -1)
return;
if (n)
delexit();
errlev = 2;
}
readhdr(loc)
off_t loc;
{
dseek(&text, loc, (long)sizeof(filhdr));
mget((short *)&filhdr,(long) sizeof(filhdr), &text);
if (N_BADMAG(filhdr)) {
if (filhdr.s_magic == OARMAG)
error(1, "old archive");
error(1, "bad magic number");
}
if (filhdr.s_imsize & 01)
error(1, "text/data size odd");
}
long round(v, r)
long v;
long r;
{
r--;
v += r;
v &= ~r;
return(v);
}
#define NSAVETAB 8192
char *savetab;
int saveleft;
char *savestr(cp)
register char *cp;
{
register int len;
len = strlen(cp) + 1;
if (len > saveleft) {
saveleft = NSAVETAB;
if (len > saveleft)
saveleft = len;
savetab = malloc(saveleft);
if (savetab == 0)
error(1, "ran out of memory (savestr)");
}
strncpy(savetab, cp, len);
cp = savetab;
savetab += len;
saveleft -= len;
return (cp);
}
bopen(bp, off, bufsize)
register struct biobuf *bp;
off_t off;
{
bp->b_ptr = bp->b_buf = (char *)malloc(bufsize);
if (bp->b_ptr == (char *)0)
error(1, "ran out of memory (bopen)");
bp->b_bufsize = bufsize;
bp->b_nleft = bufsize - (off % bufsize);
bp->b_off = off;
bp->b_link = biobufs;
biobufs = bp;
}
int bwrerror;
bwrite(p, cnt, bp)
register char *p;
register unsigned cnt;
register struct biobuf *bp;
{
register unsigned put;
register char *to;
top:
if (cnt == 0)
return;
if (bp->b_nleft) {
put = bp->b_nleft;
if (put > cnt)
put = cnt;
bp->b_nleft -= put;
to = bp->b_ptr;
bcopy(p, to, put);
bp->b_ptr += put;
p += put;
cnt -= put;
goto top;
}
if (cnt >= bp->b_bufsize) {
if (bp->b_ptr != bp->b_buf)
bflush1(bp);
put = cnt - cnt % bp->b_bufsize;
if (boffset != bp->b_off)
lseek(biofd, bp->b_off, 0);
if (write(biofd, p, put) != put) {
bwrerror = 1;
error(1, "output write error");
}
bp->b_off += put;
boffset = bp->b_off;
p += put;
cnt -= put;
goto top;
}
bflush1(bp);
goto top;
}
bcopy(p1,p2,i)
register char *p1,*p2;
register int i;
{
while(i>0){
*p2++ = *p1++;
i--;
}
}
bflush()
{
register struct biobuf *bp;
if (bwrerror)
return;
for (bp = biobufs; bp; bp = bp->b_link)
bflush1(bp);
}
bflush1(bp)
register struct biobuf *bp;
{
register long cnt = bp->b_ptr - bp->b_buf;
if (cnt == 0)
return;
if (boffset != bp->b_off)
lseek(biofd, bp->b_off, 0);
if (write(biofd, bp->b_buf, (unsigned)cnt) != (unsigned)cnt) {
bwrerror = 1;
error(1, "output write error");
}
bp->b_off += cnt;
boffset = bp->b_off;
bp->b_ptr = bp->b_buf;
bp->b_nleft = bp->b_bufsize;
}
bflushc(bp, c)
register char c;
register struct biobuf *bp;
{
bflush1(bp);
bputc(c, bp);
}
bseek(bp, off)
register struct biobuf *bp;
register off_t off;
{
bflush1(bp);
bp->b_nleft = bp->b_bufsize - (off % bp->b_bufsize);
bp->b_off = off;
}
struct tynames {
int ty_value;
char *ty_name;
} tynames[] = {
N_UNDF, "undefined",
N_ABS, "absolute",
N_CODE, "text",
N_DATA, "data",
N_BSS, "bss",
0, 0,
};
tracesym()
{
register struct tynames *tp;
printf("%s", filname);
if (archdr.ar_name[0])
printf("(%s)", archdr.ar_name);
printf(": ");
if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) {
printf("definition of common %s size %d\n",
cursym.n_un.n_name, cursym.n_value);
return;
}
for (tp = tynames; tp->ty_name; tp++)
if (tp->ty_value == (cursym.n_type&N_TYPE))
break;
printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to");
if (cursym.n_type&N_EXT)
printf(" external");
if (tp->ty_name)
printf(" %s", tp->ty_name);
printf(" %s\n", cursym.n_un.n_name);
}