diff --git a/WEGA/contrib/lcc/cmd/lld.c b/WEGA/contrib/lcc/cmd/lld.c new file mode 100644 index 0000000..dbf2240 --- /dev/null +++ b/WEGA/contrib/lcc/cmd/lld.c @@ -0,0 +1,2248 @@ +/* + * lld - string table version for P8000 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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) + 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 ; xsg_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 ; xsg_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; cn_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); in_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 ; xsg_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; xsg_code){ + if((long)curt+(long)cp->sg_code >= SEGSIZE) { + while((curt&(pagesize-1))&&((long)curtsg_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)curdsg_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>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)curtn_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 ; sn_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;isg_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)< 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; + 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)<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); +} +