1*9332Smckusick static char sccsid[] = "@(#)ld.c 4.6 11/23/82"; 26414Smckusic 3615Sbill /* 4898Sbill * ld - string table version for VAX 5615Sbill */ 6615Sbill 7615Sbill #include <sys/types.h> 8615Sbill #include <signal.h> 9615Sbill #include <stdio.h> 10615Sbill #include <ctype.h> 11650Sbill #include <ar.h> 12650Sbill #include <a.out.h> 13615Sbill #include <ranlib.h> 14615Sbill #include <stat.h> 15615Sbill #include <pagsiz.h> 16615Sbill 17615Sbill /* 18615Sbill * Basic strategy: 19615Sbill * 20615Sbill * The loader takes a number of files and libraries as arguments. 21615Sbill * A first pass examines each file in turn. Normal files are 22615Sbill * unconditionally loaded, and the (external) symbols they define and require 23615Sbill * are noted in the symbol table. Libraries are searched, and the 24615Sbill * library members which define needed symbols are remembered 25615Sbill * in a special data structure so they can be selected on the second 26615Sbill * pass. Symbols defined and required by library members are also 27615Sbill * recorded. 28615Sbill * 29615Sbill * After the first pass, the loader knows the size of the basic text 30615Sbill * data, and bss segments from the sum of the sizes of the modules which 31615Sbill * were required. It has computed, for each ``common'' symbol, the 32615Sbill * maximum size of any reference to it, and these symbols are then assigned 33615Sbill * storage locations after their sizes are appropriately rounded. 34615Sbill * The loader now knows all sizes for the eventual output file, and 35615Sbill * can determine the final locations of external symbols before it 36615Sbill * begins a second pass. 37615Sbill * 38615Sbill * On the second pass each normal file and required library member 39615Sbill * is processed again. The symbol table for each such file is 40615Sbill * reread and relevant parts of it are placed in the output. The offsets 41615Sbill * in the local symbol table for externally defined symbols are recorded 42615Sbill * since relocation information refers to symbols in this way. 43615Sbill * Armed with all necessary information, the text and data segments 44615Sbill * are relocated and the result is placed in the output file, which 45615Sbill * is pasted together, ``in place'', by writing to it in several 46615Sbill * different places concurrently. 47615Sbill */ 48615Sbill 49615Sbill /* 50615Sbill * Internal data structures 51615Sbill * 52615Sbill * All internal data structures are segmented and dynamically extended. 53615Sbill * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT) 54615Sbill * referenced library members, and 100 (NSYMPR) private (local) symbols 55615Sbill * per object module. For large programs and/or modules, these structures 56615Sbill * expand to be up to 40 (NSEG) times as large as this as necessary. 57615Sbill */ 58615Sbill #define NSEG 40 /* Number of segments, each data structure */ 59615Sbill #define NSYM 1103 /* Number of symbols per segment */ 60615Sbill #define NROUT 250 /* Number of library references per segment */ 61615Sbill #define NSYMPR 100 /* Number of private symbols per segment */ 62615Sbill 63615Sbill /* 64615Sbill * Structure describing each symbol table segment. 65615Sbill * Each segment has its own hash table. We record the first 66615Sbill * address in and first address beyond both the symbol and hash 67615Sbill * tables, for use in the routine symx and the lookup routine respectively. 68615Sbill * The symfree routine also understands this structure well as it used 69615Sbill * to back out symbols from modules we decide that we don't need in pass 1. 70615Sbill * 71615Sbill * Csymseg points to the current symbol table segment; 72615Sbill * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated, 73615Sbill * (unless csymseg->sy_used == NSYM in which case we will allocate another 74615Sbill * symbol table segment first.) 75615Sbill */ 76615Sbill struct symseg { 77615Sbill struct nlist *sy_first; /* base of this alloc'ed segment */ 78615Sbill struct nlist *sy_last; /* end of this segment, for n_strx */ 79615Sbill int sy_used; /* symbols used in this seg */ 80615Sbill struct nlist **sy_hfirst; /* base of hash table, this seg */ 81615Sbill struct nlist **sy_hlast; /* end of hash table, this seg */ 82615Sbill } symseg[NSEG], *csymseg; 83615Sbill 84615Sbill /* 85615Sbill * The lookup routine uses quadratic rehash. Since a quadratic rehash 86615Sbill * only probes 1/2 of the buckets in the table, and since the hash 87615Sbill * table is segmented the same way the symbol table is, we make the 88615Sbill * hash table have twice as many buckets as there are symbol table slots 89615Sbill * in the segment. This guarantees that the quadratic rehash will never 90615Sbill * fail to find an empty bucket if the segment is not full and the 91615Sbill * symbol is not there. 92615Sbill */ 93615Sbill #define HSIZE (NSYM*2) 94615Sbill 95615Sbill /* 96615Sbill * Xsym converts symbol table indices (ala x) into symbol table pointers. 97615Sbill * Symx (harder, but never used in loops) inverts pointers into the symbol 98615Sbill * table into indices using the symseg[] structure. 99615Sbill */ 100615Sbill #define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM)) 101615Sbill /* symx() is a function, defined below */ 102615Sbill 103615Sbill struct nlist cursym; /* current symbol */ 104615Sbill struct nlist *lastsym; /* last symbol entered */ 105615Sbill struct nlist *nextsym; /* next available symbol table entry */ 106615Sbill struct nlist *addsym; /* first sym defined during incr load */ 107615Sbill int nsym; /* pass2: number of local symbols in a.out */ 108615Sbill /* nsym + symx(nextsym) is the symbol table size during pass2 */ 109615Sbill 110615Sbill struct nlist **lookup(), **slookup(); 111650Sbill struct nlist *p_etext, *p_edata, *p_end, *entrypt; 112615Sbill 113615Sbill /* 114615Sbill * Definitions of segmentation for library member table. 115615Sbill * For each library we encounter on pass 1 we record pointers to all 116615Sbill * members which we will load on pass 2. These are recorded as offsets 117615Sbill * into the archive in the library member table. Libraries are 118615Sbill * separated in the table by the special offset value -1. 119615Sbill */ 120615Sbill off_t li_init[NROUT]; 121615Sbill struct libseg { 122615Sbill off_t *li_first; 123615Sbill int li_used; 124615Sbill int li_used2; 125615Sbill } libseg[NSEG] = { 126615Sbill li_init, 0, 0, 127615Sbill }, *clibseg = libseg; 128615Sbill 129615Sbill /* 130615Sbill * In processing each module on pass 2 we must relocate references 131615Sbill * relative to external symbols. These references are recorded 132615Sbill * in the relocation information as relative to local symbol numbers 133615Sbill * assigned to the external symbols when the module was created. 134615Sbill * Thus before relocating the module in pass 2 we create a table 135615Sbill * which maps these internal numbers to symbol table entries. 136615Sbill * A hash table is constructed, based on the local symbol table indices, 137615Sbill * for quick lookup of these symbols. 138615Sbill */ 139615Sbill #define LHSIZ 31 140615Sbill struct local { 141615Sbill int l_index; /* index to symbol in file */ 142615Sbill struct nlist *l_symbol; /* ptr to symbol table */ 143615Sbill struct local *l_link; /* hash link */ 144615Sbill } *lochash[LHSIZ], lhinit[NSYMPR]; 145615Sbill struct locseg { 146615Sbill struct local *lo_first; 147615Sbill int lo_used; 148615Sbill } locseg[NSEG] = { 149615Sbill lhinit, 0 150615Sbill }, *clocseg; 151615Sbill 152615Sbill /* 153615Sbill * Libraries are typically built with a table of contents, 154615Sbill * which is the first member of a library with special file 155615Sbill * name __.SYMDEF and contains a list of symbol names 156615Sbill * and with each symbol the offset of the library member which defines 157615Sbill * it. The loader uses this table to quickly tell which library members 158615Sbill * are (potentially) useful. The alternative, examining the symbol 159615Sbill * table of each library member, is painfully slow for large archives. 160615Sbill * 161615Sbill * See <ranlib.h> for the definition of the ranlib structure and an 162615Sbill * explanation of the __.SYMDEF file format. 163615Sbill */ 164615Sbill int tnum; /* number of symbols in table of contents */ 165615Sbill int ssiz; /* size of string table for table of contents */ 166615Sbill struct ranlib *tab; /* the table of contents (dynamically allocated) */ 167615Sbill char *tabstr; /* string table for table of contents */ 168615Sbill 169615Sbill /* 170615Sbill * We open each input file or library only once, but in pass2 we 171615Sbill * (historically) read from such a file at 2 different places at the 172615Sbill * same time. These structures are remnants from those days, 173650Sbill * and now serve only to catch ``Premature EOF''. 1746414Smckusic * In order to make I/O more efficient, we provide routines which 1756414Smckusic * work in hardware page sizes. The associated constants are defined 1766414Smckusic * as BLKSIZE, BLKSHIFT, and BLKMASK. 177615Sbill */ 1786414Smckusic #define BLKSIZE 1024 1796414Smckusic #define BLKSHIFT 10 1806414Smckusic #define BLKMASK (BLKSIZE - 1) 181615Sbill typedef struct { 182615Sbill short *fakeptr; 183615Sbill int bno; 184615Sbill int nibuf; 185615Sbill int nuser; 1866414Smckusic char buff[BLKSIZE]; 187615Sbill } PAGE; 188615Sbill 189615Sbill PAGE page[2]; 190615Sbill 191615Sbill struct { 192615Sbill short *fakeptr; 193615Sbill int bno; 194615Sbill int nibuf; 195615Sbill int nuser; 196615Sbill } fpage; 197615Sbill 198615Sbill typedef struct { 199615Sbill char *ptr; 200615Sbill int bno; 201615Sbill int nibuf; 202615Sbill long size; 203615Sbill long pos; 204615Sbill PAGE *pno; 205615Sbill } STREAM; 206615Sbill 207615Sbill STREAM text; 208615Sbill STREAM reloc; 209615Sbill 210615Sbill /* 211615Sbill * Header from the a.out and the archive it is from (if any). 212615Sbill */ 213615Sbill struct exec filhdr; 214615Sbill struct ar_hdr archdr; 215615Sbill #define OARMAG 0177545 216615Sbill 217615Sbill /* 218615Sbill * Options. 219615Sbill */ 220615Sbill int trace; 221615Sbill int xflag; /* discard local symbols */ 222615Sbill int Xflag; /* discard locals starting with 'L' */ 223615Sbill int Sflag; /* discard all except locals and globals*/ 224615Sbill int rflag; /* preserve relocation bits, don't define common */ 225615Sbill int arflag; /* original copy of rflag */ 226615Sbill int sflag; /* discard all symbols */ 227898Sbill int Mflag; /* print rudimentary load map */ 228615Sbill int nflag; /* pure procedure */ 229615Sbill int dflag; /* define common even with rflag */ 230650Sbill int zflag; /* demand paged */ 231615Sbill long hsize; /* size of hole at beginning of data to be squashed */ 232615Sbill int Aflag; /* doing incremental load */ 233650Sbill int Nflag; /* want impure a.out */ 234615Sbill int funding; /* reading fundamental file for incremental load */ 235898Sbill int yflag; /* number of symbols to be traced */ 236898Sbill char **ytab; /* the symbols */ 237615Sbill 238615Sbill /* 239615Sbill * These are the cumulative sizes, set in pass 1, which 240615Sbill * appear in the a.out header when the loader is finished. 241615Sbill */ 242615Sbill off_t tsize, dsize, bsize, trsize, drsize, ssize; 243615Sbill 244615Sbill /* 245615Sbill * Symbol relocation: c?rel is a scale factor which is 246615Sbill * added to an old relocation to convert it to new units; 247615Sbill * i.e. it is the difference between segment origins. 248650Sbill * (Thus if we are loading from a data segment which began at location 249650Sbill * 4 in a .o file into an a.out where it will be loaded starting at 250650Sbill * 1024, cdrel will be 1020.) 251615Sbill */ 252615Sbill long ctrel, cdrel, cbrel; 253615Sbill 254615Sbill /* 255650Sbill * Textbase is the start address of all text, 0 unless given by -T. 256615Sbill * Database is the base of all data, computed before and used during pass2. 257650Sbill */ 258650Sbill long textbase, database; 259650Sbill 260650Sbill /* 261615Sbill * The base addresses for the loaded text, data and bss from the 262615Sbill * current module during pass2 are given by torigin, dorigin and borigin. 263615Sbill */ 264615Sbill long torigin, dorigin, borigin; 265615Sbill 266615Sbill /* 267615Sbill * Errlev is nonzero when errors have occured. 268615Sbill * Delarg is an implicit argument to the routine delexit 269615Sbill * which is called on error. We do ``delarg = errlev'' before normal 270615Sbill * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the 271615Sbill * result file executable. 272615Sbill */ 273615Sbill int errlev; 274615Sbill int delarg = 4; 275615Sbill 276615Sbill /* 277615Sbill * The biobuf structure and associated routines are used to write 278615Sbill * into one file at several places concurrently. Calling bopen 279615Sbill * with a biobuf structure sets it up to write ``biofd'' starting 280615Sbill * at the specified offset. You can then use ``bwrite'' and/or ``bputc'' 281615Sbill * to stuff characters in the stream, much like ``fwrite'' and ``fputc''. 282615Sbill * Calling bflush drains all the buffers and MUST be done before exit. 283615Sbill */ 284615Sbill struct biobuf { 285615Sbill short b_nleft; /* Number free spaces left in b_buf */ 286615Sbill /* Initialize to be less than BUFSIZ initially, to boundary align in file */ 287615Sbill char *b_ptr; /* Next place to stuff characters */ 288615Sbill char b_buf[BUFSIZ]; /* The buffer itself */ 289615Sbill off_t b_off; /* Current file offset */ 290615Sbill struct biobuf *b_link; /* Link in chain for bflush() */ 291615Sbill } *biobufs; 292615Sbill #define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \ 293615Sbill : bflushc(b, c)) 294615Sbill int biofd; 295615Sbill off_t boffset; 296615Sbill struct biobuf *tout, *dout, *trout, *drout, *sout, *strout; 297615Sbill 298615Sbill /* 299615Sbill * Offset is the current offset in the string file. 300615Sbill * Its initial value reflects the fact that we will 301615Sbill * eventually stuff the size of the string table at the 302615Sbill * beginning of the string table (i.e. offset itself!). 303615Sbill */ 304615Sbill off_t offset = sizeof (off_t); 305615Sbill 306615Sbill int ofilfnd; /* -o given; otherwise move l.out to a.out */ 307615Sbill char *ofilename = "l.out"; 3083606Ssklower int ofilemode; /* respect umask even for unsucessful ld's */ 309615Sbill int infil; /* current input file descriptor */ 310615Sbill char *filname; /* and its name */ 311615Sbill 312615Sbill /* 313615Sbill * Base of the string table of the current module (pass1 and pass2). 314615Sbill */ 315615Sbill char *curstr; 316615Sbill 317615Sbill char get(); 318615Sbill int delexit(); 319615Sbill char *savestr(); 320615Sbill 321615Sbill main(argc, argv) 322615Sbill char **argv; 323615Sbill { 324615Sbill register int c, i; 325615Sbill int num; 326615Sbill register char *ap, **p; 327615Sbill char save; 328615Sbill 329650Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 330615Sbill signal(SIGINT, delexit); 331650Sbill signal(SIGTERM, delexit); 332650Sbill } 333615Sbill if (argc == 1) 334615Sbill exit(4); 335615Sbill p = argv+1; 336615Sbill 337650Sbill /* 338650Sbill * Scan files once to find where symbols are defined. 339650Sbill */ 340615Sbill for (c=1; c<argc; c++) { 341615Sbill if (trace) 342615Sbill printf("%s:\n", *p); 343615Sbill filname = 0; 344615Sbill ap = *p++; 345615Sbill if (*ap != '-') { 346615Sbill load1arg(ap); 347615Sbill continue; 348615Sbill } 349615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 350615Sbill 351615Sbill case 'o': 352615Sbill if (++c >= argc) 353615Sbill error(1, "-o where?"); 354615Sbill ofilename = *p++; 355615Sbill ofilfnd++; 356615Sbill continue; 357615Sbill case 'u': 358615Sbill case 'e': 359615Sbill if (++c >= argc) 360615Sbill error(1, "-u or -c: arg missing"); 361615Sbill enter(slookup(*p++)); 362615Sbill if (ap[i]=='e') 363615Sbill entrypt = lastsym; 364615Sbill continue; 365615Sbill case 'H': 366615Sbill if (++c >= argc) 367615Sbill error(1, "-H: arg missing"); 368615Sbill if (tsize!=0) 369615Sbill error(1, "-H: too late, some text already loaded"); 370615Sbill hsize = atoi(*p++); 371615Sbill continue; 372615Sbill case 'A': 373615Sbill if (++c >= argc) 374615Sbill error(1, "-A: arg missing"); 375615Sbill if (Aflag) 376615Sbill error(1, "-A: only one base file allowed"); 377615Sbill Aflag = 1; 378615Sbill nflag = 0; 379615Sbill funding = 1; 380615Sbill load1arg(*p++); 381615Sbill trsize = drsize = tsize = dsize = bsize = 0; 382615Sbill ctrel = cdrel = cbrel = 0; 383615Sbill funding = 0; 384615Sbill addsym = nextsym; 385615Sbill continue; 386615Sbill case 'D': 387615Sbill if (++c >= argc) 388615Sbill error(1, "-D: arg missing"); 389615Sbill num = htoi(*p++); 390615Sbill if (dsize > num) 391615Sbill error(1, "-D: too small"); 392615Sbill dsize = num; 393615Sbill continue; 394615Sbill case 'T': 395615Sbill if (++c >= argc) 396615Sbill error(1, "-T: arg missing"); 397615Sbill if (tsize!=0) 398615Sbill error(1, "-T: too late, some text already loaded"); 399615Sbill textbase = htoi(*p++); 400615Sbill continue; 401615Sbill case 'l': 402615Sbill save = ap[--i]; 403615Sbill ap[i]='-'; 404615Sbill load1arg(&ap[i]); 405615Sbill ap[i]=save; 406615Sbill goto next; 407898Sbill case 'M': 408898Sbill Mflag++; 409898Sbill continue; 410615Sbill case 'x': 411615Sbill xflag++; 412615Sbill continue; 413615Sbill case 'X': 414615Sbill Xflag++; 415615Sbill continue; 416615Sbill case 'S': 417615Sbill Sflag++; 418615Sbill continue; 419615Sbill case 'r': 420615Sbill rflag++; 421615Sbill arflag++; 422615Sbill continue; 423615Sbill case 's': 424615Sbill sflag++; 425615Sbill xflag++; 426615Sbill continue; 427615Sbill case 'n': 428615Sbill nflag++; 429650Sbill Nflag = zflag = 0; 430615Sbill continue; 431615Sbill case 'N': 432650Sbill Nflag++; 433650Sbill nflag = zflag = 0; 434615Sbill continue; 435615Sbill case 'd': 436615Sbill dflag++; 437615Sbill continue; 438615Sbill case 'i': 439615Sbill printf("ld: -i ignored\n"); 440615Sbill continue; 441615Sbill case 't': 442615Sbill trace++; 443615Sbill continue; 444898Sbill case 'y': 445898Sbill if (ap[i+1] == 0) 446898Sbill error(1, "-y: symbol name missing"); 447898Sbill if (yflag == 0) { 448898Sbill ytab = (char **)calloc(argc, sizeof (char **)); 449898Sbill if (ytab == 0) 450898Sbill error(1, "ran out of memory (-y)"); 451898Sbill } 452898Sbill ytab[yflag++] = &ap[i+1]; 453898Sbill goto next; 454615Sbill case 'z': 455615Sbill zflag++; 456650Sbill Nflag = nflag = 0; 457615Sbill continue; 458615Sbill default: 459615Sbill filname = savestr("-x"); /* kludge */ 460615Sbill filname[1] = ap[i]; /* kludge */ 461615Sbill archdr.ar_name[0] = 0; /* kludge */ 462615Sbill error(1, "bad flag"); 463615Sbill } 464615Sbill next: 465615Sbill ; 466615Sbill } 467650Sbill if (rflag == 0 && Nflag == 0 && nflag == 0) 468650Sbill zflag++; 469615Sbill endload(argc, argv); 470615Sbill exit(0); 471615Sbill } 472615Sbill 473615Sbill /* 474615Sbill * Convert a ascii string which is a hex number. 475615Sbill * Used by -T and -D options. 476615Sbill */ 477615Sbill htoi(p) 478615Sbill register char *p; 479615Sbill { 480615Sbill register int c, n; 481615Sbill 482615Sbill n = 0; 483615Sbill while (c = *p++) { 484615Sbill n <<= 4; 485615Sbill if (isdigit(c)) 486615Sbill n += c - '0'; 487615Sbill else if (c >= 'a' && c <= 'f') 488615Sbill n += 10 + (c - 'a'); 489615Sbill else if (c >= 'A' && c <= 'F') 490615Sbill n += 10 + (c - 'A'); 491615Sbill else 492615Sbill error(1, "badly formed hex number"); 493615Sbill } 494615Sbill return (n); 495615Sbill } 496615Sbill 497615Sbill delexit() 498615Sbill { 499*9332Smckusick struct stat stbuf; 500*9332Smckusick long size; 501*9332Smckusick char c = 0; 502615Sbill 503615Sbill bflush(); 504615Sbill unlink("l.out"); 505615Sbill if (delarg==0 && Aflag==0) 5063606Ssklower chmod(ofilename, ofilemode); 507*9332Smckusick /* 508*9332Smckusick * We have to insure that the last block of the data segment 509*9332Smckusick * is allocated a full BLKSIZE block. If the underlying 510*9332Smckusick * file system allocates frags that are smaller than BLKSIZE, 511*9332Smckusick * a full zero filled BLKSIZE block needs to be allocated so 512*9332Smckusick * that when it is demand paged, the paged in block will be 513*9332Smckusick * appropriately filled with zeros. 514*9332Smckusick */ 515*9332Smckusick fstat(biofd, &stbuf); 516*9332Smckusick size = round(stbuf.st_size, BLKSIZE); 517*9332Smckusick if (size > stbuf.st_size) { 518*9332Smckusick lseek(biofd, size - 1, 0); 519*9332Smckusick write(biofd, &c, 1); 520*9332Smckusick } 521615Sbill exit (delarg); 522615Sbill } 523615Sbill 524615Sbill endload(argc, argv) 525615Sbill int argc; 526615Sbill char **argv; 527615Sbill { 528615Sbill register int c, i; 529615Sbill long dnum; 530615Sbill register char *ap, **p; 531615Sbill 532615Sbill clibseg = libseg; 533615Sbill filname = 0; 534615Sbill middle(); 535615Sbill setupout(); 536615Sbill p = argv+1; 537615Sbill for (c=1; c<argc; c++) { 538615Sbill ap = *p++; 539615Sbill if (trace) 540615Sbill printf("%s:\n", ap); 541615Sbill if (*ap != '-') { 542615Sbill load2arg(ap); 543615Sbill continue; 544615Sbill } 545615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 546615Sbill 547615Sbill case 'D': 548615Sbill dnum = htoi(*p); 549615Sbill if (dorigin < dnum) 550615Sbill while (dorigin < dnum) 551615Sbill bputc(0, dout), dorigin++; 552615Sbill /* fall into ... */ 553615Sbill case 'T': 554615Sbill case 'u': 555615Sbill case 'e': 556615Sbill case 'o': 557615Sbill case 'H': 558615Sbill ++c; 559615Sbill ++p; 560615Sbill /* fall into ... */ 561615Sbill default: 562615Sbill continue; 563615Sbill case 'A': 564615Sbill funding = 1; 565615Sbill load2arg(*p++); 566615Sbill funding = 0; 567615Sbill c++; 568615Sbill continue; 569898Sbill case 'y': 570898Sbill goto next; 571615Sbill case 'l': 572615Sbill ap[--i]='-'; 573615Sbill load2arg(&ap[i]); 574615Sbill goto next; 575615Sbill } 576615Sbill next: 577615Sbill ; 578615Sbill } 579615Sbill finishout(); 580615Sbill } 581615Sbill 582615Sbill /* 583615Sbill * Scan file to find defined symbols. 584615Sbill */ 585615Sbill load1arg(cp) 586615Sbill register char *cp; 587615Sbill { 588615Sbill register struct ranlib *tp; 589615Sbill off_t nloc; 590898Sbill int kind; 591615Sbill 592898Sbill kind = getfile(cp); 593898Sbill if (Mflag) 594898Sbill printf("%s\n", filname); 595898Sbill switch (kind) { 596615Sbill 597615Sbill /* 598615Sbill * Plain file. 599615Sbill */ 600615Sbill case 0: 601615Sbill load1(0, 0L); 602615Sbill break; 603615Sbill 604615Sbill /* 605615Sbill * Archive without table of contents. 606615Sbill * (Slowly) process each member. 607615Sbill */ 608615Sbill case 1: 609898Sbill error(-1, 610898Sbill "warning: archive has no table of contents; add one using ranlib(1)"); 611615Sbill nloc = SARMAG; 612615Sbill while (step(nloc)) 613615Sbill nloc += sizeof(archdr) + 614615Sbill round(atol(archdr.ar_size), sizeof (short)); 615615Sbill break; 616615Sbill 617615Sbill /* 618615Sbill * Archive with table of contents. 619615Sbill * Read the table of contents and its associated string table. 620615Sbill * Pass through the library resolving symbols until nothing changes 621615Sbill * for an entire pass (i.e. you can get away with backward references 622615Sbill * when there is a table of contents!) 623615Sbill */ 624615Sbill case 2: 625615Sbill nloc = SARMAG + sizeof (archdr); 626615Sbill dseek(&text, nloc, sizeof (tnum)); 627615Sbill mget((char *)&tnum, sizeof (tnum), &text); 628615Sbill nloc += sizeof (tnum); 629615Sbill tab = (struct ranlib *)malloc(tnum); 630615Sbill if (tab == 0) 631615Sbill error(1, "ran out of memory (toc)"); 632615Sbill dseek(&text, nloc, tnum); 633615Sbill mget((char *)tab, tnum, &text); 634615Sbill nloc += tnum; 635615Sbill tnum /= sizeof (struct ranlib); 636615Sbill dseek(&text, nloc, sizeof (ssiz)); 637615Sbill mget((char *)&ssiz, sizeof (ssiz), &text); 638615Sbill nloc += sizeof (ssiz); 639615Sbill tabstr = (char *)malloc(ssiz); 640615Sbill if (tabstr == 0) 641615Sbill error(1, "ran out of memory (tocstr)"); 642615Sbill dseek(&text, nloc, ssiz); 643615Sbill mget((char *)tabstr, ssiz, &text); 644615Sbill for (tp = &tab[tnum]; --tp >= tab;) { 645615Sbill if (tp->ran_un.ran_strx < 0 || 646615Sbill tp->ran_un.ran_strx >= ssiz) 647615Sbill error(1, "mangled archive table of contents"); 648615Sbill tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx; 649615Sbill } 650615Sbill while (ldrand()) 651615Sbill continue; 652615Sbill cfree((char *)tab); 653615Sbill cfree(tabstr); 654615Sbill nextlibp(-1); 655615Sbill break; 656615Sbill 657615Sbill /* 658615Sbill * Table of contents is out of date, so search 659615Sbill * as a normal library (but skip the __.SYMDEF file). 660615Sbill */ 661615Sbill case 3: 662898Sbill error(-1, 663898Sbill "warning: table of contents for archive is out of date; rerun ranlib(1)"); 664615Sbill nloc = SARMAG; 665615Sbill do 666615Sbill nloc += sizeof(archdr) + 667615Sbill round(atol(archdr.ar_size), sizeof(short)); 668615Sbill while (step(nloc)); 669615Sbill break; 670615Sbill } 671615Sbill close(infil); 672615Sbill } 673615Sbill 674615Sbill /* 675615Sbill * Advance to the next archive member, which 676615Sbill * is at offset nloc in the archive. If the member 677615Sbill * is useful, record its location in the liblist structure 678615Sbill * for use in pass2. Mark the end of the archive in libilst with a -1. 679615Sbill */ 680615Sbill step(nloc) 681615Sbill off_t nloc; 682615Sbill { 683615Sbill 684615Sbill dseek(&text, nloc, (long) sizeof archdr); 685615Sbill if (text.size <= 0) { 686615Sbill nextlibp(-1); 687615Sbill return (0); 688615Sbill } 689615Sbill getarhdr(); 690615Sbill if (load1(1, nloc + (sizeof archdr))) 691615Sbill nextlibp(nloc); 692615Sbill return (1); 693615Sbill } 694615Sbill 695615Sbill /* 696615Sbill * Record the location of a useful archive member. 697615Sbill * Recording -1 marks the end of files from an archive. 698615Sbill * The liblist data structure is dynamically extended here. 699615Sbill */ 700615Sbill nextlibp(val) 701615Sbill off_t val; 702615Sbill { 703615Sbill 704615Sbill if (clibseg->li_used == NROUT) { 705615Sbill if (++clibseg == &libseg[NSEG]) 706615Sbill error(1, "too many files loaded from libraries"); 707615Sbill clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t)); 708615Sbill if (clibseg->li_first == 0) 709615Sbill error(1, "ran out of memory (nextlibp)"); 710615Sbill } 711615Sbill clibseg->li_first[clibseg->li_used++] = val; 712898Sbill if (val != -1 && Mflag) 713898Sbill printf("\t%s\n", archdr.ar_name); 714615Sbill } 715615Sbill 716615Sbill /* 717615Sbill * One pass over an archive with a table of contents. 718615Sbill * Remember the number of symbols currently defined, 719615Sbill * then call step on members which look promising (i.e. 720615Sbill * that define a symbol which is currently externally undefined). 721615Sbill * Indicate to our caller whether this process netted any more symbols. 722615Sbill */ 723615Sbill ldrand() 724615Sbill { 725615Sbill register struct nlist *sp, **hp; 726615Sbill register struct ranlib *tp, *tplast; 727615Sbill off_t loc; 728615Sbill int nsymt = symx(nextsym); 729615Sbill 730615Sbill tplast = &tab[tnum-1]; 731615Sbill for (tp = tab; tp <= tplast; tp++) { 732615Sbill if ((hp = slookup(tp->ran_un.ran_name)) == 0) 733615Sbill continue; 734615Sbill sp = *hp; 735615Sbill if (sp->n_type != N_EXT+N_UNDF) 736615Sbill continue; 737615Sbill step(tp->ran_off); 738615Sbill loc = tp->ran_off; 739615Sbill while (tp < tplast && (tp+1)->ran_off == loc) 740615Sbill tp++; 741615Sbill } 742615Sbill return (symx(nextsym) != nsymt); 743615Sbill } 744615Sbill 745615Sbill /* 746615Sbill * Examine a single file or archive member on pass 1. 747615Sbill */ 748615Sbill load1(libflg, loc) 749615Sbill off_t loc; 750615Sbill { 751615Sbill register struct nlist *sp; 752615Sbill struct nlist *savnext; 753615Sbill int ndef, nlocal, type, size, nsymt; 754615Sbill register int i; 755615Sbill off_t maxoff; 756615Sbill struct stat stb; 757615Sbill 758615Sbill readhdr(loc); 759615Sbill if (filhdr.a_syms == 0) { 760615Sbill if (filhdr.a_text+filhdr.a_data == 0) 761615Sbill return (0); 762615Sbill error(1, "no namelist"); 763615Sbill } 764615Sbill if (libflg) 765615Sbill maxoff = atol(archdr.ar_size); 766615Sbill else { 767615Sbill fstat(infil, &stb); 768615Sbill maxoff = stb.st_size; 769615Sbill } 770615Sbill if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff) 771615Sbill error(1, "too small (old format .o?)"); 772615Sbill ctrel = tsize; cdrel += dsize; cbrel += bsize; 773615Sbill ndef = 0; 774615Sbill nlocal = sizeof(cursym); 775615Sbill savnext = nextsym; 776615Sbill loc += N_SYMOFF(filhdr); 777615Sbill dseek(&text, loc, filhdr.a_syms); 778615Sbill dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t)); 779615Sbill mget(&size, sizeof (size), &reloc); 780615Sbill dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t)); 781615Sbill curstr = (char *)malloc(size); 782615Sbill if (curstr == NULL) 783615Sbill error(1, "no space for string table"); 784615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc); 785615Sbill while (text.size > 0) { 786615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 787615Sbill if (cursym.n_un.n_strx) { 788615Sbill if (cursym.n_un.n_strx<sizeof(size) || 789615Sbill cursym.n_un.n_strx>=size) 790615Sbill error(1, "bad string table index (pass 1)"); 791615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 792615Sbill } 793615Sbill type = cursym.n_type; 794615Sbill if ((type&N_EXT)==0) { 795615Sbill if (Xflag==0 || cursym.n_un.n_name[0]!='L' || 796615Sbill type & N_STAB) 797615Sbill nlocal += sizeof cursym; 798615Sbill continue; 799615Sbill } 800615Sbill symreloc(); 801615Sbill if (enter(lookup())) 802615Sbill continue; 803615Sbill if ((sp = lastsym)->n_type != N_EXT+N_UNDF) 804615Sbill continue; 805615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 806615Sbill if (cursym.n_value > sp->n_value) 807615Sbill sp->n_value = cursym.n_value; 808615Sbill continue; 809615Sbill } 810615Sbill if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT) 811615Sbill continue; 812615Sbill ndef++; 813615Sbill sp->n_type = cursym.n_type; 814615Sbill sp->n_value = cursym.n_value; 815615Sbill } 816615Sbill if (libflg==0 || ndef) { 817615Sbill tsize += filhdr.a_text; 818615Sbill dsize += round(filhdr.a_data, sizeof (long)); 819615Sbill bsize += round(filhdr.a_bss, sizeof (long)); 820615Sbill ssize += nlocal; 821615Sbill trsize += filhdr.a_trsize; 822615Sbill drsize += filhdr.a_drsize; 823615Sbill if (funding) 824615Sbill textbase = (*slookup("_end"))->n_value; 825615Sbill nsymt = symx(nextsym); 826615Sbill for (i = symx(savnext); i < nsymt; i++) { 827615Sbill sp = xsym(i); 828615Sbill sp->n_un.n_name = savestr(sp->n_un.n_name); 829615Sbill } 830615Sbill free(curstr); 831615Sbill return (1); 832615Sbill } 833615Sbill /* 834615Sbill * No symbols defined by this library member. 835615Sbill * Rip out the hash table entries and reset the symbol table. 836615Sbill */ 837615Sbill symfree(savnext); 838615Sbill free(curstr); 839615Sbill return(0); 840615Sbill } 841615Sbill 842615Sbill middle() 843615Sbill { 844615Sbill register struct nlist *sp; 845615Sbill long csize, t, corigin, ocsize; 846615Sbill int nund, rnd; 847615Sbill char s; 848615Sbill register int i; 849615Sbill int nsymt; 850615Sbill 851615Sbill torigin = 0; 852615Sbill dorigin = 0; 853615Sbill borigin = 0; 854615Sbill 855615Sbill p_etext = *slookup("_etext"); 856615Sbill p_edata = *slookup("_edata"); 857615Sbill p_end = *slookup("_end"); 858615Sbill /* 859615Sbill * If there are any undefined symbols, save the relocation bits. 860615Sbill */ 861615Sbill nsymt = symx(nextsym); 862615Sbill if (rflag==0) { 863615Sbill for (i = 0; i < nsymt; i++) { 864615Sbill sp = xsym(i); 865615Sbill if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 && 866650Sbill sp!=p_end && sp!=p_edata && sp!=p_etext) { 867615Sbill rflag++; 868615Sbill dflag = 0; 869615Sbill break; 870615Sbill } 871615Sbill } 872615Sbill } 873615Sbill if (rflag) 874615Sbill sflag = zflag = 0; 875615Sbill /* 876615Sbill * Assign common locations. 877615Sbill */ 878615Sbill csize = 0; 879615Sbill if (!Aflag) 880615Sbill addsym = symseg[0].sy_first; 881615Sbill database = round(tsize+textbase, 882615Sbill (nflag||zflag? PAGSIZ : sizeof (long))); 883615Sbill database += hsize; 884615Sbill if (dflag || rflag==0) { 885615Sbill ldrsym(p_etext, tsize, N_EXT+N_TEXT); 886615Sbill ldrsym(p_edata, dsize, N_EXT+N_DATA); 887615Sbill ldrsym(p_end, bsize, N_EXT+N_BSS); 888615Sbill for (i = symx(addsym); i < nsymt; i++) { 889615Sbill sp = xsym(i); 890615Sbill if ((s=sp->n_type)==N_EXT+N_UNDF && 891615Sbill (t = sp->n_value)!=0) { 892615Sbill if (t >= sizeof (double)) 893615Sbill rnd = sizeof (double); 894615Sbill else if (t >= sizeof (long)) 895615Sbill rnd = sizeof (long); 896615Sbill else 897615Sbill rnd = sizeof (short); 898615Sbill csize = round(csize, rnd); 899615Sbill sp->n_value = csize; 900615Sbill sp->n_type = N_EXT+N_COMM; 901615Sbill ocsize = csize; 902615Sbill csize += t; 903615Sbill } 904615Sbill if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) { 905615Sbill sp->n_value = ocsize; 906615Sbill sp->n_type = (s&N_STAB) | (N_EXT+N_COMM); 907615Sbill } 908615Sbill } 909615Sbill } 910615Sbill /* 911615Sbill * Now set symbols to their final value 912615Sbill */ 913615Sbill csize = round(csize, sizeof (long)); 914615Sbill torigin = textbase; 915615Sbill dorigin = database; 916615Sbill corigin = dorigin + dsize; 917615Sbill borigin = corigin + csize; 918615Sbill nund = 0; 919615Sbill nsymt = symx(nextsym); 920615Sbill for (i = symx(addsym); i<nsymt; i++) { 921615Sbill sp = xsym(i); 922615Sbill switch (sp->n_type & (N_TYPE+N_EXT)) { 923615Sbill 924615Sbill case N_EXT+N_UNDF: 9252369Skre if (arflag == 0) 9262369Skre errlev |= 01; 927615Sbill if ((arflag==0 || dflag) && sp->n_value==0) { 928650Sbill if (sp==p_end || sp==p_etext || sp==p_edata) 929650Sbill continue; 930615Sbill if (nund==0) 931615Sbill printf("Undefined:\n"); 932615Sbill nund++; 933615Sbill printf("%s\n", sp->n_un.n_name); 934615Sbill } 935615Sbill continue; 936615Sbill case N_EXT+N_ABS: 937615Sbill default: 938615Sbill continue; 939615Sbill case N_EXT+N_TEXT: 940615Sbill sp->n_value += torigin; 941615Sbill continue; 942615Sbill case N_EXT+N_DATA: 943615Sbill sp->n_value += dorigin; 944615Sbill continue; 945615Sbill case N_EXT+N_BSS: 946615Sbill sp->n_value += borigin; 947615Sbill continue; 948615Sbill case N_EXT+N_COMM: 949615Sbill sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS); 950615Sbill sp->n_value += corigin; 951615Sbill continue; 952615Sbill } 953615Sbill } 954615Sbill if (sflag || xflag) 955615Sbill ssize = 0; 956615Sbill bsize += csize; 957615Sbill nsym = ssize / (sizeof cursym); 958615Sbill if (Aflag) { 959615Sbill fixspec(p_etext,torigin); 960615Sbill fixspec(p_edata,dorigin); 961615Sbill fixspec(p_end,borigin); 962615Sbill } 963615Sbill } 964615Sbill 965615Sbill fixspec(sym,offset) 966615Sbill struct nlist *sym; 967615Sbill long offset; 968615Sbill { 969615Sbill 970615Sbill if(symx(sym) < symx(addsym) && sym!=0) 971615Sbill sym->n_value += offset; 972615Sbill } 973615Sbill 974615Sbill ldrsym(sp, val, type) 975615Sbill register struct nlist *sp; 976615Sbill long val; 977615Sbill { 978615Sbill 979615Sbill if (sp == 0) 980615Sbill return; 981615Sbill if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) { 982615Sbill printf("%s: ", sp->n_un.n_name); 983615Sbill error(0, "user attempt to redfine loader-defined symbol"); 984615Sbill return; 985615Sbill } 986615Sbill sp->n_type = type; 987615Sbill sp->n_value = val; 988615Sbill } 989615Sbill 990615Sbill off_t wroff; 991615Sbill struct biobuf toutb; 992615Sbill 993615Sbill setupout() 994615Sbill { 995615Sbill int bss; 996898Sbill extern char *sys_errlist[]; 997898Sbill extern int errno; 998615Sbill 9993606Ssklower ofilemode = 0777 & ~umask(0); 10003606Ssklower biofd = creat(ofilename, 0666 & ofilemode); 1001898Sbill if (biofd < 0) { 1002898Sbill filname = ofilename; /* kludge */ 1003898Sbill archdr.ar_name[0] = 0; /* kludge */ 1004898Sbill error(1, sys_errlist[errno]); /* kludge */ 10053606Ssklower } else { 10063606Ssklower struct stat mybuf; /* kls kludge */ 10073606Ssklower fstat(biofd, &mybuf); /* suppose file exists, wrong*/ 10083606Ssklower if(mybuf.st_mode & 0111) { /* mode, ld fails? */ 10093606Ssklower chmod(ofilename, mybuf.st_mode & 0666); 10103606Ssklower ofilemode = mybuf.st_mode; 10113606Ssklower } 1012898Sbill } 1013615Sbill tout = &toutb; 1014615Sbill bopen(tout, 0); 1015615Sbill filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC); 1016615Sbill filhdr.a_text = nflag ? tsize : 1017615Sbill round(tsize, zflag ? PAGSIZ : sizeof (long)); 1018615Sbill filhdr.a_data = zflag ? round(dsize, PAGSIZ) : dsize; 1019615Sbill bss = bsize - (filhdr.a_data - dsize); 1020615Sbill if (bss < 0) 1021615Sbill bss = 0; 1022615Sbill filhdr.a_bss = bss; 1023615Sbill filhdr.a_trsize = trsize; 1024615Sbill filhdr.a_drsize = drsize; 1025615Sbill filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym)); 1026615Sbill if (entrypt) { 1027615Sbill if (entrypt->n_type!=N_EXT+N_TEXT) 1028615Sbill error(0, "entry point not in text"); 1029615Sbill else 1030615Sbill filhdr.a_entry = entrypt->n_value; 1031615Sbill } else 1032615Sbill filhdr.a_entry = 0; 1033615Sbill filhdr.a_trsize = (rflag ? trsize:0); 1034615Sbill filhdr.a_drsize = (rflag ? drsize:0); 1035615Sbill bwrite((char *)&filhdr, sizeof (filhdr), tout); 1036615Sbill if (zflag) { 1037615Sbill bflush1(tout); 1038615Sbill biobufs = 0; 1039615Sbill bopen(tout, PAGSIZ); 1040615Sbill } 1041615Sbill wroff = N_TXTOFF(filhdr) + filhdr.a_text; 1042615Sbill outb(&dout, filhdr.a_data); 1043615Sbill if (rflag) { 1044615Sbill outb(&trout, filhdr.a_trsize); 1045615Sbill outb(&drout, filhdr.a_drsize); 1046615Sbill } 1047615Sbill if (sflag==0 || xflag==0) { 1048615Sbill outb(&sout, filhdr.a_syms); 1049615Sbill wroff += sizeof (offset); 1050615Sbill outb(&strout, 0); 1051615Sbill } 1052615Sbill } 1053615Sbill 1054615Sbill outb(bp, inc) 1055615Sbill register struct biobuf **bp; 1056615Sbill { 1057615Sbill 1058615Sbill *bp = (struct biobuf *)malloc(sizeof (struct biobuf)); 1059615Sbill if (*bp == 0) 1060615Sbill error(1, "ran out of memory (outb)"); 1061615Sbill bopen(*bp, wroff); 1062615Sbill wroff += inc; 1063615Sbill } 1064615Sbill 1065615Sbill load2arg(acp) 1066615Sbill char *acp; 1067615Sbill { 1068615Sbill register char *cp; 1069615Sbill off_t loc; 1070615Sbill 1071615Sbill cp = acp; 1072615Sbill if (getfile(cp) == 0) { 1073615Sbill while (*cp) 1074615Sbill cp++; 1075615Sbill while (cp >= acp && *--cp != '/'); 1076615Sbill mkfsym(++cp); 1077615Sbill load2(0L); 1078615Sbill } else { /* scan archive members referenced */ 1079615Sbill for (;;) { 1080615Sbill if (clibseg->li_used2 == clibseg->li_used) { 1081615Sbill if (clibseg->li_used < NROUT) 1082615Sbill error(1, "libseg botch"); 1083615Sbill clibseg++; 1084615Sbill } 1085615Sbill loc = clibseg->li_first[clibseg->li_used2++]; 1086615Sbill if (loc == -1) 1087615Sbill break; 1088615Sbill dseek(&text, loc, (long)sizeof(archdr)); 1089615Sbill getarhdr(); 1090615Sbill mkfsym(archdr.ar_name); 1091615Sbill load2(loc + (long)sizeof(archdr)); 1092615Sbill } 1093615Sbill } 1094615Sbill close(infil); 1095615Sbill } 1096615Sbill 1097615Sbill load2(loc) 1098615Sbill long loc; 1099615Sbill { 1100615Sbill int size; 1101615Sbill register struct nlist *sp; 1102615Sbill register struct local *lp; 1103615Sbill register int symno, i; 1104615Sbill int type; 1105615Sbill 1106615Sbill readhdr(loc); 1107650Sbill if (!funding) { 1108615Sbill ctrel = torigin; 1109615Sbill cdrel += dorigin; 1110615Sbill cbrel += borigin; 1111615Sbill } 1112615Sbill /* 1113615Sbill * Reread the symbol table, recording the numbering 1114615Sbill * of symbols for fixing external references. 1115615Sbill */ 1116615Sbill for (i = 0; i < LHSIZ; i++) 1117615Sbill lochash[i] = 0; 1118615Sbill clocseg = locseg; 1119615Sbill clocseg->lo_used = 0; 1120615Sbill symno = -1; 1121615Sbill loc += N_TXTOFF(filhdr); 1122615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1123615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t)); 1124615Sbill mget(&size, sizeof(size), &text); 1125615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1126615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t), 1127615Sbill size - sizeof(off_t)); 1128615Sbill curstr = (char *)malloc(size); 1129615Sbill if (curstr == NULL) 1130615Sbill error(1, "out of space reading string table (pass 2)"); 1131615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &text); 1132615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1133615Sbill filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms); 1134615Sbill while (text.size > 0) { 1135615Sbill symno++; 1136615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 1137615Sbill if (cursym.n_un.n_strx) { 1138615Sbill if (cursym.n_un.n_strx<sizeof(size) || 1139615Sbill cursym.n_un.n_strx>=size) 1140615Sbill error(1, "bad string table index (pass 2)"); 1141615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 1142615Sbill } 1143615Sbill /* inline expansion of symreloc() */ 1144615Sbill switch (cursym.n_type & 017) { 1145615Sbill 1146615Sbill case N_TEXT: 1147615Sbill case N_EXT+N_TEXT: 1148615Sbill cursym.n_value += ctrel; 1149615Sbill break; 1150615Sbill case N_DATA: 1151615Sbill case N_EXT+N_DATA: 1152615Sbill cursym.n_value += cdrel; 1153615Sbill break; 1154615Sbill case N_BSS: 1155615Sbill case N_EXT+N_BSS: 1156615Sbill cursym.n_value += cbrel; 1157615Sbill break; 1158615Sbill case N_EXT+N_UNDF: 1159615Sbill break; 1160615Sbill default: 1161615Sbill if (cursym.n_type&N_EXT) 1162615Sbill cursym.n_type = N_EXT+N_ABS; 1163615Sbill } 1164615Sbill /* end inline expansion of symreloc() */ 1165615Sbill type = cursym.n_type; 1166898Sbill if (yflag && cursym.n_un.n_name) 1167898Sbill for (i = 0; i < yflag; i++) 1168898Sbill /* fast check for 2d character! */ 1169898Sbill if (ytab[i][1] == cursym.n_un.n_name[1] && 1170898Sbill !strcmp(ytab[i], cursym.n_un.n_name)) { 1171898Sbill tracesym(); 1172898Sbill break; 1173898Sbill } 1174615Sbill if ((type&N_EXT) == 0) { 1175615Sbill if (!sflag&&!xflag&& 1176615Sbill (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB)) 1177615Sbill symwrite(&cursym, sout); 1178615Sbill continue; 1179615Sbill } 1180615Sbill if (funding) 1181615Sbill continue; 1182615Sbill if ((sp = *lookup()) == 0) 1183615Sbill error(1, "internal error: symbol not found"); 1184615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 1185615Sbill if (clocseg->lo_used == NSYMPR) { 1186615Sbill if (++clocseg == &locseg[NSEG]) 1187615Sbill error(1, "local symbol overflow"); 1188615Sbill clocseg->lo_used = 0; 1189615Sbill } 1190615Sbill if (clocseg->lo_first == 0) { 1191615Sbill clocseg->lo_first = (struct local *) 1192615Sbill malloc(NSYMPR * sizeof (struct local)); 1193615Sbill if (clocseg->lo_first == 0) 1194615Sbill error(1, "out of memory (clocseg)"); 1195615Sbill } 1196615Sbill lp = &clocseg->lo_first[clocseg->lo_used++]; 1197615Sbill lp->l_index = symno; 1198615Sbill lp->l_symbol = sp; 1199615Sbill lp->l_link = lochash[symno % LHSIZ]; 1200615Sbill lochash[symno % LHSIZ] = lp; 1201615Sbill continue; 1202615Sbill } 1203615Sbill if (cursym.n_type & N_STAB) 1204615Sbill continue; 1205615Sbill if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) { 1206615Sbill printf("%s: ", cursym.n_un.n_name); 1207615Sbill error(0, "multiply defined"); 1208615Sbill } 1209615Sbill } 1210615Sbill if (funding) 1211615Sbill return; 1212615Sbill dseek(&text, loc, filhdr.a_text); 1213615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize); 1214650Sbill load2td(ctrel, torigin - textbase, tout, trout); 1215615Sbill dseek(&text, loc+filhdr.a_text, filhdr.a_data); 1216615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, 1217615Sbill filhdr.a_drsize); 1218650Sbill load2td(cdrel, dorigin - database, dout, drout); 1219615Sbill while (filhdr.a_data & (sizeof(long)-1)) { 1220615Sbill bputc(0, dout); 1221615Sbill filhdr.a_data++; 1222615Sbill } 1223615Sbill torigin += filhdr.a_text; 12241752Sbill dorigin += round(filhdr.a_data, sizeof (long)); 12251752Sbill borigin += round(filhdr.a_bss, sizeof (long)); 1226615Sbill free(curstr); 1227615Sbill } 1228615Sbill 1229898Sbill struct tynames { 1230898Sbill int ty_value; 1231898Sbill char *ty_name; 1232898Sbill } tynames[] = { 1233898Sbill N_UNDF, "undefined", 1234898Sbill N_ABS, "absolute", 1235898Sbill N_TEXT, "text", 1236898Sbill N_DATA, "data", 1237898Sbill N_BSS, "bss", 1238898Sbill N_COMM, "common", 1239898Sbill 0, 0, 1240898Sbill }; 1241898Sbill 1242898Sbill tracesym() 1243898Sbill { 1244898Sbill register struct tynames *tp; 1245898Sbill 1246898Sbill if (cursym.n_type & N_STAB) 1247898Sbill return; 1248898Sbill printf("%s", filname); 1249898Sbill if (archdr.ar_name[0]) 1250898Sbill printf("(%s)", archdr.ar_name); 1251898Sbill printf(": "); 1252898Sbill if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) { 1253898Sbill printf("definition of common %s size %d\n", 1254898Sbill cursym.n_un.n_name, cursym.n_value); 1255898Sbill return; 1256898Sbill } 1257898Sbill for (tp = tynames; tp->ty_name; tp++) 1258898Sbill if (tp->ty_value == (cursym.n_type&N_TYPE)) 1259898Sbill break; 1260898Sbill printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to"); 1261898Sbill if (cursym.n_type&N_EXT) 1262898Sbill printf(" external"); 1263898Sbill if (tp->ty_name) 1264898Sbill printf(" %s", tp->ty_name); 1265898Sbill printf(" %s\n", cursym.n_un.n_name); 1266898Sbill } 1267898Sbill 1268650Sbill /* 1269650Sbill * This routine relocates the single text or data segment argument. 1270650Sbill * Offsets from external symbols are resolved by adding the value 1271650Sbill * of the external symbols. Non-external reference are updated to account 1272650Sbill * for the relative motion of the segments (ctrel, cdrel, ...). If 1273650Sbill * a relocation was pc-relative, then we update it to reflect the 1274650Sbill * change in the positioning of the segments by adding the displacement 1275650Sbill * of the referenced segment and subtracting the displacement of the 1276650Sbill * current segment (creloc). 1277650Sbill * 1278650Sbill * If we are saving the relocation information, then we increase 1279650Sbill * each relocation datum address by our base position in the new segment. 1280650Sbill */ 1281650Sbill load2td(creloc, position, b1, b2) 1282650Sbill long creloc, offset; 1283615Sbill struct biobuf *b1, *b2; 1284615Sbill { 1285615Sbill register struct nlist *sp; 1286615Sbill register struct local *lp; 1287615Sbill long tw; 1288615Sbill register struct relocation_info *rp, *rpend; 1289615Sbill struct relocation_info *relp; 1290615Sbill char *codep; 1291615Sbill register char *cp; 1292615Sbill int relsz, codesz; 1293615Sbill 1294615Sbill relsz = reloc.size; 1295615Sbill relp = (struct relocation_info *)malloc(relsz); 1296615Sbill codesz = text.size; 1297615Sbill codep = (char *)malloc(codesz); 1298615Sbill if (relp == 0 || codep == 0) 1299615Sbill error(1, "out of memory (load2td)"); 1300615Sbill mget((char *)relp, relsz, &reloc); 1301615Sbill rpend = &relp[relsz / sizeof (struct relocation_info)]; 1302615Sbill mget(codep, codesz, &text); 1303615Sbill for (rp = relp; rp < rpend; rp++) { 1304615Sbill cp = codep + rp->r_address; 1305650Sbill /* 1306650Sbill * Pick up previous value at location to be relocated. 1307650Sbill */ 1308615Sbill switch (rp->r_length) { 1309615Sbill 1310615Sbill case 0: /* byte */ 1311615Sbill tw = *cp; 1312615Sbill break; 1313615Sbill 1314615Sbill case 1: /* word */ 1315615Sbill tw = *(short *)cp; 1316615Sbill break; 1317615Sbill 1318615Sbill case 2: /* long */ 1319615Sbill tw = *(long *)cp; 1320615Sbill break; 1321615Sbill 1322615Sbill default: 1323615Sbill error(1, "load2td botch: bad length"); 1324615Sbill } 1325650Sbill /* 1326650Sbill * If relative to an external which is defined, 1327650Sbill * resolve to a simpler kind of reference in the 1328650Sbill * result file. If the external is undefined, just 1329650Sbill * convert the symbol number to the number of the 1330650Sbill * symbol in the result file and leave it undefined. 1331650Sbill */ 1332615Sbill if (rp->r_extern) { 1333650Sbill /* 1334650Sbill * Search the hash table which maps local 1335650Sbill * symbol numbers to symbol tables entries 1336650Sbill * in the new a.out file. 1337650Sbill */ 1338615Sbill lp = lochash[rp->r_symbolnum % LHSIZ]; 1339615Sbill while (lp->l_index != rp->r_symbolnum) { 1340615Sbill lp = lp->l_link; 1341615Sbill if (lp == 0) 1342615Sbill error(1, "local symbol botch"); 1343615Sbill } 1344615Sbill sp = lp->l_symbol; 1345615Sbill if (sp->n_type == N_EXT+N_UNDF) 1346615Sbill rp->r_symbolnum = nsym+symx(sp); 1347615Sbill else { 1348615Sbill rp->r_symbolnum = sp->n_type & N_TYPE; 1349615Sbill tw += sp->n_value; 1350615Sbill rp->r_extern = 0; 1351615Sbill } 1352615Sbill } else switch (rp->r_symbolnum & N_TYPE) { 1353650Sbill /* 1354650Sbill * Relocation is relative to the loaded position 1355650Sbill * of another segment. Update by the change in position 1356650Sbill * of that segment. 1357650Sbill */ 1358615Sbill case N_TEXT: 1359615Sbill tw += ctrel; 1360615Sbill break; 1361615Sbill case N_DATA: 1362615Sbill tw += cdrel; 1363615Sbill break; 1364615Sbill case N_BSS: 1365615Sbill tw += cbrel; 1366615Sbill break; 1367615Sbill case N_ABS: 1368615Sbill break; 1369615Sbill default: 1370615Sbill error(1, "relocation format botch (symbol type))"); 1371615Sbill } 1372650Sbill /* 1373650Sbill * Relocation is pc relative, so decrease the relocation 1374650Sbill * by the amount the current segment is displaced. 1375650Sbill * (E.g if we are a relative reference to a text location 1376650Sbill * from data space, we added the increase in the text address 1377650Sbill * above, and subtract the increase in our (data) address 1378650Sbill * here, leaving the net change the relative change in the 1379650Sbill * positioning of our text and data segments.) 1380650Sbill */ 1381615Sbill if (rp->r_pcrel) 1382615Sbill tw -= creloc; 1383650Sbill /* 1384650Sbill * Put the value back in the segment, 1385650Sbill * while checking for overflow. 1386650Sbill */ 1387615Sbill switch (rp->r_length) { 1388615Sbill 1389615Sbill case 0: /* byte */ 1390615Sbill if (tw < -128 || tw > 127) 1391615Sbill error(0, "byte displacement overflow"); 1392615Sbill *cp = tw; 1393615Sbill break; 1394615Sbill case 1: /* word */ 1395615Sbill if (tw < -32768 || tw > 32767) 1396615Sbill error(0, "word displacement overflow"); 1397615Sbill *(short *)cp = tw; 1398615Sbill break; 1399615Sbill case 2: /* long */ 1400615Sbill *(long *)cp = tw; 1401615Sbill break; 1402615Sbill } 1403650Sbill /* 1404650Sbill * If we are saving relocation information, 1405650Sbill * we must convert the address in the segment from 1406650Sbill * the old .o file into an address in the segment in 1407650Sbill * the new a.out, by adding the position of our 1408650Sbill * segment in the new larger segment. 1409650Sbill */ 1410615Sbill if (rflag) 1411650Sbill rp->r_address += position; 1412615Sbill } 1413615Sbill bwrite(codep, codesz, b1); 1414615Sbill if (rflag) 1415615Sbill bwrite(relp, relsz, b2); 1416615Sbill cfree((char *)relp); 1417615Sbill cfree(codep); 1418615Sbill } 1419615Sbill 1420615Sbill finishout() 1421615Sbill { 1422615Sbill register int i; 1423615Sbill int nsymt; 1424615Sbill 1425615Sbill if (sflag==0) { 1426615Sbill nsymt = symx(nextsym); 1427615Sbill for (i = 0; i < nsymt; i++) 1428615Sbill symwrite(xsym(i), sout); 1429615Sbill bwrite(&offset, sizeof offset, sout); 1430615Sbill } 1431615Sbill if (!ofilfnd) { 1432615Sbill unlink("a.out"); 1433898Sbill if (link("l.out", "a.out") < 0) 1434898Sbill error(1, "cannot move l.out to a.out"); 1435615Sbill ofilename = "a.out"; 1436615Sbill } 1437615Sbill delarg = errlev; 1438615Sbill delexit(); 1439615Sbill } 1440615Sbill 1441615Sbill mkfsym(s) 1442615Sbill char *s; 1443615Sbill { 1444615Sbill 1445615Sbill if (sflag || xflag) 1446615Sbill return; 1447615Sbill cursym.n_un.n_name = s; 1448615Sbill cursym.n_type = N_TEXT; 1449615Sbill cursym.n_value = torigin; 1450615Sbill symwrite(&cursym, sout); 1451615Sbill } 1452615Sbill 1453615Sbill getarhdr() 1454615Sbill { 1455615Sbill register char *cp; 1456615Sbill 1457615Sbill mget((char *)&archdr, sizeof archdr, &text); 1458615Sbill for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];) 1459615Sbill if (*cp++ == ' ') { 1460615Sbill cp[-1] = 0; 1461615Sbill return; 1462615Sbill } 1463615Sbill } 1464615Sbill 1465615Sbill mget(loc, n, sp) 1466615Sbill register STREAM *sp; 1467615Sbill register char *loc; 1468615Sbill { 1469615Sbill register char *p; 1470615Sbill register int take; 1471615Sbill 1472615Sbill top: 1473615Sbill if (n == 0) 1474615Sbill return; 1475615Sbill if (sp->size && sp->nibuf) { 1476615Sbill p = sp->ptr; 1477615Sbill take = sp->size; 1478615Sbill if (take > sp->nibuf) 1479615Sbill take = sp->nibuf; 1480615Sbill if (take > n) 1481615Sbill take = n; 1482615Sbill n -= take; 1483615Sbill sp->size -= take; 1484615Sbill sp->nibuf -= take; 1485615Sbill sp->pos += take; 1486615Sbill do 1487615Sbill *loc++ = *p++; 1488615Sbill while (--take > 0); 1489615Sbill sp->ptr = p; 1490615Sbill goto top; 1491615Sbill } 1492615Sbill if (n > BUFSIZ) { 14936414Smckusic take = n - n % BLKSIZE; 14946414Smckusic lseek(infil, (sp->bno+1)*BLKSIZE, 0); 1495615Sbill if (take > sp->size || read(infil, loc, take) != take) 1496615Sbill error(1, "premature EOF"); 1497615Sbill loc += take; 1498615Sbill n -= take; 1499615Sbill sp->size -= take; 1500615Sbill sp->pos += take; 15016414Smckusic dseek(sp, (sp->bno+1+take/BLKSIZE)*BLKSIZE, -1); 1502615Sbill goto top; 1503615Sbill } 1504615Sbill *loc++ = get(sp); 1505615Sbill --n; 1506615Sbill goto top; 1507615Sbill } 1508615Sbill 1509615Sbill symwrite(sp, bp) 1510615Sbill struct nlist *sp; 1511615Sbill struct biobuf *bp; 1512615Sbill { 1513615Sbill register int len; 1514615Sbill register char *str; 1515615Sbill 1516615Sbill str = sp->n_un.n_name; 1517615Sbill if (str) { 1518615Sbill sp->n_un.n_strx = offset; 1519615Sbill len = strlen(str) + 1; 1520615Sbill bwrite(str, len, strout); 1521615Sbill offset += len; 1522615Sbill } 1523615Sbill bwrite(sp, sizeof (*sp), bp); 1524615Sbill sp->n_un.n_name = str; 1525615Sbill } 1526615Sbill 1527615Sbill dseek(sp, loc, s) 1528615Sbill register STREAM *sp; 1529615Sbill long loc, s; 1530615Sbill { 1531615Sbill register PAGE *p; 1532615Sbill register b, o; 1533615Sbill int n; 1534615Sbill 15356414Smckusic b = loc>>BLKSHIFT; 15366414Smckusic o = loc&BLKMASK; 1537615Sbill if (o&01) 1538615Sbill error(1, "loader error; odd offset"); 1539615Sbill --sp->pno->nuser; 1540615Sbill if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b) 1541615Sbill if (p->nuser==0 || (p = &page[0])->nuser==0) { 1542615Sbill if (page[0].nuser==0 && page[1].nuser==0) 1543615Sbill if (page[0].bno < page[1].bno) 1544615Sbill p = &page[0]; 1545615Sbill p->bno = b; 15466414Smckusic lseek(infil, loc & ~(long)BLKMASK, 0); 1547615Sbill if ((n = read(infil, p->buff, sizeof(p->buff))) < 0) 1548615Sbill n = 0; 1549615Sbill p->nibuf = n; 1550615Sbill } else 1551615Sbill error(1, "botch: no pages"); 1552615Sbill ++p->nuser; 1553615Sbill sp->bno = b; 1554615Sbill sp->pno = p; 1555615Sbill if (s != -1) {sp->size = s; sp->pos = 0;} 1556615Sbill sp->ptr = (char *)(p->buff + o); 1557615Sbill if ((sp->nibuf = p->nibuf-o) <= 0) 1558615Sbill sp->size = 0; 1559615Sbill } 1560615Sbill 1561615Sbill char 1562615Sbill get(asp) 1563615Sbill STREAM *asp; 1564615Sbill { 1565615Sbill register STREAM *sp; 1566615Sbill 1567615Sbill sp = asp; 1568615Sbill if ((sp->nibuf -= sizeof(char)) < 0) { 15696414Smckusic dseek(sp, ((long)(sp->bno+1)<<BLKSHIFT), (long)-1); 1570615Sbill sp->nibuf -= sizeof(char); 1571615Sbill } 1572615Sbill if ((sp->size -= sizeof(char)) <= 0) { 1573615Sbill if (sp->size < 0) 1574615Sbill error(1, "premature EOF"); 1575615Sbill ++fpage.nuser; 1576615Sbill --sp->pno->nuser; 1577615Sbill sp->pno = (PAGE *) &fpage; 1578615Sbill } 1579615Sbill sp->pos += sizeof(char); 1580615Sbill return(*sp->ptr++); 1581615Sbill } 1582615Sbill 1583615Sbill getfile(acp) 1584615Sbill char *acp; 1585615Sbill { 1586615Sbill register char *cp; 1587615Sbill register int c; 1588615Sbill char arcmag[SARMAG+1]; 1589615Sbill struct stat stb; 1590615Sbill 1591615Sbill cp = acp; 1592615Sbill infil = -1; 1593615Sbill archdr.ar_name[0] = '\0'; 1594615Sbill filname = cp; 1595615Sbill if (cp[0]=='-' && cp[1]=='l') { 1596898Sbill char *locfilname = "/usr/local/lib/libxxxxxxxxxxxxxxx"; 1597615Sbill if(cp[2] == '\0') 1598615Sbill cp = "-la"; 1599898Sbill filname = "/usr/lib/libxxxxxxxxxxxxxxx"; 1600615Sbill for(c=0; cp[c+2]; c++) { 1601615Sbill filname[c+12] = cp[c+2]; 1602615Sbill locfilname[c+18] = cp[c+2]; 1603615Sbill } 1604615Sbill filname[c+12] = locfilname[c+18] = '.'; 1605615Sbill filname[c+13] = locfilname[c+19] = 'a'; 1606615Sbill filname[c+14] = locfilname[c+20] = '\0'; 1607615Sbill if ((infil = open(filname+4, 0)) >= 0) { 1608615Sbill filname += 4; 1609615Sbill } else if ((infil = open(filname, 0)) < 0) { 1610615Sbill filname = locfilname; 1611615Sbill } 1612615Sbill } 1613615Sbill if (infil == -1 && (infil = open(filname, 0)) < 0) 1614615Sbill error(1, "cannot open"); 1615615Sbill page[0].bno = page[1].bno = -1; 1616615Sbill page[0].nuser = page[1].nuser = 0; 1617615Sbill text.pno = reloc.pno = (PAGE *) &fpage; 1618615Sbill fpage.nuser = 2; 1619615Sbill dseek(&text, 0L, SARMAG); 1620615Sbill if (text.size <= 0) 1621615Sbill error(1, "premature EOF"); 1622615Sbill mget((char *)arcmag, SARMAG, &text); 1623615Sbill arcmag[SARMAG] = 0; 1624615Sbill if (strcmp(arcmag, ARMAG)) 1625615Sbill return (0); 1626615Sbill dseek(&text, SARMAG, sizeof archdr); 1627615Sbill if(text.size <= 0) 1628615Sbill return (1); 1629615Sbill getarhdr(); 1630615Sbill if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0) 1631615Sbill return (1); 1632615Sbill fstat(infil, &stb); 1633615Sbill return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2); 1634615Sbill } 1635615Sbill 1636615Sbill struct nlist ** 1637615Sbill lookup() 1638615Sbill { 1639615Sbill register int sh; 1640615Sbill register struct nlist **hp; 1641615Sbill register char *cp, *cp1; 1642615Sbill register struct symseg *gp; 1643615Sbill register int i; 1644615Sbill 1645615Sbill sh = 0; 1646615Sbill for (cp = cursym.n_un.n_name; *cp;) 1647615Sbill sh = (sh<<1) + *cp++; 1648615Sbill sh = (sh & 0x7fffffff) % HSIZE; 1649615Sbill for (gp = symseg; gp < &symseg[NSEG]; gp++) { 1650615Sbill if (gp->sy_first == 0) { 1651615Sbill gp->sy_first = (struct nlist *) 1652615Sbill calloc(NSYM, sizeof (struct nlist)); 1653615Sbill gp->sy_hfirst = (struct nlist **) 1654615Sbill calloc(HSIZE, sizeof (struct nlist *)); 1655615Sbill if (gp->sy_first == 0 || gp->sy_hfirst == 0) 1656615Sbill error(1, "ran out of space for symbol table"); 1657615Sbill gp->sy_last = gp->sy_first + NSYM; 1658615Sbill gp->sy_hlast = gp->sy_hfirst + HSIZE; 1659615Sbill } 1660615Sbill if (gp > csymseg) 1661615Sbill csymseg = gp; 1662615Sbill hp = gp->sy_hfirst + sh; 1663615Sbill i = 1; 1664615Sbill do { 1665615Sbill if (*hp == 0) { 1666615Sbill if (gp->sy_used == NSYM) 1667615Sbill break; 1668615Sbill return (hp); 1669615Sbill } 1670615Sbill cp1 = (*hp)->n_un.n_name; 1671615Sbill for (cp = cursym.n_un.n_name; *cp == *cp1++;) 1672615Sbill if (*cp++ == 0) 1673615Sbill return (hp); 1674615Sbill hp += i; 1675615Sbill i += 2; 1676615Sbill if (hp >= gp->sy_hlast) 1677615Sbill hp -= HSIZE; 1678615Sbill } while (i < HSIZE); 1679615Sbill if (i > HSIZE) 1680615Sbill error(1, "hash table botch"); 1681615Sbill } 1682615Sbill error(1, "symbol table overflow"); 1683615Sbill /*NOTREACHED*/ 1684615Sbill } 1685615Sbill 1686615Sbill symfree(saved) 1687615Sbill struct nlist *saved; 1688615Sbill { 1689615Sbill register struct symseg *gp; 1690615Sbill register struct nlist *sp; 1691615Sbill 1692615Sbill for (gp = csymseg; gp >= symseg; gp--, csymseg--) { 1693615Sbill sp = gp->sy_first + gp->sy_used; 1694615Sbill if (sp == saved) { 1695615Sbill nextsym = sp; 1696615Sbill return; 1697615Sbill } 1698615Sbill for (sp--; sp >= gp->sy_first; sp--) { 1699615Sbill gp->sy_hfirst[sp->n_hash] = 0; 1700615Sbill gp->sy_used--; 1701615Sbill if (sp == saved) { 1702615Sbill nextsym = sp; 1703615Sbill return; 1704615Sbill } 1705615Sbill } 1706615Sbill } 1707615Sbill if (saved == 0) 1708615Sbill return; 1709615Sbill error(1, "symfree botch"); 1710615Sbill } 1711615Sbill 1712615Sbill struct nlist ** 1713615Sbill slookup(s) 1714615Sbill char *s; 1715615Sbill { 1716615Sbill 1717615Sbill cursym.n_un.n_name = s; 1718615Sbill cursym.n_type = N_EXT+N_UNDF; 1719615Sbill cursym.n_value = 0; 1720615Sbill return (lookup()); 1721615Sbill } 1722615Sbill 1723615Sbill enter(hp) 1724615Sbill register struct nlist **hp; 1725615Sbill { 1726615Sbill register struct nlist *sp; 1727615Sbill 1728615Sbill if (*hp==0) { 1729615Sbill if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast) 1730615Sbill error(1, "enter botch"); 1731615Sbill *hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used; 1732615Sbill csymseg->sy_used++; 1733615Sbill sp->n_un.n_name = cursym.n_un.n_name; 1734615Sbill sp->n_type = cursym.n_type; 1735615Sbill sp->n_hash = hp - csymseg->sy_hfirst; 1736615Sbill sp->n_value = cursym.n_value; 1737615Sbill nextsym = lastsym + 1; 1738615Sbill return(1); 1739615Sbill } else { 1740615Sbill lastsym = *hp; 1741615Sbill return(0); 1742615Sbill } 1743615Sbill } 1744615Sbill 1745615Sbill symx(sp) 1746615Sbill struct nlist *sp; 1747615Sbill { 1748615Sbill register struct symseg *gp; 1749615Sbill 1750615Sbill if (sp == 0) 1751615Sbill return (0); 1752615Sbill for (gp = csymseg; gp >= symseg; gp--) 1753615Sbill /* <= is sloppy so nextsym will always work */ 1754615Sbill if (sp >= gp->sy_first && sp <= gp->sy_last) 1755615Sbill return ((gp - symseg) * NSYM + sp - gp->sy_first); 1756615Sbill error(1, "symx botch"); 1757615Sbill /*NOTREACHED*/ 1758615Sbill } 1759615Sbill 1760615Sbill symreloc() 1761615Sbill { 1762615Sbill if(funding) return; 1763615Sbill switch (cursym.n_type & 017) { 1764615Sbill 1765615Sbill case N_TEXT: 1766615Sbill case N_EXT+N_TEXT: 1767615Sbill cursym.n_value += ctrel; 1768615Sbill return; 1769615Sbill 1770615Sbill case N_DATA: 1771615Sbill case N_EXT+N_DATA: 1772615Sbill cursym.n_value += cdrel; 1773615Sbill return; 1774615Sbill 1775615Sbill case N_BSS: 1776615Sbill case N_EXT+N_BSS: 1777615Sbill cursym.n_value += cbrel; 1778615Sbill return; 1779615Sbill 1780615Sbill case N_EXT+N_UNDF: 1781615Sbill return; 1782615Sbill 1783615Sbill default: 1784615Sbill if (cursym.n_type&N_EXT) 1785615Sbill cursym.n_type = N_EXT+N_ABS; 1786615Sbill return; 1787615Sbill } 1788615Sbill } 1789615Sbill 1790615Sbill error(n, s) 1791615Sbill char *s; 1792615Sbill { 1793898Sbill 1794615Sbill if (errlev==0) 1795615Sbill printf("ld:"); 1796615Sbill if (filname) { 1797615Sbill printf("%s", filname); 1798615Sbill if (n != -1 && archdr.ar_name[0]) 1799615Sbill printf("(%s)", archdr.ar_name); 1800615Sbill printf(": "); 1801615Sbill } 1802615Sbill printf("%s\n", s); 1803615Sbill if (n == -1) 1804615Sbill return; 1805615Sbill if (n) 1806615Sbill delexit(); 1807615Sbill errlev = 2; 1808615Sbill } 1809615Sbill 1810615Sbill readhdr(loc) 1811615Sbill off_t loc; 1812615Sbill { 1813615Sbill 1814615Sbill dseek(&text, loc, (long)sizeof(filhdr)); 1815615Sbill mget((short *)&filhdr, sizeof(filhdr), &text); 1816615Sbill if (N_BADMAG(filhdr)) { 1817615Sbill if (filhdr.a_magic == OARMAG) 1818615Sbill error(1, "old archive"); 1819615Sbill error(1, "bad magic number"); 1820615Sbill } 1821615Sbill if (filhdr.a_text&01 || filhdr.a_data&01) 1822615Sbill error(1, "text/data size odd"); 1823615Sbill if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) { 1824615Sbill cdrel = -round(filhdr.a_text, PAGSIZ); 1825615Sbill cbrel = cdrel - filhdr.a_data; 1826615Sbill } else if (filhdr.a_magic == OMAGIC) { 1827615Sbill cdrel = -filhdr.a_text; 1828615Sbill cbrel = cdrel - filhdr.a_data; 1829615Sbill } else 1830615Sbill error(1, "bad format"); 1831615Sbill } 1832615Sbill 1833615Sbill round(v, r) 1834615Sbill int v; 1835615Sbill u_long r; 1836615Sbill { 1837615Sbill 1838615Sbill r--; 1839615Sbill v += r; 1840615Sbill v &= ~(long)r; 1841615Sbill return(v); 1842615Sbill } 1843615Sbill 1844615Sbill #define NSAVETAB 8192 1845615Sbill char *savetab; 1846615Sbill int saveleft; 1847615Sbill 1848615Sbill char * 1849615Sbill savestr(cp) 1850615Sbill register char *cp; 1851615Sbill { 1852615Sbill register int len; 1853615Sbill 1854615Sbill len = strlen(cp) + 1; 1855615Sbill if (len > saveleft) { 1856615Sbill saveleft = NSAVETAB; 1857615Sbill if (len > saveleft) 1858615Sbill saveleft = len; 1859615Sbill savetab = (char *)malloc(saveleft); 1860615Sbill if (savetab == 0) 1861615Sbill error(1, "ran out of memory (savestr)"); 1862615Sbill } 1863615Sbill strncpy(savetab, cp, len); 1864615Sbill cp = savetab; 1865615Sbill savetab += len; 1866615Sbill saveleft -= len; 1867615Sbill return (cp); 1868615Sbill } 1869615Sbill 1870615Sbill bopen(bp, off) 1871615Sbill struct biobuf *bp; 1872615Sbill { 1873615Sbill 1874615Sbill bp->b_ptr = bp->b_buf; 1875615Sbill bp->b_nleft = BUFSIZ - off % BUFSIZ; 1876615Sbill bp->b_off = off; 1877615Sbill bp->b_link = biobufs; 1878615Sbill biobufs = bp; 1879615Sbill } 1880615Sbill 1881615Sbill int bwrerror; 1882615Sbill 1883615Sbill bwrite(p, cnt, bp) 1884615Sbill register char *p; 1885615Sbill register int cnt; 1886615Sbill register struct biobuf *bp; 1887615Sbill { 1888615Sbill register int put; 1889615Sbill register char *to; 1890615Sbill 1891615Sbill top: 1892615Sbill if (cnt == 0) 1893615Sbill return; 1894615Sbill if (bp->b_nleft) { 1895615Sbill put = bp->b_nleft; 1896615Sbill if (put > cnt) 1897615Sbill put = cnt; 1898615Sbill bp->b_nleft -= put; 1899615Sbill to = bp->b_ptr; 1900615Sbill asm("movc3 r8,(r11),(r7)"); 1901615Sbill bp->b_ptr += put; 1902615Sbill p += put; 1903615Sbill cnt -= put; 1904615Sbill goto top; 1905615Sbill } 1906615Sbill if (cnt >= BUFSIZ) { 1907615Sbill if (bp->b_ptr != bp->b_buf) 1908615Sbill bflush1(bp); 1909615Sbill put = cnt - cnt % BUFSIZ; 1910615Sbill if (boffset != bp->b_off) 1911615Sbill lseek(biofd, bp->b_off, 0); 1912615Sbill if (write(biofd, p, put) != put) { 1913615Sbill bwrerror = 1; 1914615Sbill error(1, "output write error"); 1915615Sbill } 1916615Sbill bp->b_off += put; 1917615Sbill boffset = bp->b_off; 1918615Sbill p += put; 1919615Sbill cnt -= put; 1920615Sbill goto top; 1921615Sbill } 1922615Sbill bflush1(bp); 1923615Sbill goto top; 1924615Sbill } 1925615Sbill 1926615Sbill bflush() 1927615Sbill { 1928615Sbill register struct biobuf *bp; 1929615Sbill 1930615Sbill if (bwrerror) 1931615Sbill return; 1932615Sbill for (bp = biobufs; bp; bp = bp->b_link) 1933615Sbill bflush1(bp); 1934615Sbill } 1935615Sbill 1936615Sbill bflush1(bp) 1937615Sbill register struct biobuf *bp; 1938615Sbill { 1939615Sbill register int cnt = bp->b_ptr - bp->b_buf; 1940615Sbill 1941615Sbill if (cnt == 0) 1942615Sbill return; 1943615Sbill if (boffset != bp->b_off) 1944615Sbill lseek(biofd, bp->b_off, 0); 1945615Sbill if (write(biofd, bp->b_buf, cnt) != cnt) { 1946615Sbill bwrerror = 1; 1947615Sbill error(1, "output write error"); 1948615Sbill } 1949615Sbill bp->b_off += cnt; 1950615Sbill boffset = bp->b_off; 1951615Sbill bp->b_ptr = bp->b_buf; 1952615Sbill bp->b_nleft = BUFSIZ; 1953615Sbill } 1954615Sbill 1955615Sbill bflushc(bp, c) 1956615Sbill register struct biobuf *bp; 1957615Sbill { 1958615Sbill 1959615Sbill bflush1(bp); 1960615Sbill bputc(c, bp); 1961615Sbill } 1962