112671Ssam #ifndef lint 2*17133Ssam static char sccsid[] = "@(#)ld.c 4.11 08/30/84"; 312671Ssam #endif 46414Smckusic 5615Sbill /* 6898Sbill * ld - string table version for VAX 7615Sbill */ 8615Sbill 9*17133Ssam #include <sys/param.h> 10615Sbill #include <signal.h> 11615Sbill #include <stdio.h> 12615Sbill #include <ctype.h> 13650Sbill #include <ar.h> 14650Sbill #include <a.out.h> 15615Sbill #include <ranlib.h> 1613591Swnj #include <sys/stat.h> 17*17133Ssam #include <sys/file.h> 18615Sbill 19615Sbill /* 20615Sbill * Basic strategy: 21615Sbill * 22615Sbill * The loader takes a number of files and libraries as arguments. 23615Sbill * A first pass examines each file in turn. Normal files are 24615Sbill * unconditionally loaded, and the (external) symbols they define and require 25615Sbill * are noted in the symbol table. Libraries are searched, and the 26615Sbill * library members which define needed symbols are remembered 27615Sbill * in a special data structure so they can be selected on the second 28615Sbill * pass. Symbols defined and required by library members are also 29615Sbill * recorded. 30615Sbill * 31615Sbill * After the first pass, the loader knows the size of the basic text 32615Sbill * data, and bss segments from the sum of the sizes of the modules which 33615Sbill * were required. It has computed, for each ``common'' symbol, the 34615Sbill * maximum size of any reference to it, and these symbols are then assigned 35615Sbill * storage locations after their sizes are appropriately rounded. 36615Sbill * The loader now knows all sizes for the eventual output file, and 37615Sbill * can determine the final locations of external symbols before it 38615Sbill * begins a second pass. 39615Sbill * 40615Sbill * On the second pass each normal file and required library member 41615Sbill * is processed again. The symbol table for each such file is 42615Sbill * reread and relevant parts of it are placed in the output. The offsets 43615Sbill * in the local symbol table for externally defined symbols are recorded 44615Sbill * since relocation information refers to symbols in this way. 45615Sbill * Armed with all necessary information, the text and data segments 46615Sbill * are relocated and the result is placed in the output file, which 47615Sbill * is pasted together, ``in place'', by writing to it in several 48615Sbill * different places concurrently. 49615Sbill */ 50615Sbill 51615Sbill /* 52615Sbill * Internal data structures 53615Sbill * 54615Sbill * All internal data structures are segmented and dynamically extended. 55615Sbill * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT) 56615Sbill * referenced library members, and 100 (NSYMPR) private (local) symbols 57615Sbill * per object module. For large programs and/or modules, these structures 58615Sbill * expand to be up to 40 (NSEG) times as large as this as necessary. 59615Sbill */ 60615Sbill #define NSEG 40 /* Number of segments, each data structure */ 61615Sbill #define NSYM 1103 /* Number of symbols per segment */ 62615Sbill #define NROUT 250 /* Number of library references per segment */ 63615Sbill #define NSYMPR 100 /* Number of private symbols per segment */ 64615Sbill 65615Sbill /* 66615Sbill * Structure describing each symbol table segment. 67615Sbill * Each segment has its own hash table. We record the first 68615Sbill * address in and first address beyond both the symbol and hash 69615Sbill * tables, for use in the routine symx and the lookup routine respectively. 70615Sbill * The symfree routine also understands this structure well as it used 71615Sbill * to back out symbols from modules we decide that we don't need in pass 1. 72615Sbill * 73615Sbill * Csymseg points to the current symbol table segment; 74615Sbill * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated, 75615Sbill * (unless csymseg->sy_used == NSYM in which case we will allocate another 76615Sbill * symbol table segment first.) 77615Sbill */ 78615Sbill struct symseg { 79615Sbill struct nlist *sy_first; /* base of this alloc'ed segment */ 80615Sbill struct nlist *sy_last; /* end of this segment, for n_strx */ 81615Sbill int sy_used; /* symbols used in this seg */ 82615Sbill struct nlist **sy_hfirst; /* base of hash table, this seg */ 83615Sbill struct nlist **sy_hlast; /* end of hash table, this seg */ 84615Sbill } symseg[NSEG], *csymseg; 85615Sbill 86615Sbill /* 87615Sbill * The lookup routine uses quadratic rehash. Since a quadratic rehash 88615Sbill * only probes 1/2 of the buckets in the table, and since the hash 89615Sbill * table is segmented the same way the symbol table is, we make the 90615Sbill * hash table have twice as many buckets as there are symbol table slots 91615Sbill * in the segment. This guarantees that the quadratic rehash will never 92615Sbill * fail to find an empty bucket if the segment is not full and the 93615Sbill * symbol is not there. 94615Sbill */ 95615Sbill #define HSIZE (NSYM*2) 96615Sbill 97615Sbill /* 98615Sbill * Xsym converts symbol table indices (ala x) into symbol table pointers. 99615Sbill * Symx (harder, but never used in loops) inverts pointers into the symbol 100615Sbill * table into indices using the symseg[] structure. 101615Sbill */ 102615Sbill #define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM)) 103615Sbill /* symx() is a function, defined below */ 104615Sbill 105615Sbill struct nlist cursym; /* current symbol */ 106615Sbill struct nlist *lastsym; /* last symbol entered */ 107615Sbill struct nlist *nextsym; /* next available symbol table entry */ 108615Sbill struct nlist *addsym; /* first sym defined during incr load */ 109615Sbill int nsym; /* pass2: number of local symbols in a.out */ 110615Sbill /* nsym + symx(nextsym) is the symbol table size during pass2 */ 111615Sbill 112615Sbill struct nlist **lookup(), **slookup(); 113650Sbill struct nlist *p_etext, *p_edata, *p_end, *entrypt; 114615Sbill 115615Sbill /* 116615Sbill * Definitions of segmentation for library member table. 117615Sbill * For each library we encounter on pass 1 we record pointers to all 118615Sbill * members which we will load on pass 2. These are recorded as offsets 119615Sbill * into the archive in the library member table. Libraries are 120615Sbill * separated in the table by the special offset value -1. 121615Sbill */ 122615Sbill off_t li_init[NROUT]; 123615Sbill struct libseg { 124615Sbill off_t *li_first; 125615Sbill int li_used; 126615Sbill int li_used2; 127615Sbill } libseg[NSEG] = { 128615Sbill li_init, 0, 0, 129615Sbill }, *clibseg = libseg; 130615Sbill 131615Sbill /* 132615Sbill * In processing each module on pass 2 we must relocate references 133615Sbill * relative to external symbols. These references are recorded 134615Sbill * in the relocation information as relative to local symbol numbers 135615Sbill * assigned to the external symbols when the module was created. 136615Sbill * Thus before relocating the module in pass 2 we create a table 137615Sbill * which maps these internal numbers to symbol table entries. 138615Sbill * A hash table is constructed, based on the local symbol table indices, 139615Sbill * for quick lookup of these symbols. 140615Sbill */ 141615Sbill #define LHSIZ 31 142615Sbill struct local { 143615Sbill int l_index; /* index to symbol in file */ 144615Sbill struct nlist *l_symbol; /* ptr to symbol table */ 145615Sbill struct local *l_link; /* hash link */ 146615Sbill } *lochash[LHSIZ], lhinit[NSYMPR]; 147615Sbill struct locseg { 148615Sbill struct local *lo_first; 149615Sbill int lo_used; 150615Sbill } locseg[NSEG] = { 151615Sbill lhinit, 0 152615Sbill }, *clocseg; 153615Sbill 154615Sbill /* 155615Sbill * Libraries are typically built with a table of contents, 156615Sbill * which is the first member of a library with special file 157615Sbill * name __.SYMDEF and contains a list of symbol names 158615Sbill * and with each symbol the offset of the library member which defines 159615Sbill * it. The loader uses this table to quickly tell which library members 160615Sbill * are (potentially) useful. The alternative, examining the symbol 161615Sbill * table of each library member, is painfully slow for large archives. 162615Sbill * 163615Sbill * See <ranlib.h> for the definition of the ranlib structure and an 164615Sbill * explanation of the __.SYMDEF file format. 165615Sbill */ 166615Sbill int tnum; /* number of symbols in table of contents */ 167615Sbill int ssiz; /* size of string table for table of contents */ 168615Sbill struct ranlib *tab; /* the table of contents (dynamically allocated) */ 169615Sbill char *tabstr; /* string table for table of contents */ 170615Sbill 171615Sbill /* 172615Sbill * We open each input file or library only once, but in pass2 we 173615Sbill * (historically) read from such a file at 2 different places at the 174615Sbill * same time. These structures are remnants from those days, 175650Sbill * and now serve only to catch ``Premature EOF''. 1766414Smckusic * In order to make I/O more efficient, we provide routines which 17716068Sralph * use the optimal block size returned by stat(). 178615Sbill */ 1796414Smckusic #define BLKSIZE 1024 180615Sbill typedef struct { 181615Sbill short *fakeptr; 182615Sbill int bno; 183615Sbill int nibuf; 184615Sbill int nuser; 18516068Sralph char *buff; 18616068Sralph int bufsize; 187615Sbill } PAGE; 188615Sbill 189615Sbill PAGE page[2]; 19016068Sralph int p_blksize; 19116068Sralph int p_blkshift; 19216068Sralph int p_blkmask; 193615Sbill 194615Sbill struct { 195615Sbill short *fakeptr; 196615Sbill int bno; 197615Sbill int nibuf; 198615Sbill int nuser; 199615Sbill } fpage; 200615Sbill 201615Sbill typedef struct { 202615Sbill char *ptr; 203615Sbill int bno; 204615Sbill int nibuf; 205615Sbill long size; 206615Sbill long pos; 207615Sbill PAGE *pno; 208615Sbill } STREAM; 209615Sbill 210615Sbill STREAM text; 211615Sbill STREAM reloc; 212615Sbill 213615Sbill /* 214615Sbill * Header from the a.out and the archive it is from (if any). 215615Sbill */ 216615Sbill struct exec filhdr; 217615Sbill struct ar_hdr archdr; 218615Sbill #define OARMAG 0177545 219615Sbill 220615Sbill /* 221615Sbill * Options. 222615Sbill */ 223615Sbill int trace; 224615Sbill int xflag; /* discard local symbols */ 225615Sbill int Xflag; /* discard locals starting with 'L' */ 226615Sbill int Sflag; /* discard all except locals and globals*/ 227615Sbill int rflag; /* preserve relocation bits, don't define common */ 228615Sbill int arflag; /* original copy of rflag */ 229615Sbill int sflag; /* discard all symbols */ 230898Sbill int Mflag; /* print rudimentary load map */ 231615Sbill int nflag; /* pure procedure */ 232615Sbill int dflag; /* define common even with rflag */ 233650Sbill int zflag; /* demand paged */ 234615Sbill long hsize; /* size of hole at beginning of data to be squashed */ 235615Sbill int Aflag; /* doing incremental load */ 236650Sbill int Nflag; /* want impure a.out */ 237615Sbill int funding; /* reading fundamental file for incremental load */ 238898Sbill int yflag; /* number of symbols to be traced */ 239898Sbill char **ytab; /* the symbols */ 240615Sbill 241615Sbill /* 242615Sbill * These are the cumulative sizes, set in pass 1, which 243615Sbill * appear in the a.out header when the loader is finished. 244615Sbill */ 245615Sbill off_t tsize, dsize, bsize, trsize, drsize, ssize; 246615Sbill 247615Sbill /* 248615Sbill * Symbol relocation: c?rel is a scale factor which is 249615Sbill * added to an old relocation to convert it to new units; 250615Sbill * i.e. it is the difference between segment origins. 251650Sbill * (Thus if we are loading from a data segment which began at location 252650Sbill * 4 in a .o file into an a.out where it will be loaded starting at 253650Sbill * 1024, cdrel will be 1020.) 254615Sbill */ 255615Sbill long ctrel, cdrel, cbrel; 256615Sbill 257615Sbill /* 258650Sbill * Textbase is the start address of all text, 0 unless given by -T. 259615Sbill * Database is the base of all data, computed before and used during pass2. 260650Sbill */ 261650Sbill long textbase, database; 262650Sbill 263650Sbill /* 264615Sbill * The base addresses for the loaded text, data and bss from the 265615Sbill * current module during pass2 are given by torigin, dorigin and borigin. 266615Sbill */ 267615Sbill long torigin, dorigin, borigin; 268615Sbill 269615Sbill /* 270615Sbill * Errlev is nonzero when errors have occured. 271615Sbill * Delarg is an implicit argument to the routine delexit 272615Sbill * which is called on error. We do ``delarg = errlev'' before normal 273615Sbill * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the 274615Sbill * result file executable. 275615Sbill */ 276615Sbill int errlev; 277615Sbill int delarg = 4; 278615Sbill 279615Sbill /* 280615Sbill * The biobuf structure and associated routines are used to write 281615Sbill * into one file at several places concurrently. Calling bopen 282615Sbill * with a biobuf structure sets it up to write ``biofd'' starting 283615Sbill * at the specified offset. You can then use ``bwrite'' and/or ``bputc'' 284615Sbill * to stuff characters in the stream, much like ``fwrite'' and ``fputc''. 285615Sbill * Calling bflush drains all the buffers and MUST be done before exit. 286615Sbill */ 287615Sbill struct biobuf { 288615Sbill short b_nleft; /* Number free spaces left in b_buf */ 28916068Sralph /* Initialize to be less than b_bufsize initially, to boundary align in file */ 290615Sbill char *b_ptr; /* Next place to stuff characters */ 29116068Sralph char *b_buf; /* Pointer to the buffer */ 29216068Sralph int b_bufsize; /* Size of the buffer */ 293615Sbill off_t b_off; /* Current file offset */ 294615Sbill struct biobuf *b_link; /* Link in chain for bflush() */ 295615Sbill } *biobufs; 296615Sbill #define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \ 297615Sbill : bflushc(b, c)) 298615Sbill int biofd; 299615Sbill off_t boffset; 300615Sbill struct biobuf *tout, *dout, *trout, *drout, *sout, *strout; 301615Sbill 302615Sbill /* 303615Sbill * Offset is the current offset in the string file. 304615Sbill * Its initial value reflects the fact that we will 305615Sbill * eventually stuff the size of the string table at the 306615Sbill * beginning of the string table (i.e. offset itself!). 307615Sbill */ 308615Sbill off_t offset = sizeof (off_t); 309615Sbill 310615Sbill int ofilfnd; /* -o given; otherwise move l.out to a.out */ 311615Sbill char *ofilename = "l.out"; 3123606Ssklower int ofilemode; /* respect umask even for unsucessful ld's */ 313615Sbill int infil; /* current input file descriptor */ 314615Sbill char *filname; /* and its name */ 315615Sbill 316*17133Ssam #define NDIRS 25 317*17133Ssam char *dirs[NDIRS]; /* directories for library search */ 318*17133Ssam int ndir; /* number of directories */ 319*17133Ssam 320615Sbill /* 321615Sbill * Base of the string table of the current module (pass1 and pass2). 322615Sbill */ 323615Sbill char *curstr; 324615Sbill 32512671Ssam /* 32612671Ssam * System software page size, as returned by getpagesize. 32712671Ssam */ 32812671Ssam int pagesize; 32912671Ssam 330615Sbill char get(); 331615Sbill int delexit(); 332615Sbill char *savestr(); 333*17133Ssam char *malloc(); 334615Sbill 335615Sbill main(argc, argv) 336615Sbill char **argv; 337615Sbill { 338615Sbill register int c, i; 339615Sbill int num; 340615Sbill register char *ap, **p; 341615Sbill char save; 342615Sbill 343650Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 344615Sbill signal(SIGINT, delexit); 345650Sbill signal(SIGTERM, delexit); 346650Sbill } 347615Sbill if (argc == 1) 348615Sbill exit(4); 34912671Ssam pagesize = getpagesize(); 350615Sbill 351*17133Ssam /* 352*17133Ssam * Pull out search directories. 353*17133Ssam */ 354*17133Ssam for (c = 1; c < argc; c++) { 355*17133Ssam ap = argv[c]; 356*17133Ssam if (ap[0] == '-' && ap[1] == 'L') { 357*17133Ssam if (ap[2] == 0) 358*17133Ssam error(1, "-L: pathname missing"); 359*17133Ssam if (ndir >= NDIRS) 360*17133Ssam error(1, "-L: too many directories"); 361*17133Ssam dirs[ndir++] = &ap[2]; 362*17133Ssam } 363*17133Ssam } 364*17133Ssam /* add default search directories */ 365*17133Ssam dirs[ndir++] = "/lib"; 366*17133Ssam dirs[ndir++] = "/usr/lib"; 367*17133Ssam dirs[ndir++] = "/usr/local/lib"; 368*17133Ssam 369*17133Ssam p = argv+1; 370650Sbill /* 371650Sbill * Scan files once to find where symbols are defined. 372650Sbill */ 373615Sbill for (c=1; c<argc; c++) { 374615Sbill if (trace) 375615Sbill printf("%s:\n", *p); 376615Sbill filname = 0; 377615Sbill ap = *p++; 378615Sbill if (*ap != '-') { 379615Sbill load1arg(ap); 380615Sbill continue; 381615Sbill } 382615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 383615Sbill 384615Sbill case 'o': 385615Sbill if (++c >= argc) 386615Sbill error(1, "-o where?"); 387615Sbill ofilename = *p++; 388615Sbill ofilfnd++; 389615Sbill continue; 390615Sbill case 'u': 391615Sbill case 'e': 392615Sbill if (++c >= argc) 393615Sbill error(1, "-u or -c: arg missing"); 394615Sbill enter(slookup(*p++)); 395615Sbill if (ap[i]=='e') 396615Sbill entrypt = lastsym; 397615Sbill continue; 398615Sbill case 'H': 399615Sbill if (++c >= argc) 400615Sbill error(1, "-H: arg missing"); 401615Sbill if (tsize!=0) 402615Sbill error(1, "-H: too late, some text already loaded"); 403615Sbill hsize = atoi(*p++); 404615Sbill continue; 405615Sbill case 'A': 406615Sbill if (++c >= argc) 407615Sbill error(1, "-A: arg missing"); 408615Sbill if (Aflag) 409615Sbill error(1, "-A: only one base file allowed"); 410615Sbill Aflag = 1; 411615Sbill nflag = 0; 412615Sbill funding = 1; 413615Sbill load1arg(*p++); 414615Sbill trsize = drsize = tsize = dsize = bsize = 0; 415615Sbill ctrel = cdrel = cbrel = 0; 416615Sbill funding = 0; 417615Sbill addsym = nextsym; 418615Sbill continue; 419615Sbill case 'D': 420615Sbill if (++c >= argc) 421615Sbill error(1, "-D: arg missing"); 422615Sbill num = htoi(*p++); 423615Sbill if (dsize > num) 424615Sbill error(1, "-D: too small"); 425615Sbill dsize = num; 426615Sbill continue; 427615Sbill case 'T': 428615Sbill if (++c >= argc) 429615Sbill error(1, "-T: arg missing"); 430615Sbill if (tsize!=0) 431615Sbill error(1, "-T: too late, some text already loaded"); 432615Sbill textbase = htoi(*p++); 433615Sbill continue; 434615Sbill case 'l': 435615Sbill save = ap[--i]; 436615Sbill ap[i]='-'; 437615Sbill load1arg(&ap[i]); 438615Sbill ap[i]=save; 439615Sbill goto next; 440898Sbill case 'M': 441898Sbill Mflag++; 442898Sbill continue; 443615Sbill case 'x': 444615Sbill xflag++; 445615Sbill continue; 446615Sbill case 'X': 447615Sbill Xflag++; 448615Sbill continue; 449615Sbill case 'S': 450615Sbill Sflag++; 451615Sbill continue; 452615Sbill case 'r': 453615Sbill rflag++; 454615Sbill arflag++; 455615Sbill continue; 456615Sbill case 's': 457615Sbill sflag++; 458615Sbill xflag++; 459615Sbill continue; 460615Sbill case 'n': 461615Sbill nflag++; 462650Sbill Nflag = zflag = 0; 463615Sbill continue; 464615Sbill case 'N': 465650Sbill Nflag++; 466650Sbill nflag = zflag = 0; 467615Sbill continue; 468615Sbill case 'd': 469615Sbill dflag++; 470615Sbill continue; 471615Sbill case 'i': 472615Sbill printf("ld: -i ignored\n"); 473615Sbill continue; 474615Sbill case 't': 475615Sbill trace++; 476615Sbill continue; 477898Sbill case 'y': 478898Sbill if (ap[i+1] == 0) 479898Sbill error(1, "-y: symbol name missing"); 480898Sbill if (yflag == 0) { 481898Sbill ytab = (char **)calloc(argc, sizeof (char **)); 482898Sbill if (ytab == 0) 483898Sbill error(1, "ran out of memory (-y)"); 484898Sbill } 485898Sbill ytab[yflag++] = &ap[i+1]; 486898Sbill goto next; 487615Sbill case 'z': 488615Sbill zflag++; 489650Sbill Nflag = nflag = 0; 490615Sbill continue; 491*17133Ssam case 'L': 492*17133Ssam goto next; 493615Sbill default: 494615Sbill filname = savestr("-x"); /* kludge */ 495615Sbill filname[1] = ap[i]; /* kludge */ 496615Sbill archdr.ar_name[0] = 0; /* kludge */ 497615Sbill error(1, "bad flag"); 498615Sbill } 499615Sbill next: 500615Sbill ; 501615Sbill } 502650Sbill if (rflag == 0 && Nflag == 0 && nflag == 0) 503650Sbill zflag++; 504615Sbill endload(argc, argv); 505615Sbill exit(0); 506615Sbill } 507615Sbill 508615Sbill /* 509615Sbill * Convert a ascii string which is a hex number. 510615Sbill * Used by -T and -D options. 511615Sbill */ 512615Sbill htoi(p) 513615Sbill register char *p; 514615Sbill { 515615Sbill register int c, n; 516615Sbill 517615Sbill n = 0; 518615Sbill while (c = *p++) { 519615Sbill n <<= 4; 520615Sbill if (isdigit(c)) 521615Sbill n += c - '0'; 522615Sbill else if (c >= 'a' && c <= 'f') 523615Sbill n += 10 + (c - 'a'); 524615Sbill else if (c >= 'A' && c <= 'F') 525615Sbill n += 10 + (c - 'A'); 526615Sbill else 527615Sbill error(1, "badly formed hex number"); 528615Sbill } 529615Sbill return (n); 530615Sbill } 531615Sbill 532615Sbill delexit() 533615Sbill { 5349332Smckusick struct stat stbuf; 5359332Smckusick long size; 5369332Smckusick char c = 0; 537615Sbill 538615Sbill bflush(); 539615Sbill unlink("l.out"); 540615Sbill if (delarg==0 && Aflag==0) 5413606Ssklower chmod(ofilename, ofilemode); 5429332Smckusick /* 5439332Smckusick * We have to insure that the last block of the data segment 54416068Sralph * is allocated a full pagesize block. If the underlying 54516068Sralph * file system allocates frags that are smaller than pagesize, 54616068Sralph * a full zero filled pagesize block needs to be allocated so 5479332Smckusick * that when it is demand paged, the paged in block will be 5489332Smckusick * appropriately filled with zeros. 5499332Smckusick */ 5509332Smckusick fstat(biofd, &stbuf); 55116068Sralph size = round(stbuf.st_size, pagesize); 55210640Smckusick if (!rflag && size > stbuf.st_size) { 5539332Smckusick lseek(biofd, size - 1, 0); 5549332Smckusick write(biofd, &c, 1); 5559332Smckusick } 556615Sbill exit (delarg); 557615Sbill } 558615Sbill 559615Sbill endload(argc, argv) 560615Sbill int argc; 561615Sbill char **argv; 562615Sbill { 563615Sbill register int c, i; 564615Sbill long dnum; 565615Sbill register char *ap, **p; 566615Sbill 567615Sbill clibseg = libseg; 568615Sbill filname = 0; 569615Sbill middle(); 570615Sbill setupout(); 571615Sbill p = argv+1; 572615Sbill for (c=1; c<argc; c++) { 573615Sbill ap = *p++; 574615Sbill if (trace) 575615Sbill printf("%s:\n", ap); 576615Sbill if (*ap != '-') { 577615Sbill load2arg(ap); 578615Sbill continue; 579615Sbill } 580615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 581615Sbill 582615Sbill case 'D': 583615Sbill dnum = htoi(*p); 584615Sbill if (dorigin < dnum) 585615Sbill while (dorigin < dnum) 586615Sbill bputc(0, dout), dorigin++; 587615Sbill /* fall into ... */ 588615Sbill case 'T': 589615Sbill case 'u': 590615Sbill case 'e': 591615Sbill case 'o': 592615Sbill case 'H': 593615Sbill ++c; 594615Sbill ++p; 595615Sbill /* fall into ... */ 596615Sbill default: 597615Sbill continue; 598615Sbill case 'A': 599615Sbill funding = 1; 600615Sbill load2arg(*p++); 601615Sbill funding = 0; 602615Sbill c++; 603615Sbill continue; 604898Sbill case 'y': 605*17133Ssam case 'L': 606898Sbill goto next; 607615Sbill case 'l': 608615Sbill ap[--i]='-'; 609615Sbill load2arg(&ap[i]); 610615Sbill goto next; 611615Sbill } 612615Sbill next: 613615Sbill ; 614615Sbill } 615615Sbill finishout(); 616615Sbill } 617615Sbill 618615Sbill /* 619615Sbill * Scan file to find defined symbols. 620615Sbill */ 621615Sbill load1arg(cp) 622615Sbill register char *cp; 623615Sbill { 624615Sbill register struct ranlib *tp; 625615Sbill off_t nloc; 626898Sbill int kind; 627615Sbill 628898Sbill kind = getfile(cp); 629898Sbill if (Mflag) 630898Sbill printf("%s\n", filname); 631898Sbill switch (kind) { 632615Sbill 633615Sbill /* 634615Sbill * Plain file. 635615Sbill */ 636615Sbill case 0: 637615Sbill load1(0, 0L); 638615Sbill break; 639615Sbill 640615Sbill /* 641615Sbill * Archive without table of contents. 642615Sbill * (Slowly) process each member. 643615Sbill */ 644615Sbill case 1: 645898Sbill error(-1, 646898Sbill "warning: archive has no table of contents; add one using ranlib(1)"); 647615Sbill nloc = SARMAG; 648615Sbill while (step(nloc)) 649615Sbill nloc += sizeof(archdr) + 650615Sbill round(atol(archdr.ar_size), sizeof (short)); 651615Sbill break; 652615Sbill 653615Sbill /* 654615Sbill * Archive with table of contents. 655615Sbill * Read the table of contents and its associated string table. 656615Sbill * Pass through the library resolving symbols until nothing changes 657615Sbill * for an entire pass (i.e. you can get away with backward references 658615Sbill * when there is a table of contents!) 659615Sbill */ 660615Sbill case 2: 661615Sbill nloc = SARMAG + sizeof (archdr); 662615Sbill dseek(&text, nloc, sizeof (tnum)); 663615Sbill mget((char *)&tnum, sizeof (tnum), &text); 664615Sbill nloc += sizeof (tnum); 665615Sbill tab = (struct ranlib *)malloc(tnum); 666615Sbill if (tab == 0) 667615Sbill error(1, "ran out of memory (toc)"); 668615Sbill dseek(&text, nloc, tnum); 669615Sbill mget((char *)tab, tnum, &text); 670615Sbill nloc += tnum; 671615Sbill tnum /= sizeof (struct ranlib); 672615Sbill dseek(&text, nloc, sizeof (ssiz)); 673615Sbill mget((char *)&ssiz, sizeof (ssiz), &text); 674615Sbill nloc += sizeof (ssiz); 675615Sbill tabstr = (char *)malloc(ssiz); 676615Sbill if (tabstr == 0) 677615Sbill error(1, "ran out of memory (tocstr)"); 678615Sbill dseek(&text, nloc, ssiz); 679615Sbill mget((char *)tabstr, ssiz, &text); 680615Sbill for (tp = &tab[tnum]; --tp >= tab;) { 681615Sbill if (tp->ran_un.ran_strx < 0 || 682615Sbill tp->ran_un.ran_strx >= ssiz) 683615Sbill error(1, "mangled archive table of contents"); 684615Sbill tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx; 685615Sbill } 686615Sbill while (ldrand()) 687615Sbill continue; 688615Sbill cfree((char *)tab); 689615Sbill cfree(tabstr); 690615Sbill nextlibp(-1); 691615Sbill break; 692615Sbill 693615Sbill /* 694615Sbill * Table of contents is out of date, so search 695615Sbill * as a normal library (but skip the __.SYMDEF file). 696615Sbill */ 697615Sbill case 3: 698898Sbill error(-1, 699898Sbill "warning: table of contents for archive is out of date; rerun ranlib(1)"); 700615Sbill nloc = SARMAG; 701615Sbill do 702615Sbill nloc += sizeof(archdr) + 703615Sbill round(atol(archdr.ar_size), sizeof(short)); 704615Sbill while (step(nloc)); 705615Sbill break; 706615Sbill } 707615Sbill close(infil); 708615Sbill } 709615Sbill 710615Sbill /* 711615Sbill * Advance to the next archive member, which 712615Sbill * is at offset nloc in the archive. If the member 713615Sbill * is useful, record its location in the liblist structure 714615Sbill * for use in pass2. Mark the end of the archive in libilst with a -1. 715615Sbill */ 716615Sbill step(nloc) 717615Sbill off_t nloc; 718615Sbill { 719615Sbill 720615Sbill dseek(&text, nloc, (long) sizeof archdr); 721615Sbill if (text.size <= 0) { 722615Sbill nextlibp(-1); 723615Sbill return (0); 724615Sbill } 725615Sbill getarhdr(); 726615Sbill if (load1(1, nloc + (sizeof archdr))) 727615Sbill nextlibp(nloc); 728615Sbill return (1); 729615Sbill } 730615Sbill 731615Sbill /* 732615Sbill * Record the location of a useful archive member. 733615Sbill * Recording -1 marks the end of files from an archive. 734615Sbill * The liblist data structure is dynamically extended here. 735615Sbill */ 736615Sbill nextlibp(val) 737615Sbill off_t val; 738615Sbill { 739615Sbill 740615Sbill if (clibseg->li_used == NROUT) { 741615Sbill if (++clibseg == &libseg[NSEG]) 742615Sbill error(1, "too many files loaded from libraries"); 743615Sbill clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t)); 744615Sbill if (clibseg->li_first == 0) 745615Sbill error(1, "ran out of memory (nextlibp)"); 746615Sbill } 747615Sbill clibseg->li_first[clibseg->li_used++] = val; 748898Sbill if (val != -1 && Mflag) 749898Sbill printf("\t%s\n", archdr.ar_name); 750615Sbill } 751615Sbill 752615Sbill /* 753615Sbill * One pass over an archive with a table of contents. 754615Sbill * Remember the number of symbols currently defined, 755615Sbill * then call step on members which look promising (i.e. 756615Sbill * that define a symbol which is currently externally undefined). 757615Sbill * Indicate to our caller whether this process netted any more symbols. 758615Sbill */ 759615Sbill ldrand() 760615Sbill { 761615Sbill register struct nlist *sp, **hp; 762615Sbill register struct ranlib *tp, *tplast; 763615Sbill off_t loc; 764615Sbill int nsymt = symx(nextsym); 765615Sbill 766615Sbill tplast = &tab[tnum-1]; 767615Sbill for (tp = tab; tp <= tplast; tp++) { 768615Sbill if ((hp = slookup(tp->ran_un.ran_name)) == 0) 769615Sbill continue; 770615Sbill sp = *hp; 771615Sbill if (sp->n_type != N_EXT+N_UNDF) 772615Sbill continue; 773615Sbill step(tp->ran_off); 774615Sbill loc = tp->ran_off; 775615Sbill while (tp < tplast && (tp+1)->ran_off == loc) 776615Sbill tp++; 777615Sbill } 778615Sbill return (symx(nextsym) != nsymt); 779615Sbill } 780615Sbill 781615Sbill /* 782615Sbill * Examine a single file or archive member on pass 1. 783615Sbill */ 784615Sbill load1(libflg, loc) 785615Sbill off_t loc; 786615Sbill { 787615Sbill register struct nlist *sp; 788615Sbill struct nlist *savnext; 789615Sbill int ndef, nlocal, type, size, nsymt; 790615Sbill register int i; 791615Sbill off_t maxoff; 792615Sbill struct stat stb; 793615Sbill 794615Sbill readhdr(loc); 795615Sbill if (filhdr.a_syms == 0) { 796615Sbill if (filhdr.a_text+filhdr.a_data == 0) 797615Sbill return (0); 798615Sbill error(1, "no namelist"); 799615Sbill } 800615Sbill if (libflg) 801615Sbill maxoff = atol(archdr.ar_size); 802615Sbill else { 803615Sbill fstat(infil, &stb); 804615Sbill maxoff = stb.st_size; 805615Sbill } 806615Sbill if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff) 807615Sbill error(1, "too small (old format .o?)"); 808615Sbill ctrel = tsize; cdrel += dsize; cbrel += bsize; 809615Sbill ndef = 0; 810615Sbill nlocal = sizeof(cursym); 811615Sbill savnext = nextsym; 812615Sbill loc += N_SYMOFF(filhdr); 813615Sbill dseek(&text, loc, filhdr.a_syms); 814615Sbill dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t)); 815615Sbill mget(&size, sizeof (size), &reloc); 816615Sbill dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t)); 817615Sbill curstr = (char *)malloc(size); 818615Sbill if (curstr == NULL) 819615Sbill error(1, "no space for string table"); 820615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc); 821615Sbill while (text.size > 0) { 822615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 823615Sbill if (cursym.n_un.n_strx) { 824615Sbill if (cursym.n_un.n_strx<sizeof(size) || 825615Sbill cursym.n_un.n_strx>=size) 826615Sbill error(1, "bad string table index (pass 1)"); 827615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 828615Sbill } 829615Sbill type = cursym.n_type; 830615Sbill if ((type&N_EXT)==0) { 831615Sbill if (Xflag==0 || cursym.n_un.n_name[0]!='L' || 832615Sbill type & N_STAB) 833615Sbill nlocal += sizeof cursym; 834615Sbill continue; 835615Sbill } 836615Sbill symreloc(); 837615Sbill if (enter(lookup())) 838615Sbill continue; 839615Sbill if ((sp = lastsym)->n_type != N_EXT+N_UNDF) 840615Sbill continue; 841615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 842615Sbill if (cursym.n_value > sp->n_value) 843615Sbill sp->n_value = cursym.n_value; 844615Sbill continue; 845615Sbill } 846615Sbill if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT) 847615Sbill continue; 848615Sbill ndef++; 849615Sbill sp->n_type = cursym.n_type; 850615Sbill sp->n_value = cursym.n_value; 851615Sbill } 852615Sbill if (libflg==0 || ndef) { 853615Sbill tsize += filhdr.a_text; 854615Sbill dsize += round(filhdr.a_data, sizeof (long)); 855615Sbill bsize += round(filhdr.a_bss, sizeof (long)); 856615Sbill ssize += nlocal; 857615Sbill trsize += filhdr.a_trsize; 858615Sbill drsize += filhdr.a_drsize; 859615Sbill if (funding) 860615Sbill textbase = (*slookup("_end"))->n_value; 861615Sbill nsymt = symx(nextsym); 862615Sbill for (i = symx(savnext); i < nsymt; i++) { 863615Sbill sp = xsym(i); 864615Sbill sp->n_un.n_name = savestr(sp->n_un.n_name); 865615Sbill } 866615Sbill free(curstr); 867615Sbill return (1); 868615Sbill } 869615Sbill /* 870615Sbill * No symbols defined by this library member. 871615Sbill * Rip out the hash table entries and reset the symbol table. 872615Sbill */ 873615Sbill symfree(savnext); 874615Sbill free(curstr); 875615Sbill return(0); 876615Sbill } 877615Sbill 878615Sbill middle() 879615Sbill { 880615Sbill register struct nlist *sp; 881615Sbill long csize, t, corigin, ocsize; 882615Sbill int nund, rnd; 883615Sbill char s; 884615Sbill register int i; 885615Sbill int nsymt; 886615Sbill 887615Sbill torigin = 0; 888615Sbill dorigin = 0; 889615Sbill borigin = 0; 890615Sbill 891615Sbill p_etext = *slookup("_etext"); 892615Sbill p_edata = *slookup("_edata"); 893615Sbill p_end = *slookup("_end"); 894615Sbill /* 895615Sbill * If there are any undefined symbols, save the relocation bits. 896615Sbill */ 897615Sbill nsymt = symx(nextsym); 898615Sbill if (rflag==0) { 899615Sbill for (i = 0; i < nsymt; i++) { 900615Sbill sp = xsym(i); 901615Sbill if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 && 902650Sbill sp!=p_end && sp!=p_edata && sp!=p_etext) { 903615Sbill rflag++; 904615Sbill dflag = 0; 905615Sbill break; 906615Sbill } 907615Sbill } 908615Sbill } 909615Sbill if (rflag) 910615Sbill sflag = zflag = 0; 911615Sbill /* 912615Sbill * Assign common locations. 913615Sbill */ 914615Sbill csize = 0; 915615Sbill if (!Aflag) 916615Sbill addsym = symseg[0].sy_first; 917615Sbill database = round(tsize+textbase, 91812671Ssam (nflag||zflag? pagesize : sizeof (long))); 919615Sbill database += hsize; 920615Sbill if (dflag || rflag==0) { 921615Sbill ldrsym(p_etext, tsize, N_EXT+N_TEXT); 922615Sbill ldrsym(p_edata, dsize, N_EXT+N_DATA); 923615Sbill ldrsym(p_end, bsize, N_EXT+N_BSS); 924615Sbill for (i = symx(addsym); i < nsymt; i++) { 925615Sbill sp = xsym(i); 926615Sbill if ((s=sp->n_type)==N_EXT+N_UNDF && 927615Sbill (t = sp->n_value)!=0) { 928615Sbill if (t >= sizeof (double)) 929615Sbill rnd = sizeof (double); 930615Sbill else if (t >= sizeof (long)) 931615Sbill rnd = sizeof (long); 932615Sbill else 933615Sbill rnd = sizeof (short); 934615Sbill csize = round(csize, rnd); 935615Sbill sp->n_value = csize; 936615Sbill sp->n_type = N_EXT+N_COMM; 937615Sbill ocsize = csize; 938615Sbill csize += t; 939615Sbill } 940615Sbill if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) { 941615Sbill sp->n_value = ocsize; 942615Sbill sp->n_type = (s&N_STAB) | (N_EXT+N_COMM); 943615Sbill } 944615Sbill } 945615Sbill } 946615Sbill /* 947615Sbill * Now set symbols to their final value 948615Sbill */ 949615Sbill csize = round(csize, sizeof (long)); 950615Sbill torigin = textbase; 951615Sbill dorigin = database; 952615Sbill corigin = dorigin + dsize; 953615Sbill borigin = corigin + csize; 954615Sbill nund = 0; 955615Sbill nsymt = symx(nextsym); 956615Sbill for (i = symx(addsym); i<nsymt; i++) { 957615Sbill sp = xsym(i); 958615Sbill switch (sp->n_type & (N_TYPE+N_EXT)) { 959615Sbill 960615Sbill case N_EXT+N_UNDF: 9612369Skre if (arflag == 0) 9622369Skre errlev |= 01; 963615Sbill if ((arflag==0 || dflag) && sp->n_value==0) { 964650Sbill if (sp==p_end || sp==p_etext || sp==p_edata) 965650Sbill continue; 966615Sbill if (nund==0) 967615Sbill printf("Undefined:\n"); 968615Sbill nund++; 969615Sbill printf("%s\n", sp->n_un.n_name); 970615Sbill } 971615Sbill continue; 972615Sbill case N_EXT+N_ABS: 973615Sbill default: 974615Sbill continue; 975615Sbill case N_EXT+N_TEXT: 976615Sbill sp->n_value += torigin; 977615Sbill continue; 978615Sbill case N_EXT+N_DATA: 979615Sbill sp->n_value += dorigin; 980615Sbill continue; 981615Sbill case N_EXT+N_BSS: 982615Sbill sp->n_value += borigin; 983615Sbill continue; 984615Sbill case N_EXT+N_COMM: 985615Sbill sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS); 986615Sbill sp->n_value += corigin; 987615Sbill continue; 988615Sbill } 989615Sbill } 990615Sbill if (sflag || xflag) 991615Sbill ssize = 0; 992615Sbill bsize += csize; 993615Sbill nsym = ssize / (sizeof cursym); 994615Sbill if (Aflag) { 995615Sbill fixspec(p_etext,torigin); 996615Sbill fixspec(p_edata,dorigin); 997615Sbill fixspec(p_end,borigin); 998615Sbill } 999615Sbill } 1000615Sbill 1001615Sbill fixspec(sym,offset) 1002615Sbill struct nlist *sym; 1003615Sbill long offset; 1004615Sbill { 1005615Sbill 1006615Sbill if(symx(sym) < symx(addsym) && sym!=0) 1007615Sbill sym->n_value += offset; 1008615Sbill } 1009615Sbill 1010615Sbill ldrsym(sp, val, type) 1011615Sbill register struct nlist *sp; 1012615Sbill long val; 1013615Sbill { 1014615Sbill 1015615Sbill if (sp == 0) 1016615Sbill return; 1017615Sbill if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) { 1018615Sbill printf("%s: ", sp->n_un.n_name); 1019615Sbill error(0, "user attempt to redfine loader-defined symbol"); 1020615Sbill return; 1021615Sbill } 1022615Sbill sp->n_type = type; 1023615Sbill sp->n_value = val; 1024615Sbill } 1025615Sbill 1026615Sbill off_t wroff; 1027615Sbill struct biobuf toutb; 1028615Sbill 1029615Sbill setupout() 1030615Sbill { 1031615Sbill int bss; 103216068Sralph struct stat stbuf; 1033898Sbill extern char *sys_errlist[]; 1034898Sbill extern int errno; 1035615Sbill 10363606Ssklower ofilemode = 0777 & ~umask(0); 10373606Ssklower biofd = creat(ofilename, 0666 & ofilemode); 1038898Sbill if (biofd < 0) { 1039898Sbill filname = ofilename; /* kludge */ 1040898Sbill archdr.ar_name[0] = 0; /* kludge */ 1041898Sbill error(1, sys_errlist[errno]); /* kludge */ 1042898Sbill } 104316068Sralph fstat(biofd, &stbuf); /* suppose file exists, wrong*/ 104416068Sralph if (stbuf.st_mode & 0111) { /* mode, ld fails? */ 104516068Sralph chmod(ofilename, stbuf.st_mode & 0666); 104616068Sralph ofilemode = stbuf.st_mode; 104716068Sralph } 1048615Sbill filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC); 1049615Sbill filhdr.a_text = nflag ? tsize : 105012671Ssam round(tsize, zflag ? pagesize : sizeof (long)); 105112671Ssam filhdr.a_data = zflag ? round(dsize, pagesize) : dsize; 1052615Sbill bss = bsize - (filhdr.a_data - dsize); 1053615Sbill if (bss < 0) 1054615Sbill bss = 0; 1055615Sbill filhdr.a_bss = bss; 1056615Sbill filhdr.a_trsize = trsize; 1057615Sbill filhdr.a_drsize = drsize; 1058615Sbill filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym)); 1059615Sbill if (entrypt) { 1060615Sbill if (entrypt->n_type!=N_EXT+N_TEXT) 1061615Sbill error(0, "entry point not in text"); 1062615Sbill else 1063615Sbill filhdr.a_entry = entrypt->n_value; 1064615Sbill } else 1065615Sbill filhdr.a_entry = 0; 1066615Sbill filhdr.a_trsize = (rflag ? trsize:0); 1067615Sbill filhdr.a_drsize = (rflag ? drsize:0); 106816068Sralph tout = &toutb; 106916068Sralph bopen(tout, 0, stbuf.st_blksize); 1070615Sbill bwrite((char *)&filhdr, sizeof (filhdr), tout); 107116068Sralph if (zflag) 107216068Sralph bseek(tout, pagesize); 1073615Sbill wroff = N_TXTOFF(filhdr) + filhdr.a_text; 107416068Sralph outb(&dout, filhdr.a_data, stbuf.st_blksize); 1075615Sbill if (rflag) { 107616068Sralph outb(&trout, filhdr.a_trsize, stbuf.st_blksize); 107716068Sralph outb(&drout, filhdr.a_drsize, stbuf.st_blksize); 1078615Sbill } 1079615Sbill if (sflag==0 || xflag==0) { 108016068Sralph outb(&sout, filhdr.a_syms, stbuf.st_blksize); 1081615Sbill wroff += sizeof (offset); 108216068Sralph outb(&strout, 0, stbuf.st_blksize); 1083615Sbill } 1084615Sbill } 1085615Sbill 108616068Sralph outb(bp, inc, bufsize) 1087615Sbill register struct biobuf **bp; 1088615Sbill { 1089615Sbill 1090615Sbill *bp = (struct biobuf *)malloc(sizeof (struct biobuf)); 1091615Sbill if (*bp == 0) 1092615Sbill error(1, "ran out of memory (outb)"); 109316068Sralph bopen(*bp, wroff, bufsize); 1094615Sbill wroff += inc; 1095615Sbill } 1096615Sbill 1097615Sbill load2arg(acp) 1098615Sbill char *acp; 1099615Sbill { 1100615Sbill register char *cp; 1101615Sbill off_t loc; 1102615Sbill 1103615Sbill cp = acp; 1104615Sbill if (getfile(cp) == 0) { 1105615Sbill while (*cp) 1106615Sbill cp++; 1107615Sbill while (cp >= acp && *--cp != '/'); 1108615Sbill mkfsym(++cp); 1109615Sbill load2(0L); 1110615Sbill } else { /* scan archive members referenced */ 1111615Sbill for (;;) { 1112615Sbill if (clibseg->li_used2 == clibseg->li_used) { 1113615Sbill if (clibseg->li_used < NROUT) 1114615Sbill error(1, "libseg botch"); 1115615Sbill clibseg++; 1116615Sbill } 1117615Sbill loc = clibseg->li_first[clibseg->li_used2++]; 1118615Sbill if (loc == -1) 1119615Sbill break; 1120615Sbill dseek(&text, loc, (long)sizeof(archdr)); 1121615Sbill getarhdr(); 1122615Sbill mkfsym(archdr.ar_name); 1123615Sbill load2(loc + (long)sizeof(archdr)); 1124615Sbill } 1125615Sbill } 1126615Sbill close(infil); 1127615Sbill } 1128615Sbill 1129615Sbill load2(loc) 1130615Sbill long loc; 1131615Sbill { 1132615Sbill int size; 1133615Sbill register struct nlist *sp; 1134615Sbill register struct local *lp; 1135615Sbill register int symno, i; 1136615Sbill int type; 1137615Sbill 1138615Sbill readhdr(loc); 1139650Sbill if (!funding) { 1140615Sbill ctrel = torigin; 1141615Sbill cdrel += dorigin; 1142615Sbill cbrel += borigin; 1143615Sbill } 1144615Sbill /* 1145615Sbill * Reread the symbol table, recording the numbering 1146615Sbill * of symbols for fixing external references. 1147615Sbill */ 1148615Sbill for (i = 0; i < LHSIZ; i++) 1149615Sbill lochash[i] = 0; 1150615Sbill clocseg = locseg; 1151615Sbill clocseg->lo_used = 0; 1152615Sbill symno = -1; 1153615Sbill loc += N_TXTOFF(filhdr); 1154615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1155615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t)); 1156615Sbill mget(&size, sizeof(size), &text); 1157615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1158615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t), 1159615Sbill size - sizeof(off_t)); 1160615Sbill curstr = (char *)malloc(size); 1161615Sbill if (curstr == NULL) 1162615Sbill error(1, "out of space reading string table (pass 2)"); 1163615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &text); 1164615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1165615Sbill filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms); 1166615Sbill while (text.size > 0) { 1167615Sbill symno++; 1168615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 1169615Sbill if (cursym.n_un.n_strx) { 1170615Sbill if (cursym.n_un.n_strx<sizeof(size) || 1171615Sbill cursym.n_un.n_strx>=size) 1172615Sbill error(1, "bad string table index (pass 2)"); 1173615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 1174615Sbill } 1175615Sbill /* inline expansion of symreloc() */ 1176615Sbill switch (cursym.n_type & 017) { 1177615Sbill 1178615Sbill case N_TEXT: 1179615Sbill case N_EXT+N_TEXT: 1180615Sbill cursym.n_value += ctrel; 1181615Sbill break; 1182615Sbill case N_DATA: 1183615Sbill case N_EXT+N_DATA: 1184615Sbill cursym.n_value += cdrel; 1185615Sbill break; 1186615Sbill case N_BSS: 1187615Sbill case N_EXT+N_BSS: 1188615Sbill cursym.n_value += cbrel; 1189615Sbill break; 1190615Sbill case N_EXT+N_UNDF: 1191615Sbill break; 1192615Sbill default: 1193615Sbill if (cursym.n_type&N_EXT) 1194615Sbill cursym.n_type = N_EXT+N_ABS; 1195615Sbill } 1196615Sbill /* end inline expansion of symreloc() */ 1197615Sbill type = cursym.n_type; 1198898Sbill if (yflag && cursym.n_un.n_name) 1199898Sbill for (i = 0; i < yflag; i++) 1200898Sbill /* fast check for 2d character! */ 1201898Sbill if (ytab[i][1] == cursym.n_un.n_name[1] && 1202898Sbill !strcmp(ytab[i], cursym.n_un.n_name)) { 1203898Sbill tracesym(); 1204898Sbill break; 1205898Sbill } 1206615Sbill if ((type&N_EXT) == 0) { 1207615Sbill if (!sflag&&!xflag&& 1208615Sbill (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB)) 1209615Sbill symwrite(&cursym, sout); 1210615Sbill continue; 1211615Sbill } 1212615Sbill if (funding) 1213615Sbill continue; 1214615Sbill if ((sp = *lookup()) == 0) 1215615Sbill error(1, "internal error: symbol not found"); 1216615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 1217615Sbill if (clocseg->lo_used == NSYMPR) { 1218615Sbill if (++clocseg == &locseg[NSEG]) 1219615Sbill error(1, "local symbol overflow"); 1220615Sbill clocseg->lo_used = 0; 1221615Sbill } 1222615Sbill if (clocseg->lo_first == 0) { 1223615Sbill clocseg->lo_first = (struct local *) 1224615Sbill malloc(NSYMPR * sizeof (struct local)); 1225615Sbill if (clocseg->lo_first == 0) 1226615Sbill error(1, "out of memory (clocseg)"); 1227615Sbill } 1228615Sbill lp = &clocseg->lo_first[clocseg->lo_used++]; 1229615Sbill lp->l_index = symno; 1230615Sbill lp->l_symbol = sp; 1231615Sbill lp->l_link = lochash[symno % LHSIZ]; 1232615Sbill lochash[symno % LHSIZ] = lp; 1233615Sbill continue; 1234615Sbill } 1235615Sbill if (cursym.n_type & N_STAB) 1236615Sbill continue; 1237615Sbill if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) { 1238615Sbill printf("%s: ", cursym.n_un.n_name); 1239615Sbill error(0, "multiply defined"); 1240615Sbill } 1241615Sbill } 1242615Sbill if (funding) 1243615Sbill return; 1244615Sbill dseek(&text, loc, filhdr.a_text); 1245615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize); 1246650Sbill load2td(ctrel, torigin - textbase, tout, trout); 1247615Sbill dseek(&text, loc+filhdr.a_text, filhdr.a_data); 1248615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, 1249615Sbill filhdr.a_drsize); 1250650Sbill load2td(cdrel, dorigin - database, dout, drout); 1251615Sbill while (filhdr.a_data & (sizeof(long)-1)) { 1252615Sbill bputc(0, dout); 1253615Sbill filhdr.a_data++; 1254615Sbill } 1255615Sbill torigin += filhdr.a_text; 12561752Sbill dorigin += round(filhdr.a_data, sizeof (long)); 12571752Sbill borigin += round(filhdr.a_bss, sizeof (long)); 1258615Sbill free(curstr); 1259615Sbill } 1260615Sbill 1261898Sbill struct tynames { 1262898Sbill int ty_value; 1263898Sbill char *ty_name; 1264898Sbill } tynames[] = { 1265898Sbill N_UNDF, "undefined", 1266898Sbill N_ABS, "absolute", 1267898Sbill N_TEXT, "text", 1268898Sbill N_DATA, "data", 1269898Sbill N_BSS, "bss", 1270898Sbill N_COMM, "common", 1271898Sbill 0, 0, 1272898Sbill }; 1273898Sbill 1274898Sbill tracesym() 1275898Sbill { 1276898Sbill register struct tynames *tp; 1277898Sbill 1278898Sbill if (cursym.n_type & N_STAB) 1279898Sbill return; 1280898Sbill printf("%s", filname); 1281898Sbill if (archdr.ar_name[0]) 1282898Sbill printf("(%s)", archdr.ar_name); 1283898Sbill printf(": "); 1284898Sbill if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) { 1285898Sbill printf("definition of common %s size %d\n", 1286898Sbill cursym.n_un.n_name, cursym.n_value); 1287898Sbill return; 1288898Sbill } 1289898Sbill for (tp = tynames; tp->ty_name; tp++) 1290898Sbill if (tp->ty_value == (cursym.n_type&N_TYPE)) 1291898Sbill break; 1292898Sbill printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to"); 1293898Sbill if (cursym.n_type&N_EXT) 1294898Sbill printf(" external"); 1295898Sbill if (tp->ty_name) 1296898Sbill printf(" %s", tp->ty_name); 1297898Sbill printf(" %s\n", cursym.n_un.n_name); 1298898Sbill } 1299898Sbill 1300650Sbill /* 1301650Sbill * This routine relocates the single text or data segment argument. 1302650Sbill * Offsets from external symbols are resolved by adding the value 1303650Sbill * of the external symbols. Non-external reference are updated to account 1304650Sbill * for the relative motion of the segments (ctrel, cdrel, ...). If 1305650Sbill * a relocation was pc-relative, then we update it to reflect the 1306650Sbill * change in the positioning of the segments by adding the displacement 1307650Sbill * of the referenced segment and subtracting the displacement of the 1308650Sbill * current segment (creloc). 1309650Sbill * 1310650Sbill * If we are saving the relocation information, then we increase 1311650Sbill * each relocation datum address by our base position in the new segment. 1312650Sbill */ 1313650Sbill load2td(creloc, position, b1, b2) 1314650Sbill long creloc, offset; 1315615Sbill struct biobuf *b1, *b2; 1316615Sbill { 1317615Sbill register struct nlist *sp; 1318615Sbill register struct local *lp; 1319615Sbill long tw; 1320615Sbill register struct relocation_info *rp, *rpend; 1321615Sbill struct relocation_info *relp; 1322615Sbill char *codep; 1323615Sbill register char *cp; 1324615Sbill int relsz, codesz; 1325615Sbill 1326615Sbill relsz = reloc.size; 1327615Sbill relp = (struct relocation_info *)malloc(relsz); 1328615Sbill codesz = text.size; 1329615Sbill codep = (char *)malloc(codesz); 1330615Sbill if (relp == 0 || codep == 0) 1331615Sbill error(1, "out of memory (load2td)"); 1332615Sbill mget((char *)relp, relsz, &reloc); 1333615Sbill rpend = &relp[relsz / sizeof (struct relocation_info)]; 1334615Sbill mget(codep, codesz, &text); 1335615Sbill for (rp = relp; rp < rpend; rp++) { 1336615Sbill cp = codep + rp->r_address; 1337650Sbill /* 1338650Sbill * Pick up previous value at location to be relocated. 1339650Sbill */ 1340615Sbill switch (rp->r_length) { 1341615Sbill 1342615Sbill case 0: /* byte */ 1343615Sbill tw = *cp; 1344615Sbill break; 1345615Sbill 1346615Sbill case 1: /* word */ 1347615Sbill tw = *(short *)cp; 1348615Sbill break; 1349615Sbill 1350615Sbill case 2: /* long */ 1351615Sbill tw = *(long *)cp; 1352615Sbill break; 1353615Sbill 1354615Sbill default: 1355615Sbill error(1, "load2td botch: bad length"); 1356615Sbill } 1357650Sbill /* 1358650Sbill * If relative to an external which is defined, 1359650Sbill * resolve to a simpler kind of reference in the 1360650Sbill * result file. If the external is undefined, just 1361650Sbill * convert the symbol number to the number of the 1362650Sbill * symbol in the result file and leave it undefined. 1363650Sbill */ 1364615Sbill if (rp->r_extern) { 1365650Sbill /* 1366650Sbill * Search the hash table which maps local 1367650Sbill * symbol numbers to symbol tables entries 1368650Sbill * in the new a.out file. 1369650Sbill */ 1370615Sbill lp = lochash[rp->r_symbolnum % LHSIZ]; 1371615Sbill while (lp->l_index != rp->r_symbolnum) { 1372615Sbill lp = lp->l_link; 1373615Sbill if (lp == 0) 1374615Sbill error(1, "local symbol botch"); 1375615Sbill } 1376615Sbill sp = lp->l_symbol; 1377615Sbill if (sp->n_type == N_EXT+N_UNDF) 1378615Sbill rp->r_symbolnum = nsym+symx(sp); 1379615Sbill else { 1380615Sbill rp->r_symbolnum = sp->n_type & N_TYPE; 1381615Sbill tw += sp->n_value; 1382615Sbill rp->r_extern = 0; 1383615Sbill } 1384615Sbill } else switch (rp->r_symbolnum & N_TYPE) { 1385650Sbill /* 1386650Sbill * Relocation is relative to the loaded position 1387650Sbill * of another segment. Update by the change in position 1388650Sbill * of that segment. 1389650Sbill */ 1390615Sbill case N_TEXT: 1391615Sbill tw += ctrel; 1392615Sbill break; 1393615Sbill case N_DATA: 1394615Sbill tw += cdrel; 1395615Sbill break; 1396615Sbill case N_BSS: 1397615Sbill tw += cbrel; 1398615Sbill break; 1399615Sbill case N_ABS: 1400615Sbill break; 1401615Sbill default: 1402615Sbill error(1, "relocation format botch (symbol type))"); 1403615Sbill } 1404650Sbill /* 1405650Sbill * Relocation is pc relative, so decrease the relocation 1406650Sbill * by the amount the current segment is displaced. 1407650Sbill * (E.g if we are a relative reference to a text location 1408650Sbill * from data space, we added the increase in the text address 1409650Sbill * above, and subtract the increase in our (data) address 1410650Sbill * here, leaving the net change the relative change in the 1411650Sbill * positioning of our text and data segments.) 1412650Sbill */ 1413615Sbill if (rp->r_pcrel) 1414615Sbill tw -= creloc; 1415650Sbill /* 1416650Sbill * Put the value back in the segment, 1417650Sbill * while checking for overflow. 1418650Sbill */ 1419615Sbill switch (rp->r_length) { 1420615Sbill 1421615Sbill case 0: /* byte */ 1422615Sbill if (tw < -128 || tw > 127) 1423615Sbill error(0, "byte displacement overflow"); 1424615Sbill *cp = tw; 1425615Sbill break; 1426615Sbill case 1: /* word */ 1427615Sbill if (tw < -32768 || tw > 32767) 1428615Sbill error(0, "word displacement overflow"); 1429615Sbill *(short *)cp = tw; 1430615Sbill break; 1431615Sbill case 2: /* long */ 1432615Sbill *(long *)cp = tw; 1433615Sbill break; 1434615Sbill } 1435650Sbill /* 1436650Sbill * If we are saving relocation information, 1437650Sbill * we must convert the address in the segment from 1438650Sbill * the old .o file into an address in the segment in 1439650Sbill * the new a.out, by adding the position of our 1440650Sbill * segment in the new larger segment. 1441650Sbill */ 1442615Sbill if (rflag) 1443650Sbill rp->r_address += position; 1444615Sbill } 1445615Sbill bwrite(codep, codesz, b1); 1446615Sbill if (rflag) 1447615Sbill bwrite(relp, relsz, b2); 1448615Sbill cfree((char *)relp); 1449615Sbill cfree(codep); 1450615Sbill } 1451615Sbill 1452615Sbill finishout() 1453615Sbill { 1454615Sbill register int i; 1455615Sbill int nsymt; 1456615Sbill 1457615Sbill if (sflag==0) { 1458615Sbill nsymt = symx(nextsym); 1459615Sbill for (i = 0; i < nsymt; i++) 1460615Sbill symwrite(xsym(i), sout); 1461615Sbill bwrite(&offset, sizeof offset, sout); 1462615Sbill } 1463615Sbill if (!ofilfnd) { 1464615Sbill unlink("a.out"); 1465898Sbill if (link("l.out", "a.out") < 0) 1466898Sbill error(1, "cannot move l.out to a.out"); 1467615Sbill ofilename = "a.out"; 1468615Sbill } 1469615Sbill delarg = errlev; 1470615Sbill delexit(); 1471615Sbill } 1472615Sbill 1473615Sbill mkfsym(s) 1474615Sbill char *s; 1475615Sbill { 1476615Sbill 1477615Sbill if (sflag || xflag) 1478615Sbill return; 1479615Sbill cursym.n_un.n_name = s; 1480615Sbill cursym.n_type = N_TEXT; 1481615Sbill cursym.n_value = torigin; 1482615Sbill symwrite(&cursym, sout); 1483615Sbill } 1484615Sbill 1485615Sbill getarhdr() 1486615Sbill { 1487615Sbill register char *cp; 1488615Sbill 1489615Sbill mget((char *)&archdr, sizeof archdr, &text); 1490615Sbill for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];) 1491615Sbill if (*cp++ == ' ') { 1492615Sbill cp[-1] = 0; 1493615Sbill return; 1494615Sbill } 1495615Sbill } 1496615Sbill 1497615Sbill mget(loc, n, sp) 1498615Sbill register STREAM *sp; 1499615Sbill register char *loc; 1500615Sbill { 1501615Sbill register char *p; 1502615Sbill register int take; 1503615Sbill 1504615Sbill top: 1505615Sbill if (n == 0) 1506615Sbill return; 1507615Sbill if (sp->size && sp->nibuf) { 1508615Sbill p = sp->ptr; 1509615Sbill take = sp->size; 1510615Sbill if (take > sp->nibuf) 1511615Sbill take = sp->nibuf; 1512615Sbill if (take > n) 1513615Sbill take = n; 1514615Sbill n -= take; 1515615Sbill sp->size -= take; 1516615Sbill sp->nibuf -= take; 1517615Sbill sp->pos += take; 1518615Sbill do 1519615Sbill *loc++ = *p++; 1520615Sbill while (--take > 0); 1521615Sbill sp->ptr = p; 1522615Sbill goto top; 1523615Sbill } 152416068Sralph if (n > p_blksize) { 152516068Sralph take = n - n % p_blksize; 152616068Sralph lseek(infil, (sp->bno+1)<<p_blkshift, 0); 1527615Sbill if (take > sp->size || read(infil, loc, take) != take) 1528615Sbill error(1, "premature EOF"); 1529615Sbill loc += take; 1530615Sbill n -= take; 1531615Sbill sp->size -= take; 1532615Sbill sp->pos += take; 153316068Sralph dseek(sp, (sp->bno+1+(take>>p_blkshift))<<p_blkshift, -1); 1534615Sbill goto top; 1535615Sbill } 1536615Sbill *loc++ = get(sp); 1537615Sbill --n; 1538615Sbill goto top; 1539615Sbill } 1540615Sbill 1541615Sbill symwrite(sp, bp) 1542615Sbill struct nlist *sp; 1543615Sbill struct biobuf *bp; 1544615Sbill { 1545615Sbill register int len; 1546615Sbill register char *str; 1547615Sbill 1548615Sbill str = sp->n_un.n_name; 1549615Sbill if (str) { 1550615Sbill sp->n_un.n_strx = offset; 1551615Sbill len = strlen(str) + 1; 1552615Sbill bwrite(str, len, strout); 1553615Sbill offset += len; 1554615Sbill } 1555615Sbill bwrite(sp, sizeof (*sp), bp); 1556615Sbill sp->n_un.n_name = str; 1557615Sbill } 1558615Sbill 1559615Sbill dseek(sp, loc, s) 1560615Sbill register STREAM *sp; 1561615Sbill long loc, s; 1562615Sbill { 1563615Sbill register PAGE *p; 1564615Sbill register b, o; 1565615Sbill int n; 1566615Sbill 156716068Sralph b = loc>>p_blkshift; 156816068Sralph o = loc&p_blkmask; 1569615Sbill if (o&01) 1570615Sbill error(1, "loader error; odd offset"); 1571615Sbill --sp->pno->nuser; 1572615Sbill if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b) 1573615Sbill if (p->nuser==0 || (p = &page[0])->nuser==0) { 1574615Sbill if (page[0].nuser==0 && page[1].nuser==0) 1575615Sbill if (page[0].bno < page[1].bno) 1576615Sbill p = &page[0]; 1577615Sbill p->bno = b; 157816068Sralph lseek(infil, loc & ~(long)p_blkmask, 0); 157916068Sralph if ((n = read(infil, p->buff, p_blksize)) < 0) 1580615Sbill n = 0; 1581615Sbill p->nibuf = n; 158216068Sralph } else 158316068Sralph error(1, "botch: no pages"); 1584615Sbill ++p->nuser; 1585615Sbill sp->bno = b; 1586615Sbill sp->pno = p; 1587615Sbill if (s != -1) {sp->size = s; sp->pos = 0;} 1588615Sbill sp->ptr = (char *)(p->buff + o); 1589615Sbill if ((sp->nibuf = p->nibuf-o) <= 0) 1590615Sbill sp->size = 0; 1591615Sbill } 1592615Sbill 1593615Sbill char 1594615Sbill get(asp) 1595615Sbill STREAM *asp; 1596615Sbill { 1597615Sbill register STREAM *sp; 1598615Sbill 1599615Sbill sp = asp; 1600615Sbill if ((sp->nibuf -= sizeof(char)) < 0) { 160116068Sralph dseek(sp, ((long)(sp->bno+1)<<p_blkshift), (long)-1); 1602615Sbill sp->nibuf -= sizeof(char); 1603615Sbill } 1604615Sbill if ((sp->size -= sizeof(char)) <= 0) { 1605615Sbill if (sp->size < 0) 1606615Sbill error(1, "premature EOF"); 1607615Sbill ++fpage.nuser; 1608615Sbill --sp->pno->nuser; 1609615Sbill sp->pno = (PAGE *) &fpage; 1610615Sbill } 1611615Sbill sp->pos += sizeof(char); 1612615Sbill return(*sp->ptr++); 1613615Sbill } 1614615Sbill 1615615Sbill getfile(acp) 1616615Sbill char *acp; 1617615Sbill { 1618615Sbill register int c; 1619615Sbill char arcmag[SARMAG+1]; 1620615Sbill struct stat stb; 1621615Sbill 1622615Sbill archdr.ar_name[0] = '\0'; 1623*17133Ssam filname = acp; 1624*17133Ssam if (filname[0] == '-' && filname[1] == 'l') 1625*17133Ssam infil = libopen(filname + 2, O_RDONLY); 1626*17133Ssam else 1627*17133Ssam infil = open(filname, O_RDONLY); 1628*17133Ssam if (infil < 0) 1629615Sbill error(1, "cannot open"); 163016068Sralph fstat(infil, &stb); 1631615Sbill page[0].bno = page[1].bno = -1; 1632615Sbill page[0].nuser = page[1].nuser = 0; 163316068Sralph c = stb.st_blksize; 163416068Sralph if (c == 0 || (c & (c - 1)) != 0) { 163516068Sralph /* use default size if not a power of two */ 163616068Sralph c = BLKSIZE; 163716068Sralph } 163816068Sralph if (p_blksize != c) { 163916068Sralph p_blksize = c; 164016068Sralph p_blkmask = c - 1; 164116068Sralph for (p_blkshift = 0; c > 1 ; p_blkshift++) 164216068Sralph c >>= 1; 164316068Sralph if (page[0].buff != NULL) 164416068Sralph free(page[0].buff); 164516068Sralph page[0].buff = (char *)malloc(p_blksize); 164616068Sralph if (page[0].buff == NULL) 164716068Sralph error(1, "ran out of memory (getfile)"); 164816068Sralph if (page[1].buff != NULL) 164916068Sralph free(page[1].buff); 165016068Sralph page[1].buff = (char *)malloc(p_blksize); 165116068Sralph if (page[1].buff == NULL) 165216068Sralph error(1, "ran out of memory (getfile)"); 165316068Sralph } 1654615Sbill text.pno = reloc.pno = (PAGE *) &fpage; 1655615Sbill fpage.nuser = 2; 1656615Sbill dseek(&text, 0L, SARMAG); 1657615Sbill if (text.size <= 0) 1658615Sbill error(1, "premature EOF"); 1659615Sbill mget((char *)arcmag, SARMAG, &text); 1660615Sbill arcmag[SARMAG] = 0; 1661615Sbill if (strcmp(arcmag, ARMAG)) 1662615Sbill return (0); 1663615Sbill dseek(&text, SARMAG, sizeof archdr); 1664*17133Ssam if (text.size <= 0) 1665615Sbill return (1); 1666615Sbill getarhdr(); 1667615Sbill if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0) 1668615Sbill return (1); 1669615Sbill return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2); 1670615Sbill } 1671615Sbill 1672*17133Ssam /* 1673*17133Ssam * Search for a library with given name 1674*17133Ssam * using the directory search array. 1675*17133Ssam */ 1676*17133Ssam libopen(name, oflags) 1677*17133Ssam char *name; 1678*17133Ssam int oflags; 1679*17133Ssam { 1680*17133Ssam register char *p, *cp; 1681*17133Ssam register int i; 1682*17133Ssam static char buf[MAXPATHLEN+1]; 1683*17133Ssam int fd = -1; 1684*17133Ssam 1685*17133Ssam if (*name == '\0') /* backwards compat */ 1686*17133Ssam name = "a"; 1687*17133Ssam for (i = 0; i < ndir && fd == -1; i++) { 1688*17133Ssam p = buf; 1689*17133Ssam for (cp = dirs[i]; *cp; *p++ = *cp++) 1690*17133Ssam ; 1691*17133Ssam *p++ = '/'; 1692*17133Ssam for (cp = "lib"; *cp; *p++ = *cp++) 1693*17133Ssam ; 1694*17133Ssam for (cp = name; *cp; *p++ = *cp++) 1695*17133Ssam ; 1696*17133Ssam cp = ".a"; 1697*17133Ssam while (*p++ = *cp++) 1698*17133Ssam ; 1699*17133Ssam fd = open(buf, oflags); 1700*17133Ssam } 1701*17133Ssam if (fd != -1) 1702*17133Ssam filname = buf; 1703*17133Ssam return (fd); 1704*17133Ssam } 1705*17133Ssam 1706615Sbill struct nlist ** 1707615Sbill lookup() 1708615Sbill { 1709615Sbill register int sh; 1710615Sbill register struct nlist **hp; 1711615Sbill register char *cp, *cp1; 1712615Sbill register struct symseg *gp; 1713615Sbill register int i; 1714615Sbill 1715615Sbill sh = 0; 1716615Sbill for (cp = cursym.n_un.n_name; *cp;) 1717615Sbill sh = (sh<<1) + *cp++; 1718615Sbill sh = (sh & 0x7fffffff) % HSIZE; 1719615Sbill for (gp = symseg; gp < &symseg[NSEG]; gp++) { 1720615Sbill if (gp->sy_first == 0) { 1721615Sbill gp->sy_first = (struct nlist *) 1722615Sbill calloc(NSYM, sizeof (struct nlist)); 1723615Sbill gp->sy_hfirst = (struct nlist **) 1724615Sbill calloc(HSIZE, sizeof (struct nlist *)); 1725615Sbill if (gp->sy_first == 0 || gp->sy_hfirst == 0) 1726615Sbill error(1, "ran out of space for symbol table"); 1727615Sbill gp->sy_last = gp->sy_first + NSYM; 1728615Sbill gp->sy_hlast = gp->sy_hfirst + HSIZE; 1729615Sbill } 1730615Sbill if (gp > csymseg) 1731615Sbill csymseg = gp; 1732615Sbill hp = gp->sy_hfirst + sh; 1733615Sbill i = 1; 1734615Sbill do { 1735615Sbill if (*hp == 0) { 1736615Sbill if (gp->sy_used == NSYM) 1737615Sbill break; 1738615Sbill return (hp); 1739615Sbill } 1740615Sbill cp1 = (*hp)->n_un.n_name; 1741615Sbill for (cp = cursym.n_un.n_name; *cp == *cp1++;) 1742615Sbill if (*cp++ == 0) 1743615Sbill return (hp); 1744615Sbill hp += i; 1745615Sbill i += 2; 1746615Sbill if (hp >= gp->sy_hlast) 1747615Sbill hp -= HSIZE; 1748615Sbill } while (i < HSIZE); 1749615Sbill if (i > HSIZE) 1750615Sbill error(1, "hash table botch"); 1751615Sbill } 1752615Sbill error(1, "symbol table overflow"); 1753615Sbill /*NOTREACHED*/ 1754615Sbill } 1755615Sbill 1756615Sbill symfree(saved) 1757615Sbill struct nlist *saved; 1758615Sbill { 1759615Sbill register struct symseg *gp; 1760615Sbill register struct nlist *sp; 1761615Sbill 1762615Sbill for (gp = csymseg; gp >= symseg; gp--, csymseg--) { 1763615Sbill sp = gp->sy_first + gp->sy_used; 1764615Sbill if (sp == saved) { 1765615Sbill nextsym = sp; 1766615Sbill return; 1767615Sbill } 1768615Sbill for (sp--; sp >= gp->sy_first; sp--) { 1769615Sbill gp->sy_hfirst[sp->n_hash] = 0; 1770615Sbill gp->sy_used--; 1771615Sbill if (sp == saved) { 1772615Sbill nextsym = sp; 1773615Sbill return; 1774615Sbill } 1775615Sbill } 1776615Sbill } 1777615Sbill if (saved == 0) 1778615Sbill return; 1779615Sbill error(1, "symfree botch"); 1780615Sbill } 1781615Sbill 1782615Sbill struct nlist ** 1783615Sbill slookup(s) 1784615Sbill char *s; 1785615Sbill { 1786615Sbill 1787615Sbill cursym.n_un.n_name = s; 1788615Sbill cursym.n_type = N_EXT+N_UNDF; 1789615Sbill cursym.n_value = 0; 1790615Sbill return (lookup()); 1791615Sbill } 1792615Sbill 1793615Sbill enter(hp) 1794615Sbill register struct nlist **hp; 1795615Sbill { 1796615Sbill register struct nlist *sp; 1797615Sbill 1798615Sbill if (*hp==0) { 1799615Sbill if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast) 1800615Sbill error(1, "enter botch"); 1801615Sbill *hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used; 1802615Sbill csymseg->sy_used++; 1803615Sbill sp->n_un.n_name = cursym.n_un.n_name; 1804615Sbill sp->n_type = cursym.n_type; 1805615Sbill sp->n_hash = hp - csymseg->sy_hfirst; 1806615Sbill sp->n_value = cursym.n_value; 1807615Sbill nextsym = lastsym + 1; 1808615Sbill return(1); 1809615Sbill } else { 1810615Sbill lastsym = *hp; 1811615Sbill return(0); 1812615Sbill } 1813615Sbill } 1814615Sbill 1815615Sbill symx(sp) 1816615Sbill struct nlist *sp; 1817615Sbill { 1818615Sbill register struct symseg *gp; 1819615Sbill 1820615Sbill if (sp == 0) 1821615Sbill return (0); 1822615Sbill for (gp = csymseg; gp >= symseg; gp--) 1823615Sbill /* <= is sloppy so nextsym will always work */ 1824615Sbill if (sp >= gp->sy_first && sp <= gp->sy_last) 1825615Sbill return ((gp - symseg) * NSYM + sp - gp->sy_first); 1826615Sbill error(1, "symx botch"); 1827615Sbill /*NOTREACHED*/ 1828615Sbill } 1829615Sbill 1830615Sbill symreloc() 1831615Sbill { 1832615Sbill if(funding) return; 1833615Sbill switch (cursym.n_type & 017) { 1834615Sbill 1835615Sbill case N_TEXT: 1836615Sbill case N_EXT+N_TEXT: 1837615Sbill cursym.n_value += ctrel; 1838615Sbill return; 1839615Sbill 1840615Sbill case N_DATA: 1841615Sbill case N_EXT+N_DATA: 1842615Sbill cursym.n_value += cdrel; 1843615Sbill return; 1844615Sbill 1845615Sbill case N_BSS: 1846615Sbill case N_EXT+N_BSS: 1847615Sbill cursym.n_value += cbrel; 1848615Sbill return; 1849615Sbill 1850615Sbill case N_EXT+N_UNDF: 1851615Sbill return; 1852615Sbill 1853615Sbill default: 1854615Sbill if (cursym.n_type&N_EXT) 1855615Sbill cursym.n_type = N_EXT+N_ABS; 1856615Sbill return; 1857615Sbill } 1858615Sbill } 1859615Sbill 1860615Sbill error(n, s) 1861615Sbill char *s; 1862615Sbill { 1863898Sbill 1864615Sbill if (errlev==0) 1865615Sbill printf("ld:"); 1866615Sbill if (filname) { 1867615Sbill printf("%s", filname); 1868615Sbill if (n != -1 && archdr.ar_name[0]) 1869615Sbill printf("(%s)", archdr.ar_name); 1870615Sbill printf(": "); 1871615Sbill } 1872615Sbill printf("%s\n", s); 1873615Sbill if (n == -1) 1874615Sbill return; 1875615Sbill if (n) 1876615Sbill delexit(); 1877615Sbill errlev = 2; 1878615Sbill } 1879615Sbill 1880615Sbill readhdr(loc) 1881615Sbill off_t loc; 1882615Sbill { 1883615Sbill 1884615Sbill dseek(&text, loc, (long)sizeof(filhdr)); 1885615Sbill mget((short *)&filhdr, sizeof(filhdr), &text); 1886615Sbill if (N_BADMAG(filhdr)) { 1887615Sbill if (filhdr.a_magic == OARMAG) 1888615Sbill error(1, "old archive"); 1889615Sbill error(1, "bad magic number"); 1890615Sbill } 1891615Sbill if (filhdr.a_text&01 || filhdr.a_data&01) 1892615Sbill error(1, "text/data size odd"); 1893615Sbill if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) { 189412671Ssam cdrel = -round(filhdr.a_text, pagesize); 1895615Sbill cbrel = cdrel - filhdr.a_data; 1896615Sbill } else if (filhdr.a_magic == OMAGIC) { 1897615Sbill cdrel = -filhdr.a_text; 1898615Sbill cbrel = cdrel - filhdr.a_data; 1899615Sbill } else 1900615Sbill error(1, "bad format"); 1901615Sbill } 1902615Sbill 1903615Sbill round(v, r) 1904615Sbill int v; 1905615Sbill u_long r; 1906615Sbill { 1907615Sbill 1908615Sbill r--; 1909615Sbill v += r; 1910615Sbill v &= ~(long)r; 1911615Sbill return(v); 1912615Sbill } 1913615Sbill 1914615Sbill #define NSAVETAB 8192 1915615Sbill char *savetab; 1916615Sbill int saveleft; 1917615Sbill 1918615Sbill char * 1919615Sbill savestr(cp) 1920615Sbill register char *cp; 1921615Sbill { 1922615Sbill register int len; 1923615Sbill 1924615Sbill len = strlen(cp) + 1; 1925615Sbill if (len > saveleft) { 1926615Sbill saveleft = NSAVETAB; 1927615Sbill if (len > saveleft) 1928615Sbill saveleft = len; 1929*17133Ssam savetab = malloc(saveleft); 1930615Sbill if (savetab == 0) 1931615Sbill error(1, "ran out of memory (savestr)"); 1932615Sbill } 1933615Sbill strncpy(savetab, cp, len); 1934615Sbill cp = savetab; 1935615Sbill savetab += len; 1936615Sbill saveleft -= len; 1937615Sbill return (cp); 1938615Sbill } 1939615Sbill 194016068Sralph bopen(bp, off, bufsize) 194116068Sralph register struct biobuf *bp; 1942615Sbill { 1943615Sbill 1944*17133Ssam bp->b_ptr = bp->b_buf = malloc(bufsize); 194516068Sralph if (bp->b_ptr == (char *)0) 194616068Sralph error(1, "ran out of memory (bopen)"); 194716068Sralph bp->b_bufsize = bufsize; 194816068Sralph bp->b_nleft = bufsize - (off % bufsize); 1949615Sbill bp->b_off = off; 1950615Sbill bp->b_link = biobufs; 1951615Sbill biobufs = bp; 1952615Sbill } 1953615Sbill 1954615Sbill int bwrerror; 1955615Sbill 1956615Sbill bwrite(p, cnt, bp) 1957615Sbill register char *p; 1958615Sbill register int cnt; 1959615Sbill register struct biobuf *bp; 1960615Sbill { 1961615Sbill register int put; 1962615Sbill register char *to; 1963615Sbill 1964615Sbill top: 1965615Sbill if (cnt == 0) 1966615Sbill return; 1967615Sbill if (bp->b_nleft) { 1968615Sbill put = bp->b_nleft; 1969615Sbill if (put > cnt) 1970615Sbill put = cnt; 1971615Sbill bp->b_nleft -= put; 1972615Sbill to = bp->b_ptr; 1973615Sbill asm("movc3 r8,(r11),(r7)"); 1974615Sbill bp->b_ptr += put; 1975615Sbill p += put; 1976615Sbill cnt -= put; 1977615Sbill goto top; 1978615Sbill } 197916068Sralph if (cnt >= bp->b_bufsize) { 1980615Sbill if (bp->b_ptr != bp->b_buf) 1981615Sbill bflush1(bp); 198216068Sralph put = cnt - cnt % bp->b_bufsize; 1983615Sbill if (boffset != bp->b_off) 1984615Sbill lseek(biofd, bp->b_off, 0); 1985615Sbill if (write(biofd, p, put) != put) { 1986615Sbill bwrerror = 1; 1987615Sbill error(1, "output write error"); 1988615Sbill } 1989615Sbill bp->b_off += put; 1990615Sbill boffset = bp->b_off; 1991615Sbill p += put; 1992615Sbill cnt -= put; 1993615Sbill goto top; 1994615Sbill } 1995615Sbill bflush1(bp); 1996615Sbill goto top; 1997615Sbill } 1998615Sbill 1999615Sbill bflush() 2000615Sbill { 2001615Sbill register struct biobuf *bp; 2002615Sbill 2003615Sbill if (bwrerror) 2004615Sbill return; 2005615Sbill for (bp = biobufs; bp; bp = bp->b_link) 2006615Sbill bflush1(bp); 2007615Sbill } 2008615Sbill 2009615Sbill bflush1(bp) 2010615Sbill register struct biobuf *bp; 2011615Sbill { 2012615Sbill register int cnt = bp->b_ptr - bp->b_buf; 2013615Sbill 2014615Sbill if (cnt == 0) 2015615Sbill return; 2016615Sbill if (boffset != bp->b_off) 2017615Sbill lseek(biofd, bp->b_off, 0); 2018615Sbill if (write(biofd, bp->b_buf, cnt) != cnt) { 2019615Sbill bwrerror = 1; 2020615Sbill error(1, "output write error"); 2021615Sbill } 2022615Sbill bp->b_off += cnt; 2023615Sbill boffset = bp->b_off; 2024615Sbill bp->b_ptr = bp->b_buf; 202516068Sralph bp->b_nleft = bp->b_bufsize; 2026615Sbill } 2027615Sbill 2028615Sbill bflushc(bp, c) 2029615Sbill register struct biobuf *bp; 2030615Sbill { 2031615Sbill 2032615Sbill bflush1(bp); 2033615Sbill bputc(c, bp); 2034615Sbill } 203516068Sralph 203616068Sralph bseek(bp, off) 203716068Sralph register struct biobuf *bp; 203816068Sralph register off_t off; 203916068Sralph { 204016068Sralph bflush1(bp); 204116068Sralph 204216068Sralph bp->b_nleft = bp->b_bufsize - (off % bp->b_bufsize); 204316068Sralph bp->b_off = off; 204416068Sralph } 2045