1*3606Ssklower static char sccsid[] = "@(#)ld.c 4.4 04/26/81"; 2615Sbill /* 3898Sbill * ld - string table version for VAX 4615Sbill */ 5615Sbill 6615Sbill #include <sys/types.h> 7615Sbill #include <signal.h> 8615Sbill #include <stdio.h> 9615Sbill #include <ctype.h> 10650Sbill #include <ar.h> 11650Sbill #include <a.out.h> 12615Sbill #include <ranlib.h> 13615Sbill #include <stat.h> 14615Sbill #include <pagsiz.h> 15615Sbill 16615Sbill /* 17615Sbill * Basic strategy: 18615Sbill * 19615Sbill * The loader takes a number of files and libraries as arguments. 20615Sbill * A first pass examines each file in turn. Normal files are 21615Sbill * unconditionally loaded, and the (external) symbols they define and require 22615Sbill * are noted in the symbol table. Libraries are searched, and the 23615Sbill * library members which define needed symbols are remembered 24615Sbill * in a special data structure so they can be selected on the second 25615Sbill * pass. Symbols defined and required by library members are also 26615Sbill * recorded. 27615Sbill * 28615Sbill * After the first pass, the loader knows the size of the basic text 29615Sbill * data, and bss segments from the sum of the sizes of the modules which 30615Sbill * were required. It has computed, for each ``common'' symbol, the 31615Sbill * maximum size of any reference to it, and these symbols are then assigned 32615Sbill * storage locations after their sizes are appropriately rounded. 33615Sbill * The loader now knows all sizes for the eventual output file, and 34615Sbill * can determine the final locations of external symbols before it 35615Sbill * begins a second pass. 36615Sbill * 37615Sbill * On the second pass each normal file and required library member 38615Sbill * is processed again. The symbol table for each such file is 39615Sbill * reread and relevant parts of it are placed in the output. The offsets 40615Sbill * in the local symbol table for externally defined symbols are recorded 41615Sbill * since relocation information refers to symbols in this way. 42615Sbill * Armed with all necessary information, the text and data segments 43615Sbill * are relocated and the result is placed in the output file, which 44615Sbill * is pasted together, ``in place'', by writing to it in several 45615Sbill * different places concurrently. 46615Sbill */ 47615Sbill 48615Sbill /* 49615Sbill * Internal data structures 50615Sbill * 51615Sbill * All internal data structures are segmented and dynamically extended. 52615Sbill * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT) 53615Sbill * referenced library members, and 100 (NSYMPR) private (local) symbols 54615Sbill * per object module. For large programs and/or modules, these structures 55615Sbill * expand to be up to 40 (NSEG) times as large as this as necessary. 56615Sbill */ 57615Sbill #define NSEG 40 /* Number of segments, each data structure */ 58615Sbill #define NSYM 1103 /* Number of symbols per segment */ 59615Sbill #define NROUT 250 /* Number of library references per segment */ 60615Sbill #define NSYMPR 100 /* Number of private symbols per segment */ 61615Sbill 62615Sbill /* 63615Sbill * Structure describing each symbol table segment. 64615Sbill * Each segment has its own hash table. We record the first 65615Sbill * address in and first address beyond both the symbol and hash 66615Sbill * tables, for use in the routine symx and the lookup routine respectively. 67615Sbill * The symfree routine also understands this structure well as it used 68615Sbill * to back out symbols from modules we decide that we don't need in pass 1. 69615Sbill * 70615Sbill * Csymseg points to the current symbol table segment; 71615Sbill * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated, 72615Sbill * (unless csymseg->sy_used == NSYM in which case we will allocate another 73615Sbill * symbol table segment first.) 74615Sbill */ 75615Sbill struct symseg { 76615Sbill struct nlist *sy_first; /* base of this alloc'ed segment */ 77615Sbill struct nlist *sy_last; /* end of this segment, for n_strx */ 78615Sbill int sy_used; /* symbols used in this seg */ 79615Sbill struct nlist **sy_hfirst; /* base of hash table, this seg */ 80615Sbill struct nlist **sy_hlast; /* end of hash table, this seg */ 81615Sbill } symseg[NSEG], *csymseg; 82615Sbill 83615Sbill /* 84615Sbill * The lookup routine uses quadratic rehash. Since a quadratic rehash 85615Sbill * only probes 1/2 of the buckets in the table, and since the hash 86615Sbill * table is segmented the same way the symbol table is, we make the 87615Sbill * hash table have twice as many buckets as there are symbol table slots 88615Sbill * in the segment. This guarantees that the quadratic rehash will never 89615Sbill * fail to find an empty bucket if the segment is not full and the 90615Sbill * symbol is not there. 91615Sbill */ 92615Sbill #define HSIZE (NSYM*2) 93615Sbill 94615Sbill /* 95615Sbill * Xsym converts symbol table indices (ala x) into symbol table pointers. 96615Sbill * Symx (harder, but never used in loops) inverts pointers into the symbol 97615Sbill * table into indices using the symseg[] structure. 98615Sbill */ 99615Sbill #define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM)) 100615Sbill /* symx() is a function, defined below */ 101615Sbill 102615Sbill struct nlist cursym; /* current symbol */ 103615Sbill struct nlist *lastsym; /* last symbol entered */ 104615Sbill struct nlist *nextsym; /* next available symbol table entry */ 105615Sbill struct nlist *addsym; /* first sym defined during incr load */ 106615Sbill int nsym; /* pass2: number of local symbols in a.out */ 107615Sbill /* nsym + symx(nextsym) is the symbol table size during pass2 */ 108615Sbill 109615Sbill struct nlist **lookup(), **slookup(); 110650Sbill struct nlist *p_etext, *p_edata, *p_end, *entrypt; 111615Sbill 112615Sbill /* 113615Sbill * Definitions of segmentation for library member table. 114615Sbill * For each library we encounter on pass 1 we record pointers to all 115615Sbill * members which we will load on pass 2. These are recorded as offsets 116615Sbill * into the archive in the library member table. Libraries are 117615Sbill * separated in the table by the special offset value -1. 118615Sbill */ 119615Sbill off_t li_init[NROUT]; 120615Sbill struct libseg { 121615Sbill off_t *li_first; 122615Sbill int li_used; 123615Sbill int li_used2; 124615Sbill } libseg[NSEG] = { 125615Sbill li_init, 0, 0, 126615Sbill }, *clibseg = libseg; 127615Sbill 128615Sbill /* 129615Sbill * In processing each module on pass 2 we must relocate references 130615Sbill * relative to external symbols. These references are recorded 131615Sbill * in the relocation information as relative to local symbol numbers 132615Sbill * assigned to the external symbols when the module was created. 133615Sbill * Thus before relocating the module in pass 2 we create a table 134615Sbill * which maps these internal numbers to symbol table entries. 135615Sbill * A hash table is constructed, based on the local symbol table indices, 136615Sbill * for quick lookup of these symbols. 137615Sbill */ 138615Sbill #define LHSIZ 31 139615Sbill struct local { 140615Sbill int l_index; /* index to symbol in file */ 141615Sbill struct nlist *l_symbol; /* ptr to symbol table */ 142615Sbill struct local *l_link; /* hash link */ 143615Sbill } *lochash[LHSIZ], lhinit[NSYMPR]; 144615Sbill struct locseg { 145615Sbill struct local *lo_first; 146615Sbill int lo_used; 147615Sbill } locseg[NSEG] = { 148615Sbill lhinit, 0 149615Sbill }, *clocseg; 150615Sbill 151615Sbill /* 152615Sbill * Libraries are typically built with a table of contents, 153615Sbill * which is the first member of a library with special file 154615Sbill * name __.SYMDEF and contains a list of symbol names 155615Sbill * and with each symbol the offset of the library member which defines 156615Sbill * it. The loader uses this table to quickly tell which library members 157615Sbill * are (potentially) useful. The alternative, examining the symbol 158615Sbill * table of each library member, is painfully slow for large archives. 159615Sbill * 160615Sbill * See <ranlib.h> for the definition of the ranlib structure and an 161615Sbill * explanation of the __.SYMDEF file format. 162615Sbill */ 163615Sbill int tnum; /* number of symbols in table of contents */ 164615Sbill int ssiz; /* size of string table for table of contents */ 165615Sbill struct ranlib *tab; /* the table of contents (dynamically allocated) */ 166615Sbill char *tabstr; /* string table for table of contents */ 167615Sbill 168615Sbill /* 169615Sbill * We open each input file or library only once, but in pass2 we 170615Sbill * (historically) read from such a file at 2 different places at the 171615Sbill * same time. These structures are remnants from those days, 172650Sbill * and now serve only to catch ``Premature EOF''. 173615Sbill */ 174615Sbill typedef struct { 175615Sbill short *fakeptr; 176615Sbill int bno; 177615Sbill int nibuf; 178615Sbill int nuser; 179615Sbill char buff[BSIZE]; 180615Sbill } PAGE; 181615Sbill 182615Sbill PAGE page[2]; 183615Sbill 184615Sbill struct { 185615Sbill short *fakeptr; 186615Sbill int bno; 187615Sbill int nibuf; 188615Sbill int nuser; 189615Sbill } fpage; 190615Sbill 191615Sbill typedef struct { 192615Sbill char *ptr; 193615Sbill int bno; 194615Sbill int nibuf; 195615Sbill long size; 196615Sbill long pos; 197615Sbill PAGE *pno; 198615Sbill } STREAM; 199615Sbill 200615Sbill STREAM text; 201615Sbill STREAM reloc; 202615Sbill 203615Sbill /* 204615Sbill * Header from the a.out and the archive it is from (if any). 205615Sbill */ 206615Sbill struct exec filhdr; 207615Sbill struct ar_hdr archdr; 208615Sbill #define OARMAG 0177545 209615Sbill 210615Sbill /* 211615Sbill * Options. 212615Sbill */ 213615Sbill int trace; 214615Sbill int xflag; /* discard local symbols */ 215615Sbill int Xflag; /* discard locals starting with 'L' */ 216615Sbill int Sflag; /* discard all except locals and globals*/ 217615Sbill int rflag; /* preserve relocation bits, don't define common */ 218615Sbill int arflag; /* original copy of rflag */ 219615Sbill int sflag; /* discard all symbols */ 220898Sbill int Mflag; /* print rudimentary load map */ 221615Sbill int nflag; /* pure procedure */ 222615Sbill int dflag; /* define common even with rflag */ 223650Sbill int zflag; /* demand paged */ 224615Sbill long hsize; /* size of hole at beginning of data to be squashed */ 225615Sbill int Aflag; /* doing incremental load */ 226650Sbill int Nflag; /* want impure a.out */ 227615Sbill int funding; /* reading fundamental file for incremental load */ 228898Sbill int yflag; /* number of symbols to be traced */ 229898Sbill char **ytab; /* the symbols */ 230615Sbill 231615Sbill /* 232615Sbill * These are the cumulative sizes, set in pass 1, which 233615Sbill * appear in the a.out header when the loader is finished. 234615Sbill */ 235615Sbill off_t tsize, dsize, bsize, trsize, drsize, ssize; 236615Sbill 237615Sbill /* 238615Sbill * Symbol relocation: c?rel is a scale factor which is 239615Sbill * added to an old relocation to convert it to new units; 240615Sbill * i.e. it is the difference between segment origins. 241650Sbill * (Thus if we are loading from a data segment which began at location 242650Sbill * 4 in a .o file into an a.out where it will be loaded starting at 243650Sbill * 1024, cdrel will be 1020.) 244615Sbill */ 245615Sbill long ctrel, cdrel, cbrel; 246615Sbill 247615Sbill /* 248650Sbill * Textbase is the start address of all text, 0 unless given by -T. 249615Sbill * Database is the base of all data, computed before and used during pass2. 250650Sbill */ 251650Sbill long textbase, database; 252650Sbill 253650Sbill /* 254615Sbill * The base addresses for the loaded text, data and bss from the 255615Sbill * current module during pass2 are given by torigin, dorigin and borigin. 256615Sbill */ 257615Sbill long torigin, dorigin, borigin; 258615Sbill 259615Sbill /* 260615Sbill * Errlev is nonzero when errors have occured. 261615Sbill * Delarg is an implicit argument to the routine delexit 262615Sbill * which is called on error. We do ``delarg = errlev'' before normal 263615Sbill * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the 264615Sbill * result file executable. 265615Sbill */ 266615Sbill int errlev; 267615Sbill int delarg = 4; 268615Sbill 269615Sbill /* 270615Sbill * The biobuf structure and associated routines are used to write 271615Sbill * into one file at several places concurrently. Calling bopen 272615Sbill * with a biobuf structure sets it up to write ``biofd'' starting 273615Sbill * at the specified offset. You can then use ``bwrite'' and/or ``bputc'' 274615Sbill * to stuff characters in the stream, much like ``fwrite'' and ``fputc''. 275615Sbill * Calling bflush drains all the buffers and MUST be done before exit. 276615Sbill */ 277615Sbill struct biobuf { 278615Sbill short b_nleft; /* Number free spaces left in b_buf */ 279615Sbill /* Initialize to be less than BUFSIZ initially, to boundary align in file */ 280615Sbill char *b_ptr; /* Next place to stuff characters */ 281615Sbill char b_buf[BUFSIZ]; /* The buffer itself */ 282615Sbill off_t b_off; /* Current file offset */ 283615Sbill struct biobuf *b_link; /* Link in chain for bflush() */ 284615Sbill } *biobufs; 285615Sbill #define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \ 286615Sbill : bflushc(b, c)) 287615Sbill int biofd; 288615Sbill off_t boffset; 289615Sbill struct biobuf *tout, *dout, *trout, *drout, *sout, *strout; 290615Sbill 291615Sbill /* 292615Sbill * Offset is the current offset in the string file. 293615Sbill * Its initial value reflects the fact that we will 294615Sbill * eventually stuff the size of the string table at the 295615Sbill * beginning of the string table (i.e. offset itself!). 296615Sbill */ 297615Sbill off_t offset = sizeof (off_t); 298615Sbill 299615Sbill int ofilfnd; /* -o given; otherwise move l.out to a.out */ 300615Sbill char *ofilename = "l.out"; 301*3606Ssklower int ofilemode; /* respect umask even for unsucessful ld's */ 302615Sbill int infil; /* current input file descriptor */ 303615Sbill char *filname; /* and its name */ 304615Sbill 305615Sbill /* 306615Sbill * Base of the string table of the current module (pass1 and pass2). 307615Sbill */ 308615Sbill char *curstr; 309615Sbill 310615Sbill char get(); 311615Sbill int delexit(); 312615Sbill char *savestr(); 313615Sbill 314615Sbill main(argc, argv) 315615Sbill char **argv; 316615Sbill { 317615Sbill register int c, i; 318615Sbill int num; 319615Sbill register char *ap, **p; 320615Sbill char save; 321615Sbill 322650Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 323615Sbill signal(SIGINT, delexit); 324650Sbill signal(SIGTERM, delexit); 325650Sbill } 326615Sbill if (argc == 1) 327615Sbill exit(4); 328615Sbill p = argv+1; 329615Sbill 330650Sbill /* 331650Sbill * Scan files once to find where symbols are defined. 332650Sbill */ 333615Sbill for (c=1; c<argc; c++) { 334615Sbill if (trace) 335615Sbill printf("%s:\n", *p); 336615Sbill filname = 0; 337615Sbill ap = *p++; 338615Sbill if (*ap != '-') { 339615Sbill load1arg(ap); 340615Sbill continue; 341615Sbill } 342615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 343615Sbill 344615Sbill case 'o': 345615Sbill if (++c >= argc) 346615Sbill error(1, "-o where?"); 347615Sbill ofilename = *p++; 348615Sbill ofilfnd++; 349615Sbill continue; 350615Sbill case 'u': 351615Sbill case 'e': 352615Sbill if (++c >= argc) 353615Sbill error(1, "-u or -c: arg missing"); 354615Sbill enter(slookup(*p++)); 355615Sbill if (ap[i]=='e') 356615Sbill entrypt = lastsym; 357615Sbill continue; 358615Sbill case 'H': 359615Sbill if (++c >= argc) 360615Sbill error(1, "-H: arg missing"); 361615Sbill if (tsize!=0) 362615Sbill error(1, "-H: too late, some text already loaded"); 363615Sbill hsize = atoi(*p++); 364615Sbill continue; 365615Sbill case 'A': 366615Sbill if (++c >= argc) 367615Sbill error(1, "-A: arg missing"); 368615Sbill if (Aflag) 369615Sbill error(1, "-A: only one base file allowed"); 370615Sbill Aflag = 1; 371615Sbill nflag = 0; 372615Sbill funding = 1; 373615Sbill load1arg(*p++); 374615Sbill trsize = drsize = tsize = dsize = bsize = 0; 375615Sbill ctrel = cdrel = cbrel = 0; 376615Sbill funding = 0; 377615Sbill addsym = nextsym; 378615Sbill continue; 379615Sbill case 'D': 380615Sbill if (++c >= argc) 381615Sbill error(1, "-D: arg missing"); 382615Sbill num = htoi(*p++); 383615Sbill if (dsize > num) 384615Sbill error(1, "-D: too small"); 385615Sbill dsize = num; 386615Sbill continue; 387615Sbill case 'T': 388615Sbill if (++c >= argc) 389615Sbill error(1, "-T: arg missing"); 390615Sbill if (tsize!=0) 391615Sbill error(1, "-T: too late, some text already loaded"); 392615Sbill textbase = htoi(*p++); 393615Sbill continue; 394615Sbill case 'l': 395615Sbill save = ap[--i]; 396615Sbill ap[i]='-'; 397615Sbill load1arg(&ap[i]); 398615Sbill ap[i]=save; 399615Sbill goto next; 400898Sbill case 'M': 401898Sbill Mflag++; 402898Sbill continue; 403615Sbill case 'x': 404615Sbill xflag++; 405615Sbill continue; 406615Sbill case 'X': 407615Sbill Xflag++; 408615Sbill continue; 409615Sbill case 'S': 410615Sbill Sflag++; 411615Sbill continue; 412615Sbill case 'r': 413615Sbill rflag++; 414615Sbill arflag++; 415615Sbill continue; 416615Sbill case 's': 417615Sbill sflag++; 418615Sbill xflag++; 419615Sbill continue; 420615Sbill case 'n': 421615Sbill nflag++; 422650Sbill Nflag = zflag = 0; 423615Sbill continue; 424615Sbill case 'N': 425650Sbill Nflag++; 426650Sbill nflag = zflag = 0; 427615Sbill continue; 428615Sbill case 'd': 429615Sbill dflag++; 430615Sbill continue; 431615Sbill case 'i': 432615Sbill printf("ld: -i ignored\n"); 433615Sbill continue; 434615Sbill case 't': 435615Sbill trace++; 436615Sbill continue; 437898Sbill case 'y': 438898Sbill if (ap[i+1] == 0) 439898Sbill error(1, "-y: symbol name missing"); 440898Sbill if (yflag == 0) { 441898Sbill ytab = (char **)calloc(argc, sizeof (char **)); 442898Sbill if (ytab == 0) 443898Sbill error(1, "ran out of memory (-y)"); 444898Sbill } 445898Sbill ytab[yflag++] = &ap[i+1]; 446898Sbill goto next; 447615Sbill case 'z': 448615Sbill zflag++; 449650Sbill Nflag = nflag = 0; 450615Sbill continue; 451615Sbill default: 452615Sbill filname = savestr("-x"); /* kludge */ 453615Sbill filname[1] = ap[i]; /* kludge */ 454615Sbill archdr.ar_name[0] = 0; /* kludge */ 455615Sbill error(1, "bad flag"); 456615Sbill } 457615Sbill next: 458615Sbill ; 459615Sbill } 460650Sbill if (rflag == 0 && Nflag == 0 && nflag == 0) 461650Sbill zflag++; 462615Sbill endload(argc, argv); 463615Sbill exit(0); 464615Sbill } 465615Sbill 466615Sbill /* 467615Sbill * Convert a ascii string which is a hex number. 468615Sbill * Used by -T and -D options. 469615Sbill */ 470615Sbill htoi(p) 471615Sbill register char *p; 472615Sbill { 473615Sbill register int c, n; 474615Sbill 475615Sbill n = 0; 476615Sbill while (c = *p++) { 477615Sbill n <<= 4; 478615Sbill if (isdigit(c)) 479615Sbill n += c - '0'; 480615Sbill else if (c >= 'a' && c <= 'f') 481615Sbill n += 10 + (c - 'a'); 482615Sbill else if (c >= 'A' && c <= 'F') 483615Sbill n += 10 + (c - 'A'); 484615Sbill else 485615Sbill error(1, "badly formed hex number"); 486615Sbill } 487615Sbill return (n); 488615Sbill } 489615Sbill 490615Sbill delexit() 491615Sbill { 492615Sbill 493615Sbill bflush(); 494615Sbill unlink("l.out"); 495615Sbill if (delarg==0 && Aflag==0) 496*3606Ssklower chmod(ofilename, ofilemode); 497615Sbill exit (delarg); 498615Sbill } 499615Sbill 500615Sbill endload(argc, argv) 501615Sbill int argc; 502615Sbill char **argv; 503615Sbill { 504615Sbill register int c, i; 505615Sbill long dnum; 506615Sbill register char *ap, **p; 507615Sbill 508615Sbill clibseg = libseg; 509615Sbill filname = 0; 510615Sbill middle(); 511615Sbill setupout(); 512615Sbill p = argv+1; 513615Sbill for (c=1; c<argc; c++) { 514615Sbill ap = *p++; 515615Sbill if (trace) 516615Sbill printf("%s:\n", ap); 517615Sbill if (*ap != '-') { 518615Sbill load2arg(ap); 519615Sbill continue; 520615Sbill } 521615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 522615Sbill 523615Sbill case 'D': 524615Sbill dnum = htoi(*p); 525615Sbill if (dorigin < dnum) 526615Sbill while (dorigin < dnum) 527615Sbill bputc(0, dout), dorigin++; 528615Sbill /* fall into ... */ 529615Sbill case 'T': 530615Sbill case 'u': 531615Sbill case 'e': 532615Sbill case 'o': 533615Sbill case 'H': 534615Sbill ++c; 535615Sbill ++p; 536615Sbill /* fall into ... */ 537615Sbill default: 538615Sbill continue; 539615Sbill case 'A': 540615Sbill funding = 1; 541615Sbill load2arg(*p++); 542615Sbill funding = 0; 543615Sbill c++; 544615Sbill continue; 545898Sbill case 'y': 546898Sbill goto next; 547615Sbill case 'l': 548615Sbill ap[--i]='-'; 549615Sbill load2arg(&ap[i]); 550615Sbill goto next; 551615Sbill } 552615Sbill next: 553615Sbill ; 554615Sbill } 555615Sbill finishout(); 556615Sbill } 557615Sbill 558615Sbill /* 559615Sbill * Scan file to find defined symbols. 560615Sbill */ 561615Sbill load1arg(cp) 562615Sbill register char *cp; 563615Sbill { 564615Sbill register struct ranlib *tp; 565615Sbill off_t nloc; 566898Sbill int kind; 567615Sbill 568898Sbill kind = getfile(cp); 569898Sbill if (Mflag) 570898Sbill printf("%s\n", filname); 571898Sbill switch (kind) { 572615Sbill 573615Sbill /* 574615Sbill * Plain file. 575615Sbill */ 576615Sbill case 0: 577615Sbill load1(0, 0L); 578615Sbill break; 579615Sbill 580615Sbill /* 581615Sbill * Archive without table of contents. 582615Sbill * (Slowly) process each member. 583615Sbill */ 584615Sbill case 1: 585898Sbill error(-1, 586898Sbill "warning: archive has no table of contents; add one using ranlib(1)"); 587615Sbill nloc = SARMAG; 588615Sbill while (step(nloc)) 589615Sbill nloc += sizeof(archdr) + 590615Sbill round(atol(archdr.ar_size), sizeof (short)); 591615Sbill break; 592615Sbill 593615Sbill /* 594615Sbill * Archive with table of contents. 595615Sbill * Read the table of contents and its associated string table. 596615Sbill * Pass through the library resolving symbols until nothing changes 597615Sbill * for an entire pass (i.e. you can get away with backward references 598615Sbill * when there is a table of contents!) 599615Sbill */ 600615Sbill case 2: 601615Sbill nloc = SARMAG + sizeof (archdr); 602615Sbill dseek(&text, nloc, sizeof (tnum)); 603615Sbill mget((char *)&tnum, sizeof (tnum), &text); 604615Sbill nloc += sizeof (tnum); 605615Sbill tab = (struct ranlib *)malloc(tnum); 606615Sbill if (tab == 0) 607615Sbill error(1, "ran out of memory (toc)"); 608615Sbill dseek(&text, nloc, tnum); 609615Sbill mget((char *)tab, tnum, &text); 610615Sbill nloc += tnum; 611615Sbill tnum /= sizeof (struct ranlib); 612615Sbill dseek(&text, nloc, sizeof (ssiz)); 613615Sbill mget((char *)&ssiz, sizeof (ssiz), &text); 614615Sbill nloc += sizeof (ssiz); 615615Sbill tabstr = (char *)malloc(ssiz); 616615Sbill if (tabstr == 0) 617615Sbill error(1, "ran out of memory (tocstr)"); 618615Sbill dseek(&text, nloc, ssiz); 619615Sbill mget((char *)tabstr, ssiz, &text); 620615Sbill for (tp = &tab[tnum]; --tp >= tab;) { 621615Sbill if (tp->ran_un.ran_strx < 0 || 622615Sbill tp->ran_un.ran_strx >= ssiz) 623615Sbill error(1, "mangled archive table of contents"); 624615Sbill tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx; 625615Sbill } 626615Sbill while (ldrand()) 627615Sbill continue; 628615Sbill cfree((char *)tab); 629615Sbill cfree(tabstr); 630615Sbill nextlibp(-1); 631615Sbill break; 632615Sbill 633615Sbill /* 634615Sbill * Table of contents is out of date, so search 635615Sbill * as a normal library (but skip the __.SYMDEF file). 636615Sbill */ 637615Sbill case 3: 638898Sbill error(-1, 639898Sbill "warning: table of contents for archive is out of date; rerun ranlib(1)"); 640615Sbill nloc = SARMAG; 641615Sbill do 642615Sbill nloc += sizeof(archdr) + 643615Sbill round(atol(archdr.ar_size), sizeof(short)); 644615Sbill while (step(nloc)); 645615Sbill break; 646615Sbill } 647615Sbill close(infil); 648615Sbill } 649615Sbill 650615Sbill /* 651615Sbill * Advance to the next archive member, which 652615Sbill * is at offset nloc in the archive. If the member 653615Sbill * is useful, record its location in the liblist structure 654615Sbill * for use in pass2. Mark the end of the archive in libilst with a -1. 655615Sbill */ 656615Sbill step(nloc) 657615Sbill off_t nloc; 658615Sbill { 659615Sbill 660615Sbill dseek(&text, nloc, (long) sizeof archdr); 661615Sbill if (text.size <= 0) { 662615Sbill nextlibp(-1); 663615Sbill return (0); 664615Sbill } 665615Sbill getarhdr(); 666615Sbill if (load1(1, nloc + (sizeof archdr))) 667615Sbill nextlibp(nloc); 668615Sbill return (1); 669615Sbill } 670615Sbill 671615Sbill /* 672615Sbill * Record the location of a useful archive member. 673615Sbill * Recording -1 marks the end of files from an archive. 674615Sbill * The liblist data structure is dynamically extended here. 675615Sbill */ 676615Sbill nextlibp(val) 677615Sbill off_t val; 678615Sbill { 679615Sbill 680615Sbill if (clibseg->li_used == NROUT) { 681615Sbill if (++clibseg == &libseg[NSEG]) 682615Sbill error(1, "too many files loaded from libraries"); 683615Sbill clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t)); 684615Sbill if (clibseg->li_first == 0) 685615Sbill error(1, "ran out of memory (nextlibp)"); 686615Sbill } 687615Sbill clibseg->li_first[clibseg->li_used++] = val; 688898Sbill if (val != -1 && Mflag) 689898Sbill printf("\t%s\n", archdr.ar_name); 690615Sbill } 691615Sbill 692615Sbill /* 693615Sbill * One pass over an archive with a table of contents. 694615Sbill * Remember the number of symbols currently defined, 695615Sbill * then call step on members which look promising (i.e. 696615Sbill * that define a symbol which is currently externally undefined). 697615Sbill * Indicate to our caller whether this process netted any more symbols. 698615Sbill */ 699615Sbill ldrand() 700615Sbill { 701615Sbill register struct nlist *sp, **hp; 702615Sbill register struct ranlib *tp, *tplast; 703615Sbill off_t loc; 704615Sbill int nsymt = symx(nextsym); 705615Sbill 706615Sbill tplast = &tab[tnum-1]; 707615Sbill for (tp = tab; tp <= tplast; tp++) { 708615Sbill if ((hp = slookup(tp->ran_un.ran_name)) == 0) 709615Sbill continue; 710615Sbill sp = *hp; 711615Sbill if (sp->n_type != N_EXT+N_UNDF) 712615Sbill continue; 713615Sbill step(tp->ran_off); 714615Sbill loc = tp->ran_off; 715615Sbill while (tp < tplast && (tp+1)->ran_off == loc) 716615Sbill tp++; 717615Sbill } 718615Sbill return (symx(nextsym) != nsymt); 719615Sbill } 720615Sbill 721615Sbill /* 722615Sbill * Examine a single file or archive member on pass 1. 723615Sbill */ 724615Sbill load1(libflg, loc) 725615Sbill off_t loc; 726615Sbill { 727615Sbill register struct nlist *sp; 728615Sbill struct nlist *savnext; 729615Sbill int ndef, nlocal, type, size, nsymt; 730615Sbill register int i; 731615Sbill off_t maxoff; 732615Sbill struct stat stb; 733615Sbill 734615Sbill readhdr(loc); 735615Sbill if (filhdr.a_syms == 0) { 736615Sbill if (filhdr.a_text+filhdr.a_data == 0) 737615Sbill return (0); 738615Sbill error(1, "no namelist"); 739615Sbill } 740615Sbill if (libflg) 741615Sbill maxoff = atol(archdr.ar_size); 742615Sbill else { 743615Sbill fstat(infil, &stb); 744615Sbill maxoff = stb.st_size; 745615Sbill } 746615Sbill if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff) 747615Sbill error(1, "too small (old format .o?)"); 748615Sbill ctrel = tsize; cdrel += dsize; cbrel += bsize; 749615Sbill ndef = 0; 750615Sbill nlocal = sizeof(cursym); 751615Sbill savnext = nextsym; 752615Sbill loc += N_SYMOFF(filhdr); 753615Sbill dseek(&text, loc, filhdr.a_syms); 754615Sbill dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t)); 755615Sbill mget(&size, sizeof (size), &reloc); 756615Sbill dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t)); 757615Sbill curstr = (char *)malloc(size); 758615Sbill if (curstr == NULL) 759615Sbill error(1, "no space for string table"); 760615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc); 761615Sbill while (text.size > 0) { 762615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 763615Sbill if (cursym.n_un.n_strx) { 764615Sbill if (cursym.n_un.n_strx<sizeof(size) || 765615Sbill cursym.n_un.n_strx>=size) 766615Sbill error(1, "bad string table index (pass 1)"); 767615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 768615Sbill } 769615Sbill type = cursym.n_type; 770615Sbill if ((type&N_EXT)==0) { 771615Sbill if (Xflag==0 || cursym.n_un.n_name[0]!='L' || 772615Sbill type & N_STAB) 773615Sbill nlocal += sizeof cursym; 774615Sbill continue; 775615Sbill } 776615Sbill symreloc(); 777615Sbill if (enter(lookup())) 778615Sbill continue; 779615Sbill if ((sp = lastsym)->n_type != N_EXT+N_UNDF) 780615Sbill continue; 781615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 782615Sbill if (cursym.n_value > sp->n_value) 783615Sbill sp->n_value = cursym.n_value; 784615Sbill continue; 785615Sbill } 786615Sbill if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT) 787615Sbill continue; 788615Sbill ndef++; 789615Sbill sp->n_type = cursym.n_type; 790615Sbill sp->n_value = cursym.n_value; 791615Sbill } 792615Sbill if (libflg==0 || ndef) { 793615Sbill tsize += filhdr.a_text; 794615Sbill dsize += round(filhdr.a_data, sizeof (long)); 795615Sbill bsize += round(filhdr.a_bss, sizeof (long)); 796615Sbill ssize += nlocal; 797615Sbill trsize += filhdr.a_trsize; 798615Sbill drsize += filhdr.a_drsize; 799615Sbill if (funding) 800615Sbill textbase = (*slookup("_end"))->n_value; 801615Sbill nsymt = symx(nextsym); 802615Sbill for (i = symx(savnext); i < nsymt; i++) { 803615Sbill sp = xsym(i); 804615Sbill sp->n_un.n_name = savestr(sp->n_un.n_name); 805615Sbill } 806615Sbill free(curstr); 807615Sbill return (1); 808615Sbill } 809615Sbill /* 810615Sbill * No symbols defined by this library member. 811615Sbill * Rip out the hash table entries and reset the symbol table. 812615Sbill */ 813615Sbill symfree(savnext); 814615Sbill free(curstr); 815615Sbill return(0); 816615Sbill } 817615Sbill 818615Sbill middle() 819615Sbill { 820615Sbill register struct nlist *sp; 821615Sbill long csize, t, corigin, ocsize; 822615Sbill int nund, rnd; 823615Sbill char s; 824615Sbill register int i; 825615Sbill int nsymt; 826615Sbill 827615Sbill torigin = 0; 828615Sbill dorigin = 0; 829615Sbill borigin = 0; 830615Sbill 831615Sbill p_etext = *slookup("_etext"); 832615Sbill p_edata = *slookup("_edata"); 833615Sbill p_end = *slookup("_end"); 834615Sbill /* 835615Sbill * If there are any undefined symbols, save the relocation bits. 836615Sbill */ 837615Sbill nsymt = symx(nextsym); 838615Sbill if (rflag==0) { 839615Sbill for (i = 0; i < nsymt; i++) { 840615Sbill sp = xsym(i); 841615Sbill if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 && 842650Sbill sp!=p_end && sp!=p_edata && sp!=p_etext) { 843615Sbill rflag++; 844615Sbill dflag = 0; 845615Sbill break; 846615Sbill } 847615Sbill } 848615Sbill } 849615Sbill if (rflag) 850615Sbill sflag = zflag = 0; 851615Sbill /* 852615Sbill * Assign common locations. 853615Sbill */ 854615Sbill csize = 0; 855615Sbill if (!Aflag) 856615Sbill addsym = symseg[0].sy_first; 857615Sbill database = round(tsize+textbase, 858615Sbill (nflag||zflag? PAGSIZ : sizeof (long))); 859615Sbill database += hsize; 860615Sbill if (dflag || rflag==0) { 861615Sbill ldrsym(p_etext, tsize, N_EXT+N_TEXT); 862615Sbill ldrsym(p_edata, dsize, N_EXT+N_DATA); 863615Sbill ldrsym(p_end, bsize, N_EXT+N_BSS); 864615Sbill for (i = symx(addsym); i < nsymt; i++) { 865615Sbill sp = xsym(i); 866615Sbill if ((s=sp->n_type)==N_EXT+N_UNDF && 867615Sbill (t = sp->n_value)!=0) { 868615Sbill if (t >= sizeof (double)) 869615Sbill rnd = sizeof (double); 870615Sbill else if (t >= sizeof (long)) 871615Sbill rnd = sizeof (long); 872615Sbill else 873615Sbill rnd = sizeof (short); 874615Sbill csize = round(csize, rnd); 875615Sbill sp->n_value = csize; 876615Sbill sp->n_type = N_EXT+N_COMM; 877615Sbill ocsize = csize; 878615Sbill csize += t; 879615Sbill } 880615Sbill if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) { 881615Sbill sp->n_value = ocsize; 882615Sbill sp->n_type = (s&N_STAB) | (N_EXT+N_COMM); 883615Sbill } 884615Sbill } 885615Sbill } 886615Sbill /* 887615Sbill * Now set symbols to their final value 888615Sbill */ 889615Sbill csize = round(csize, sizeof (long)); 890615Sbill torigin = textbase; 891615Sbill dorigin = database; 892615Sbill corigin = dorigin + dsize; 893615Sbill borigin = corigin + csize; 894615Sbill nund = 0; 895615Sbill nsymt = symx(nextsym); 896615Sbill for (i = symx(addsym); i<nsymt; i++) { 897615Sbill sp = xsym(i); 898615Sbill switch (sp->n_type & (N_TYPE+N_EXT)) { 899615Sbill 900615Sbill case N_EXT+N_UNDF: 9012369Skre if (arflag == 0) 9022369Skre errlev |= 01; 903615Sbill if ((arflag==0 || dflag) && sp->n_value==0) { 904650Sbill if (sp==p_end || sp==p_etext || sp==p_edata) 905650Sbill continue; 906615Sbill if (nund==0) 907615Sbill printf("Undefined:\n"); 908615Sbill nund++; 909615Sbill printf("%s\n", sp->n_un.n_name); 910615Sbill } 911615Sbill continue; 912615Sbill case N_EXT+N_ABS: 913615Sbill default: 914615Sbill continue; 915615Sbill case N_EXT+N_TEXT: 916615Sbill sp->n_value += torigin; 917615Sbill continue; 918615Sbill case N_EXT+N_DATA: 919615Sbill sp->n_value += dorigin; 920615Sbill continue; 921615Sbill case N_EXT+N_BSS: 922615Sbill sp->n_value += borigin; 923615Sbill continue; 924615Sbill case N_EXT+N_COMM: 925615Sbill sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS); 926615Sbill sp->n_value += corigin; 927615Sbill continue; 928615Sbill } 929615Sbill } 930615Sbill if (sflag || xflag) 931615Sbill ssize = 0; 932615Sbill bsize += csize; 933615Sbill nsym = ssize / (sizeof cursym); 934615Sbill if (Aflag) { 935615Sbill fixspec(p_etext,torigin); 936615Sbill fixspec(p_edata,dorigin); 937615Sbill fixspec(p_end,borigin); 938615Sbill } 939615Sbill } 940615Sbill 941615Sbill fixspec(sym,offset) 942615Sbill struct nlist *sym; 943615Sbill long offset; 944615Sbill { 945615Sbill 946615Sbill if(symx(sym) < symx(addsym) && sym!=0) 947615Sbill sym->n_value += offset; 948615Sbill } 949615Sbill 950615Sbill ldrsym(sp, val, type) 951615Sbill register struct nlist *sp; 952615Sbill long val; 953615Sbill { 954615Sbill 955615Sbill if (sp == 0) 956615Sbill return; 957615Sbill if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) { 958615Sbill printf("%s: ", sp->n_un.n_name); 959615Sbill error(0, "user attempt to redfine loader-defined symbol"); 960615Sbill return; 961615Sbill } 962615Sbill sp->n_type = type; 963615Sbill sp->n_value = val; 964615Sbill } 965615Sbill 966615Sbill off_t wroff; 967615Sbill struct biobuf toutb; 968615Sbill 969615Sbill setupout() 970615Sbill { 971615Sbill int bss; 972898Sbill extern char *sys_errlist[]; 973898Sbill extern int errno; 974615Sbill 975*3606Ssklower ofilemode = 0777 & ~umask(0); 976*3606Ssklower biofd = creat(ofilename, 0666 & ofilemode); 977898Sbill if (biofd < 0) { 978898Sbill filname = ofilename; /* kludge */ 979898Sbill archdr.ar_name[0] = 0; /* kludge */ 980898Sbill error(1, sys_errlist[errno]); /* kludge */ 981*3606Ssklower } else { 982*3606Ssklower struct stat mybuf; /* kls kludge */ 983*3606Ssklower fstat(biofd, &mybuf); /* suppose file exists, wrong*/ 984*3606Ssklower if(mybuf.st_mode & 0111) { /* mode, ld fails? */ 985*3606Ssklower chmod(ofilename, mybuf.st_mode & 0666); 986*3606Ssklower ofilemode = mybuf.st_mode; 987*3606Ssklower } 988898Sbill } 989615Sbill tout = &toutb; 990615Sbill bopen(tout, 0); 991615Sbill filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC); 992615Sbill filhdr.a_text = nflag ? tsize : 993615Sbill round(tsize, zflag ? PAGSIZ : sizeof (long)); 994615Sbill filhdr.a_data = zflag ? round(dsize, PAGSIZ) : dsize; 995615Sbill bss = bsize - (filhdr.a_data - dsize); 996615Sbill if (bss < 0) 997615Sbill bss = 0; 998615Sbill filhdr.a_bss = bss; 999615Sbill filhdr.a_trsize = trsize; 1000615Sbill filhdr.a_drsize = drsize; 1001615Sbill filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym)); 1002615Sbill if (entrypt) { 1003615Sbill if (entrypt->n_type!=N_EXT+N_TEXT) 1004615Sbill error(0, "entry point not in text"); 1005615Sbill else 1006615Sbill filhdr.a_entry = entrypt->n_value; 1007615Sbill } else 1008615Sbill filhdr.a_entry = 0; 1009615Sbill filhdr.a_trsize = (rflag ? trsize:0); 1010615Sbill filhdr.a_drsize = (rflag ? drsize:0); 1011615Sbill bwrite((char *)&filhdr, sizeof (filhdr), tout); 1012615Sbill if (zflag) { 1013615Sbill bflush1(tout); 1014615Sbill biobufs = 0; 1015615Sbill bopen(tout, PAGSIZ); 1016615Sbill } 1017615Sbill wroff = N_TXTOFF(filhdr) + filhdr.a_text; 1018615Sbill outb(&dout, filhdr.a_data); 1019615Sbill if (rflag) { 1020615Sbill outb(&trout, filhdr.a_trsize); 1021615Sbill outb(&drout, filhdr.a_drsize); 1022615Sbill } 1023615Sbill if (sflag==0 || xflag==0) { 1024615Sbill outb(&sout, filhdr.a_syms); 1025615Sbill wroff += sizeof (offset); 1026615Sbill outb(&strout, 0); 1027615Sbill } 1028615Sbill } 1029615Sbill 1030615Sbill outb(bp, inc) 1031615Sbill register struct biobuf **bp; 1032615Sbill { 1033615Sbill 1034615Sbill *bp = (struct biobuf *)malloc(sizeof (struct biobuf)); 1035615Sbill if (*bp == 0) 1036615Sbill error(1, "ran out of memory (outb)"); 1037615Sbill bopen(*bp, wroff); 1038615Sbill wroff += inc; 1039615Sbill } 1040615Sbill 1041615Sbill load2arg(acp) 1042615Sbill char *acp; 1043615Sbill { 1044615Sbill register char *cp; 1045615Sbill off_t loc; 1046615Sbill 1047615Sbill cp = acp; 1048615Sbill if (getfile(cp) == 0) { 1049615Sbill while (*cp) 1050615Sbill cp++; 1051615Sbill while (cp >= acp && *--cp != '/'); 1052615Sbill mkfsym(++cp); 1053615Sbill load2(0L); 1054615Sbill } else { /* scan archive members referenced */ 1055615Sbill for (;;) { 1056615Sbill if (clibseg->li_used2 == clibseg->li_used) { 1057615Sbill if (clibseg->li_used < NROUT) 1058615Sbill error(1, "libseg botch"); 1059615Sbill clibseg++; 1060615Sbill } 1061615Sbill loc = clibseg->li_first[clibseg->li_used2++]; 1062615Sbill if (loc == -1) 1063615Sbill break; 1064615Sbill dseek(&text, loc, (long)sizeof(archdr)); 1065615Sbill getarhdr(); 1066615Sbill mkfsym(archdr.ar_name); 1067615Sbill load2(loc + (long)sizeof(archdr)); 1068615Sbill } 1069615Sbill } 1070615Sbill close(infil); 1071615Sbill } 1072615Sbill 1073615Sbill load2(loc) 1074615Sbill long loc; 1075615Sbill { 1076615Sbill int size; 1077615Sbill register struct nlist *sp; 1078615Sbill register struct local *lp; 1079615Sbill register int symno, i; 1080615Sbill int type; 1081615Sbill 1082615Sbill readhdr(loc); 1083650Sbill if (!funding) { 1084615Sbill ctrel = torigin; 1085615Sbill cdrel += dorigin; 1086615Sbill cbrel += borigin; 1087615Sbill } 1088615Sbill /* 1089615Sbill * Reread the symbol table, recording the numbering 1090615Sbill * of symbols for fixing external references. 1091615Sbill */ 1092615Sbill for (i = 0; i < LHSIZ; i++) 1093615Sbill lochash[i] = 0; 1094615Sbill clocseg = locseg; 1095615Sbill clocseg->lo_used = 0; 1096615Sbill symno = -1; 1097615Sbill loc += N_TXTOFF(filhdr); 1098615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1099615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t)); 1100615Sbill mget(&size, sizeof(size), &text); 1101615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1102615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t), 1103615Sbill size - sizeof(off_t)); 1104615Sbill curstr = (char *)malloc(size); 1105615Sbill if (curstr == NULL) 1106615Sbill error(1, "out of space reading string table (pass 2)"); 1107615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &text); 1108615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1109615Sbill filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms); 1110615Sbill while (text.size > 0) { 1111615Sbill symno++; 1112615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 1113615Sbill if (cursym.n_un.n_strx) { 1114615Sbill if (cursym.n_un.n_strx<sizeof(size) || 1115615Sbill cursym.n_un.n_strx>=size) 1116615Sbill error(1, "bad string table index (pass 2)"); 1117615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 1118615Sbill } 1119615Sbill /* inline expansion of symreloc() */ 1120615Sbill switch (cursym.n_type & 017) { 1121615Sbill 1122615Sbill case N_TEXT: 1123615Sbill case N_EXT+N_TEXT: 1124615Sbill cursym.n_value += ctrel; 1125615Sbill break; 1126615Sbill case N_DATA: 1127615Sbill case N_EXT+N_DATA: 1128615Sbill cursym.n_value += cdrel; 1129615Sbill break; 1130615Sbill case N_BSS: 1131615Sbill case N_EXT+N_BSS: 1132615Sbill cursym.n_value += cbrel; 1133615Sbill break; 1134615Sbill case N_EXT+N_UNDF: 1135615Sbill break; 1136615Sbill default: 1137615Sbill if (cursym.n_type&N_EXT) 1138615Sbill cursym.n_type = N_EXT+N_ABS; 1139615Sbill } 1140615Sbill /* end inline expansion of symreloc() */ 1141615Sbill type = cursym.n_type; 1142898Sbill if (yflag && cursym.n_un.n_name) 1143898Sbill for (i = 0; i < yflag; i++) 1144898Sbill /* fast check for 2d character! */ 1145898Sbill if (ytab[i][1] == cursym.n_un.n_name[1] && 1146898Sbill !strcmp(ytab[i], cursym.n_un.n_name)) { 1147898Sbill tracesym(); 1148898Sbill break; 1149898Sbill } 1150615Sbill if ((type&N_EXT) == 0) { 1151615Sbill if (!sflag&&!xflag&& 1152615Sbill (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB)) 1153615Sbill symwrite(&cursym, sout); 1154615Sbill continue; 1155615Sbill } 1156615Sbill if (funding) 1157615Sbill continue; 1158615Sbill if ((sp = *lookup()) == 0) 1159615Sbill error(1, "internal error: symbol not found"); 1160615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 1161615Sbill if (clocseg->lo_used == NSYMPR) { 1162615Sbill if (++clocseg == &locseg[NSEG]) 1163615Sbill error(1, "local symbol overflow"); 1164615Sbill clocseg->lo_used = 0; 1165615Sbill } 1166615Sbill if (clocseg->lo_first == 0) { 1167615Sbill clocseg->lo_first = (struct local *) 1168615Sbill malloc(NSYMPR * sizeof (struct local)); 1169615Sbill if (clocseg->lo_first == 0) 1170615Sbill error(1, "out of memory (clocseg)"); 1171615Sbill } 1172615Sbill lp = &clocseg->lo_first[clocseg->lo_used++]; 1173615Sbill lp->l_index = symno; 1174615Sbill lp->l_symbol = sp; 1175615Sbill lp->l_link = lochash[symno % LHSIZ]; 1176615Sbill lochash[symno % LHSIZ] = lp; 1177615Sbill continue; 1178615Sbill } 1179615Sbill if (cursym.n_type & N_STAB) 1180615Sbill continue; 1181615Sbill if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) { 1182615Sbill printf("%s: ", cursym.n_un.n_name); 1183615Sbill error(0, "multiply defined"); 1184615Sbill } 1185615Sbill } 1186615Sbill if (funding) 1187615Sbill return; 1188615Sbill dseek(&text, loc, filhdr.a_text); 1189615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize); 1190650Sbill load2td(ctrel, torigin - textbase, tout, trout); 1191615Sbill dseek(&text, loc+filhdr.a_text, filhdr.a_data); 1192615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, 1193615Sbill filhdr.a_drsize); 1194650Sbill load2td(cdrel, dorigin - database, dout, drout); 1195615Sbill while (filhdr.a_data & (sizeof(long)-1)) { 1196615Sbill bputc(0, dout); 1197615Sbill filhdr.a_data++; 1198615Sbill } 1199615Sbill torigin += filhdr.a_text; 12001752Sbill dorigin += round(filhdr.a_data, sizeof (long)); 12011752Sbill borigin += round(filhdr.a_bss, sizeof (long)); 1202615Sbill free(curstr); 1203615Sbill } 1204615Sbill 1205898Sbill struct tynames { 1206898Sbill int ty_value; 1207898Sbill char *ty_name; 1208898Sbill } tynames[] = { 1209898Sbill N_UNDF, "undefined", 1210898Sbill N_ABS, "absolute", 1211898Sbill N_TEXT, "text", 1212898Sbill N_DATA, "data", 1213898Sbill N_BSS, "bss", 1214898Sbill N_COMM, "common", 1215898Sbill 0, 0, 1216898Sbill }; 1217898Sbill 1218898Sbill tracesym() 1219898Sbill { 1220898Sbill register struct tynames *tp; 1221898Sbill 1222898Sbill if (cursym.n_type & N_STAB) 1223898Sbill return; 1224898Sbill printf("%s", filname); 1225898Sbill if (archdr.ar_name[0]) 1226898Sbill printf("(%s)", archdr.ar_name); 1227898Sbill printf(": "); 1228898Sbill if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) { 1229898Sbill printf("definition of common %s size %d\n", 1230898Sbill cursym.n_un.n_name, cursym.n_value); 1231898Sbill return; 1232898Sbill } 1233898Sbill for (tp = tynames; tp->ty_name; tp++) 1234898Sbill if (tp->ty_value == (cursym.n_type&N_TYPE)) 1235898Sbill break; 1236898Sbill printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to"); 1237898Sbill if (cursym.n_type&N_EXT) 1238898Sbill printf(" external"); 1239898Sbill if (tp->ty_name) 1240898Sbill printf(" %s", tp->ty_name); 1241898Sbill printf(" %s\n", cursym.n_un.n_name); 1242898Sbill } 1243898Sbill 1244650Sbill /* 1245650Sbill * This routine relocates the single text or data segment argument. 1246650Sbill * Offsets from external symbols are resolved by adding the value 1247650Sbill * of the external symbols. Non-external reference are updated to account 1248650Sbill * for the relative motion of the segments (ctrel, cdrel, ...). If 1249650Sbill * a relocation was pc-relative, then we update it to reflect the 1250650Sbill * change in the positioning of the segments by adding the displacement 1251650Sbill * of the referenced segment and subtracting the displacement of the 1252650Sbill * current segment (creloc). 1253650Sbill * 1254650Sbill * If we are saving the relocation information, then we increase 1255650Sbill * each relocation datum address by our base position in the new segment. 1256650Sbill */ 1257650Sbill load2td(creloc, position, b1, b2) 1258650Sbill long creloc, offset; 1259615Sbill struct biobuf *b1, *b2; 1260615Sbill { 1261615Sbill register struct nlist *sp; 1262615Sbill register struct local *lp; 1263615Sbill long tw; 1264615Sbill register struct relocation_info *rp, *rpend; 1265615Sbill struct relocation_info *relp; 1266615Sbill char *codep; 1267615Sbill register char *cp; 1268615Sbill int relsz, codesz; 1269615Sbill 1270615Sbill relsz = reloc.size; 1271615Sbill relp = (struct relocation_info *)malloc(relsz); 1272615Sbill codesz = text.size; 1273615Sbill codep = (char *)malloc(codesz); 1274615Sbill if (relp == 0 || codep == 0) 1275615Sbill error(1, "out of memory (load2td)"); 1276615Sbill mget((char *)relp, relsz, &reloc); 1277615Sbill rpend = &relp[relsz / sizeof (struct relocation_info)]; 1278615Sbill mget(codep, codesz, &text); 1279615Sbill for (rp = relp; rp < rpend; rp++) { 1280615Sbill cp = codep + rp->r_address; 1281650Sbill /* 1282650Sbill * Pick up previous value at location to be relocated. 1283650Sbill */ 1284615Sbill switch (rp->r_length) { 1285615Sbill 1286615Sbill case 0: /* byte */ 1287615Sbill tw = *cp; 1288615Sbill break; 1289615Sbill 1290615Sbill case 1: /* word */ 1291615Sbill tw = *(short *)cp; 1292615Sbill break; 1293615Sbill 1294615Sbill case 2: /* long */ 1295615Sbill tw = *(long *)cp; 1296615Sbill break; 1297615Sbill 1298615Sbill default: 1299615Sbill error(1, "load2td botch: bad length"); 1300615Sbill } 1301650Sbill /* 1302650Sbill * If relative to an external which is defined, 1303650Sbill * resolve to a simpler kind of reference in the 1304650Sbill * result file. If the external is undefined, just 1305650Sbill * convert the symbol number to the number of the 1306650Sbill * symbol in the result file and leave it undefined. 1307650Sbill */ 1308615Sbill if (rp->r_extern) { 1309650Sbill /* 1310650Sbill * Search the hash table which maps local 1311650Sbill * symbol numbers to symbol tables entries 1312650Sbill * in the new a.out file. 1313650Sbill */ 1314615Sbill lp = lochash[rp->r_symbolnum % LHSIZ]; 1315615Sbill while (lp->l_index != rp->r_symbolnum) { 1316615Sbill lp = lp->l_link; 1317615Sbill if (lp == 0) 1318615Sbill error(1, "local symbol botch"); 1319615Sbill } 1320615Sbill sp = lp->l_symbol; 1321615Sbill if (sp->n_type == N_EXT+N_UNDF) 1322615Sbill rp->r_symbolnum = nsym+symx(sp); 1323615Sbill else { 1324615Sbill rp->r_symbolnum = sp->n_type & N_TYPE; 1325615Sbill tw += sp->n_value; 1326615Sbill rp->r_extern = 0; 1327615Sbill } 1328615Sbill } else switch (rp->r_symbolnum & N_TYPE) { 1329650Sbill /* 1330650Sbill * Relocation is relative to the loaded position 1331650Sbill * of another segment. Update by the change in position 1332650Sbill * of that segment. 1333650Sbill */ 1334615Sbill case N_TEXT: 1335615Sbill tw += ctrel; 1336615Sbill break; 1337615Sbill case N_DATA: 1338615Sbill tw += cdrel; 1339615Sbill break; 1340615Sbill case N_BSS: 1341615Sbill tw += cbrel; 1342615Sbill break; 1343615Sbill case N_ABS: 1344615Sbill break; 1345615Sbill default: 1346615Sbill error(1, "relocation format botch (symbol type))"); 1347615Sbill } 1348650Sbill /* 1349650Sbill * Relocation is pc relative, so decrease the relocation 1350650Sbill * by the amount the current segment is displaced. 1351650Sbill * (E.g if we are a relative reference to a text location 1352650Sbill * from data space, we added the increase in the text address 1353650Sbill * above, and subtract the increase in our (data) address 1354650Sbill * here, leaving the net change the relative change in the 1355650Sbill * positioning of our text and data segments.) 1356650Sbill */ 1357615Sbill if (rp->r_pcrel) 1358615Sbill tw -= creloc; 1359650Sbill /* 1360650Sbill * Put the value back in the segment, 1361650Sbill * while checking for overflow. 1362650Sbill */ 1363615Sbill switch (rp->r_length) { 1364615Sbill 1365615Sbill case 0: /* byte */ 1366615Sbill if (tw < -128 || tw > 127) 1367615Sbill error(0, "byte displacement overflow"); 1368615Sbill *cp = tw; 1369615Sbill break; 1370615Sbill case 1: /* word */ 1371615Sbill if (tw < -32768 || tw > 32767) 1372615Sbill error(0, "word displacement overflow"); 1373615Sbill *(short *)cp = tw; 1374615Sbill break; 1375615Sbill case 2: /* long */ 1376615Sbill *(long *)cp = tw; 1377615Sbill break; 1378615Sbill } 1379650Sbill /* 1380650Sbill * If we are saving relocation information, 1381650Sbill * we must convert the address in the segment from 1382650Sbill * the old .o file into an address in the segment in 1383650Sbill * the new a.out, by adding the position of our 1384650Sbill * segment in the new larger segment. 1385650Sbill */ 1386615Sbill if (rflag) 1387650Sbill rp->r_address += position; 1388615Sbill } 1389615Sbill bwrite(codep, codesz, b1); 1390615Sbill if (rflag) 1391615Sbill bwrite(relp, relsz, b2); 1392615Sbill cfree((char *)relp); 1393615Sbill cfree(codep); 1394615Sbill } 1395615Sbill 1396615Sbill finishout() 1397615Sbill { 1398615Sbill register int i; 1399615Sbill int nsymt; 1400615Sbill 1401615Sbill if (sflag==0) { 1402615Sbill nsymt = symx(nextsym); 1403615Sbill for (i = 0; i < nsymt; i++) 1404615Sbill symwrite(xsym(i), sout); 1405615Sbill bwrite(&offset, sizeof offset, sout); 1406615Sbill } 1407615Sbill if (!ofilfnd) { 1408615Sbill unlink("a.out"); 1409898Sbill if (link("l.out", "a.out") < 0) 1410898Sbill error(1, "cannot move l.out to a.out"); 1411615Sbill ofilename = "a.out"; 1412615Sbill } 1413615Sbill delarg = errlev; 1414615Sbill delexit(); 1415615Sbill } 1416615Sbill 1417615Sbill mkfsym(s) 1418615Sbill char *s; 1419615Sbill { 1420615Sbill 1421615Sbill if (sflag || xflag) 1422615Sbill return; 1423615Sbill cursym.n_un.n_name = s; 1424615Sbill cursym.n_type = N_TEXT; 1425615Sbill cursym.n_value = torigin; 1426615Sbill symwrite(&cursym, sout); 1427615Sbill } 1428615Sbill 1429615Sbill getarhdr() 1430615Sbill { 1431615Sbill register char *cp; 1432615Sbill 1433615Sbill mget((char *)&archdr, sizeof archdr, &text); 1434615Sbill for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];) 1435615Sbill if (*cp++ == ' ') { 1436615Sbill cp[-1] = 0; 1437615Sbill return; 1438615Sbill } 1439615Sbill } 1440615Sbill 1441615Sbill mget(loc, n, sp) 1442615Sbill register STREAM *sp; 1443615Sbill register char *loc; 1444615Sbill { 1445615Sbill register char *p; 1446615Sbill register int take; 1447615Sbill 1448615Sbill top: 1449615Sbill if (n == 0) 1450615Sbill return; 1451615Sbill if (sp->size && sp->nibuf) { 1452615Sbill p = sp->ptr; 1453615Sbill take = sp->size; 1454615Sbill if (take > sp->nibuf) 1455615Sbill take = sp->nibuf; 1456615Sbill if (take > n) 1457615Sbill take = n; 1458615Sbill n -= take; 1459615Sbill sp->size -= take; 1460615Sbill sp->nibuf -= take; 1461615Sbill sp->pos += take; 1462615Sbill do 1463615Sbill *loc++ = *p++; 1464615Sbill while (--take > 0); 1465615Sbill sp->ptr = p; 1466615Sbill goto top; 1467615Sbill } 1468615Sbill if (n > BUFSIZ) { 1469615Sbill take = n - n % BSIZE; 1470615Sbill lseek(infil, (sp->bno+1)*BSIZE, 0); 1471615Sbill if (take > sp->size || read(infil, loc, take) != take) 1472615Sbill error(1, "premature EOF"); 1473615Sbill loc += take; 1474615Sbill n -= take; 1475615Sbill sp->size -= take; 1476615Sbill sp->pos += take; 1477615Sbill dseek(sp, (sp->bno+1+take/BSIZE)*BSIZE, -1); 1478615Sbill goto top; 1479615Sbill } 1480615Sbill *loc++ = get(sp); 1481615Sbill --n; 1482615Sbill goto top; 1483615Sbill } 1484615Sbill 1485615Sbill symwrite(sp, bp) 1486615Sbill struct nlist *sp; 1487615Sbill struct biobuf *bp; 1488615Sbill { 1489615Sbill register int len; 1490615Sbill register char *str; 1491615Sbill 1492615Sbill str = sp->n_un.n_name; 1493615Sbill if (str) { 1494615Sbill sp->n_un.n_strx = offset; 1495615Sbill len = strlen(str) + 1; 1496615Sbill bwrite(str, len, strout); 1497615Sbill offset += len; 1498615Sbill } 1499615Sbill bwrite(sp, sizeof (*sp), bp); 1500615Sbill sp->n_un.n_name = str; 1501615Sbill } 1502615Sbill 1503615Sbill dseek(sp, loc, s) 1504615Sbill register STREAM *sp; 1505615Sbill long loc, s; 1506615Sbill { 1507615Sbill register PAGE *p; 1508615Sbill register b, o; 1509615Sbill int n; 1510615Sbill 1511615Sbill b = loc>>BSHIFT; 1512615Sbill o = loc&BMASK; 1513615Sbill if (o&01) 1514615Sbill error(1, "loader error; odd offset"); 1515615Sbill --sp->pno->nuser; 1516615Sbill if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b) 1517615Sbill if (p->nuser==0 || (p = &page[0])->nuser==0) { 1518615Sbill if (page[0].nuser==0 && page[1].nuser==0) 1519615Sbill if (page[0].bno < page[1].bno) 1520615Sbill p = &page[0]; 1521615Sbill p->bno = b; 1522615Sbill lseek(infil, loc & ~(long)BMASK, 0); 1523615Sbill if ((n = read(infil, p->buff, sizeof(p->buff))) < 0) 1524615Sbill n = 0; 1525615Sbill p->nibuf = n; 1526615Sbill } else 1527615Sbill error(1, "botch: no pages"); 1528615Sbill ++p->nuser; 1529615Sbill sp->bno = b; 1530615Sbill sp->pno = p; 1531615Sbill if (s != -1) {sp->size = s; sp->pos = 0;} 1532615Sbill sp->ptr = (char *)(p->buff + o); 1533615Sbill if ((sp->nibuf = p->nibuf-o) <= 0) 1534615Sbill sp->size = 0; 1535615Sbill } 1536615Sbill 1537615Sbill char 1538615Sbill get(asp) 1539615Sbill STREAM *asp; 1540615Sbill { 1541615Sbill register STREAM *sp; 1542615Sbill 1543615Sbill sp = asp; 1544615Sbill if ((sp->nibuf -= sizeof(char)) < 0) { 1545615Sbill dseek(sp, ((long)(sp->bno+1)<<BSHIFT), (long)-1); 1546615Sbill sp->nibuf -= sizeof(char); 1547615Sbill } 1548615Sbill if ((sp->size -= sizeof(char)) <= 0) { 1549615Sbill if (sp->size < 0) 1550615Sbill error(1, "premature EOF"); 1551615Sbill ++fpage.nuser; 1552615Sbill --sp->pno->nuser; 1553615Sbill sp->pno = (PAGE *) &fpage; 1554615Sbill } 1555615Sbill sp->pos += sizeof(char); 1556615Sbill return(*sp->ptr++); 1557615Sbill } 1558615Sbill 1559615Sbill getfile(acp) 1560615Sbill char *acp; 1561615Sbill { 1562615Sbill register char *cp; 1563615Sbill register int c; 1564615Sbill char arcmag[SARMAG+1]; 1565615Sbill struct stat stb; 1566615Sbill 1567615Sbill cp = acp; 1568615Sbill infil = -1; 1569615Sbill archdr.ar_name[0] = '\0'; 1570615Sbill filname = cp; 1571615Sbill if (cp[0]=='-' && cp[1]=='l') { 1572898Sbill char *locfilname = "/usr/local/lib/libxxxxxxxxxxxxxxx"; 1573615Sbill if(cp[2] == '\0') 1574615Sbill cp = "-la"; 1575898Sbill filname = "/usr/lib/libxxxxxxxxxxxxxxx"; 1576615Sbill for(c=0; cp[c+2]; c++) { 1577615Sbill filname[c+12] = cp[c+2]; 1578615Sbill locfilname[c+18] = cp[c+2]; 1579615Sbill } 1580615Sbill filname[c+12] = locfilname[c+18] = '.'; 1581615Sbill filname[c+13] = locfilname[c+19] = 'a'; 1582615Sbill filname[c+14] = locfilname[c+20] = '\0'; 1583615Sbill if ((infil = open(filname+4, 0)) >= 0) { 1584615Sbill filname += 4; 1585615Sbill } else if ((infil = open(filname, 0)) < 0) { 1586615Sbill filname = locfilname; 1587615Sbill } 1588615Sbill } 1589615Sbill if (infil == -1 && (infil = open(filname, 0)) < 0) 1590615Sbill error(1, "cannot open"); 1591615Sbill page[0].bno = page[1].bno = -1; 1592615Sbill page[0].nuser = page[1].nuser = 0; 1593615Sbill text.pno = reloc.pno = (PAGE *) &fpage; 1594615Sbill fpage.nuser = 2; 1595615Sbill dseek(&text, 0L, SARMAG); 1596615Sbill if (text.size <= 0) 1597615Sbill error(1, "premature EOF"); 1598615Sbill mget((char *)arcmag, SARMAG, &text); 1599615Sbill arcmag[SARMAG] = 0; 1600615Sbill if (strcmp(arcmag, ARMAG)) 1601615Sbill return (0); 1602615Sbill dseek(&text, SARMAG, sizeof archdr); 1603615Sbill if(text.size <= 0) 1604615Sbill return (1); 1605615Sbill getarhdr(); 1606615Sbill if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0) 1607615Sbill return (1); 1608615Sbill fstat(infil, &stb); 1609615Sbill return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2); 1610615Sbill } 1611615Sbill 1612615Sbill struct nlist ** 1613615Sbill lookup() 1614615Sbill { 1615615Sbill register int sh; 1616615Sbill register struct nlist **hp; 1617615Sbill register char *cp, *cp1; 1618615Sbill register struct symseg *gp; 1619615Sbill register int i; 1620615Sbill 1621615Sbill sh = 0; 1622615Sbill for (cp = cursym.n_un.n_name; *cp;) 1623615Sbill sh = (sh<<1) + *cp++; 1624615Sbill sh = (sh & 0x7fffffff) % HSIZE; 1625615Sbill for (gp = symseg; gp < &symseg[NSEG]; gp++) { 1626615Sbill if (gp->sy_first == 0) { 1627615Sbill gp->sy_first = (struct nlist *) 1628615Sbill calloc(NSYM, sizeof (struct nlist)); 1629615Sbill gp->sy_hfirst = (struct nlist **) 1630615Sbill calloc(HSIZE, sizeof (struct nlist *)); 1631615Sbill if (gp->sy_first == 0 || gp->sy_hfirst == 0) 1632615Sbill error(1, "ran out of space for symbol table"); 1633615Sbill gp->sy_last = gp->sy_first + NSYM; 1634615Sbill gp->sy_hlast = gp->sy_hfirst + HSIZE; 1635615Sbill } 1636615Sbill if (gp > csymseg) 1637615Sbill csymseg = gp; 1638615Sbill hp = gp->sy_hfirst + sh; 1639615Sbill i = 1; 1640615Sbill do { 1641615Sbill if (*hp == 0) { 1642615Sbill if (gp->sy_used == NSYM) 1643615Sbill break; 1644615Sbill return (hp); 1645615Sbill } 1646615Sbill cp1 = (*hp)->n_un.n_name; 1647615Sbill for (cp = cursym.n_un.n_name; *cp == *cp1++;) 1648615Sbill if (*cp++ == 0) 1649615Sbill return (hp); 1650615Sbill hp += i; 1651615Sbill i += 2; 1652615Sbill if (hp >= gp->sy_hlast) 1653615Sbill hp -= HSIZE; 1654615Sbill } while (i < HSIZE); 1655615Sbill if (i > HSIZE) 1656615Sbill error(1, "hash table botch"); 1657615Sbill } 1658615Sbill error(1, "symbol table overflow"); 1659615Sbill /*NOTREACHED*/ 1660615Sbill } 1661615Sbill 1662615Sbill symfree(saved) 1663615Sbill struct nlist *saved; 1664615Sbill { 1665615Sbill register struct symseg *gp; 1666615Sbill register struct nlist *sp; 1667615Sbill 1668615Sbill for (gp = csymseg; gp >= symseg; gp--, csymseg--) { 1669615Sbill sp = gp->sy_first + gp->sy_used; 1670615Sbill if (sp == saved) { 1671615Sbill nextsym = sp; 1672615Sbill return; 1673615Sbill } 1674615Sbill for (sp--; sp >= gp->sy_first; sp--) { 1675615Sbill gp->sy_hfirst[sp->n_hash] = 0; 1676615Sbill gp->sy_used--; 1677615Sbill if (sp == saved) { 1678615Sbill nextsym = sp; 1679615Sbill return; 1680615Sbill } 1681615Sbill } 1682615Sbill } 1683615Sbill if (saved == 0) 1684615Sbill return; 1685615Sbill error(1, "symfree botch"); 1686615Sbill } 1687615Sbill 1688615Sbill struct nlist ** 1689615Sbill slookup(s) 1690615Sbill char *s; 1691615Sbill { 1692615Sbill 1693615Sbill cursym.n_un.n_name = s; 1694615Sbill cursym.n_type = N_EXT+N_UNDF; 1695615Sbill cursym.n_value = 0; 1696615Sbill return (lookup()); 1697615Sbill } 1698615Sbill 1699615Sbill enter(hp) 1700615Sbill register struct nlist **hp; 1701615Sbill { 1702615Sbill register struct nlist *sp; 1703615Sbill 1704615Sbill if (*hp==0) { 1705615Sbill if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast) 1706615Sbill error(1, "enter botch"); 1707615Sbill *hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used; 1708615Sbill csymseg->sy_used++; 1709615Sbill sp->n_un.n_name = cursym.n_un.n_name; 1710615Sbill sp->n_type = cursym.n_type; 1711615Sbill sp->n_hash = hp - csymseg->sy_hfirst; 1712615Sbill sp->n_value = cursym.n_value; 1713615Sbill nextsym = lastsym + 1; 1714615Sbill return(1); 1715615Sbill } else { 1716615Sbill lastsym = *hp; 1717615Sbill return(0); 1718615Sbill } 1719615Sbill } 1720615Sbill 1721615Sbill symx(sp) 1722615Sbill struct nlist *sp; 1723615Sbill { 1724615Sbill register struct symseg *gp; 1725615Sbill 1726615Sbill if (sp == 0) 1727615Sbill return (0); 1728615Sbill for (gp = csymseg; gp >= symseg; gp--) 1729615Sbill /* <= is sloppy so nextsym will always work */ 1730615Sbill if (sp >= gp->sy_first && sp <= gp->sy_last) 1731615Sbill return ((gp - symseg) * NSYM + sp - gp->sy_first); 1732615Sbill error(1, "symx botch"); 1733615Sbill /*NOTREACHED*/ 1734615Sbill } 1735615Sbill 1736615Sbill symreloc() 1737615Sbill { 1738615Sbill if(funding) return; 1739615Sbill switch (cursym.n_type & 017) { 1740615Sbill 1741615Sbill case N_TEXT: 1742615Sbill case N_EXT+N_TEXT: 1743615Sbill cursym.n_value += ctrel; 1744615Sbill return; 1745615Sbill 1746615Sbill case N_DATA: 1747615Sbill case N_EXT+N_DATA: 1748615Sbill cursym.n_value += cdrel; 1749615Sbill return; 1750615Sbill 1751615Sbill case N_BSS: 1752615Sbill case N_EXT+N_BSS: 1753615Sbill cursym.n_value += cbrel; 1754615Sbill return; 1755615Sbill 1756615Sbill case N_EXT+N_UNDF: 1757615Sbill return; 1758615Sbill 1759615Sbill default: 1760615Sbill if (cursym.n_type&N_EXT) 1761615Sbill cursym.n_type = N_EXT+N_ABS; 1762615Sbill return; 1763615Sbill } 1764615Sbill } 1765615Sbill 1766615Sbill error(n, s) 1767615Sbill char *s; 1768615Sbill { 1769898Sbill 1770615Sbill if (errlev==0) 1771615Sbill printf("ld:"); 1772615Sbill if (filname) { 1773615Sbill printf("%s", filname); 1774615Sbill if (n != -1 && archdr.ar_name[0]) 1775615Sbill printf("(%s)", archdr.ar_name); 1776615Sbill printf(": "); 1777615Sbill } 1778615Sbill printf("%s\n", s); 1779615Sbill if (n == -1) 1780615Sbill return; 1781615Sbill if (n) 1782615Sbill delexit(); 1783615Sbill errlev = 2; 1784615Sbill } 1785615Sbill 1786615Sbill readhdr(loc) 1787615Sbill off_t loc; 1788615Sbill { 1789615Sbill 1790615Sbill dseek(&text, loc, (long)sizeof(filhdr)); 1791615Sbill mget((short *)&filhdr, sizeof(filhdr), &text); 1792615Sbill if (N_BADMAG(filhdr)) { 1793615Sbill if (filhdr.a_magic == OARMAG) 1794615Sbill error(1, "old archive"); 1795615Sbill error(1, "bad magic number"); 1796615Sbill } 1797615Sbill if (filhdr.a_text&01 || filhdr.a_data&01) 1798615Sbill error(1, "text/data size odd"); 1799615Sbill if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) { 1800615Sbill cdrel = -round(filhdr.a_text, PAGSIZ); 1801615Sbill cbrel = cdrel - filhdr.a_data; 1802615Sbill } else if (filhdr.a_magic == OMAGIC) { 1803615Sbill cdrel = -filhdr.a_text; 1804615Sbill cbrel = cdrel - filhdr.a_data; 1805615Sbill } else 1806615Sbill error(1, "bad format"); 1807615Sbill } 1808615Sbill 1809615Sbill round(v, r) 1810615Sbill int v; 1811615Sbill u_long r; 1812615Sbill { 1813615Sbill 1814615Sbill r--; 1815615Sbill v += r; 1816615Sbill v &= ~(long)r; 1817615Sbill return(v); 1818615Sbill } 1819615Sbill 1820615Sbill #define NSAVETAB 8192 1821615Sbill char *savetab; 1822615Sbill int saveleft; 1823615Sbill 1824615Sbill char * 1825615Sbill savestr(cp) 1826615Sbill register char *cp; 1827615Sbill { 1828615Sbill register int len; 1829615Sbill 1830615Sbill len = strlen(cp) + 1; 1831615Sbill if (len > saveleft) { 1832615Sbill saveleft = NSAVETAB; 1833615Sbill if (len > saveleft) 1834615Sbill saveleft = len; 1835615Sbill savetab = (char *)malloc(saveleft); 1836615Sbill if (savetab == 0) 1837615Sbill error(1, "ran out of memory (savestr)"); 1838615Sbill } 1839615Sbill strncpy(savetab, cp, len); 1840615Sbill cp = savetab; 1841615Sbill savetab += len; 1842615Sbill saveleft -= len; 1843615Sbill return (cp); 1844615Sbill } 1845615Sbill 1846615Sbill bopen(bp, off) 1847615Sbill struct biobuf *bp; 1848615Sbill { 1849615Sbill 1850615Sbill bp->b_ptr = bp->b_buf; 1851615Sbill bp->b_nleft = BUFSIZ - off % BUFSIZ; 1852615Sbill bp->b_off = off; 1853615Sbill bp->b_link = biobufs; 1854615Sbill biobufs = bp; 1855615Sbill } 1856615Sbill 1857615Sbill int bwrerror; 1858615Sbill 1859615Sbill bwrite(p, cnt, bp) 1860615Sbill register char *p; 1861615Sbill register int cnt; 1862615Sbill register struct biobuf *bp; 1863615Sbill { 1864615Sbill register int put; 1865615Sbill register char *to; 1866615Sbill 1867615Sbill top: 1868615Sbill if (cnt == 0) 1869615Sbill return; 1870615Sbill if (bp->b_nleft) { 1871615Sbill put = bp->b_nleft; 1872615Sbill if (put > cnt) 1873615Sbill put = cnt; 1874615Sbill bp->b_nleft -= put; 1875615Sbill to = bp->b_ptr; 1876615Sbill asm("movc3 r8,(r11),(r7)"); 1877615Sbill bp->b_ptr += put; 1878615Sbill p += put; 1879615Sbill cnt -= put; 1880615Sbill goto top; 1881615Sbill } 1882615Sbill if (cnt >= BUFSIZ) { 1883615Sbill if (bp->b_ptr != bp->b_buf) 1884615Sbill bflush1(bp); 1885615Sbill put = cnt - cnt % BUFSIZ; 1886615Sbill if (boffset != bp->b_off) 1887615Sbill lseek(biofd, bp->b_off, 0); 1888615Sbill if (write(biofd, p, put) != put) { 1889615Sbill bwrerror = 1; 1890615Sbill error(1, "output write error"); 1891615Sbill } 1892615Sbill bp->b_off += put; 1893615Sbill boffset = bp->b_off; 1894615Sbill p += put; 1895615Sbill cnt -= put; 1896615Sbill goto top; 1897615Sbill } 1898615Sbill bflush1(bp); 1899615Sbill goto top; 1900615Sbill } 1901615Sbill 1902615Sbill bflush() 1903615Sbill { 1904615Sbill register struct biobuf *bp; 1905615Sbill 1906615Sbill if (bwrerror) 1907615Sbill return; 1908615Sbill for (bp = biobufs; bp; bp = bp->b_link) 1909615Sbill bflush1(bp); 1910615Sbill } 1911615Sbill 1912615Sbill bflush1(bp) 1913615Sbill register struct biobuf *bp; 1914615Sbill { 1915615Sbill register int cnt = bp->b_ptr - bp->b_buf; 1916615Sbill 1917615Sbill if (cnt == 0) 1918615Sbill return; 1919615Sbill if (boffset != bp->b_off) 1920615Sbill lseek(biofd, bp->b_off, 0); 1921615Sbill if (write(biofd, bp->b_buf, cnt) != cnt) { 1922615Sbill bwrerror = 1; 1923615Sbill error(1, "output write error"); 1924615Sbill } 1925615Sbill bp->b_off += cnt; 1926615Sbill boffset = bp->b_off; 1927615Sbill bp->b_ptr = bp->b_buf; 1928615Sbill bp->b_nleft = BUFSIZ; 1929615Sbill } 1930615Sbill 1931615Sbill bflushc(bp, c) 1932615Sbill register struct biobuf *bp; 1933615Sbill { 1934615Sbill 1935615Sbill bflush1(bp); 1936615Sbill bputc(c, bp); 1937615Sbill } 1938