112671Ssam #ifndef lint 2*16068Sralph static char sccsid[] = "@(#)ld.c 4.10 02/17/84"; 312671Ssam #endif 46414Smckusic 5615Sbill /* 6898Sbill * ld - string table version for VAX 7615Sbill */ 8615Sbill 9615Sbill #include <sys/types.h> 10615Sbill #include <signal.h> 11615Sbill #include <stdio.h> 12615Sbill #include <ctype.h> 13650Sbill #include <ar.h> 14650Sbill #include <a.out.h> 15615Sbill #include <ranlib.h> 1613591Swnj #include <sys/stat.h> 17615Sbill 18615Sbill /* 19615Sbill * Basic strategy: 20615Sbill * 21615Sbill * The loader takes a number of files and libraries as arguments. 22615Sbill * A first pass examines each file in turn. Normal files are 23615Sbill * unconditionally loaded, and the (external) symbols they define and require 24615Sbill * are noted in the symbol table. Libraries are searched, and the 25615Sbill * library members which define needed symbols are remembered 26615Sbill * in a special data structure so they can be selected on the second 27615Sbill * pass. Symbols defined and required by library members are also 28615Sbill * recorded. 29615Sbill * 30615Sbill * After the first pass, the loader knows the size of the basic text 31615Sbill * data, and bss segments from the sum of the sizes of the modules which 32615Sbill * were required. It has computed, for each ``common'' symbol, the 33615Sbill * maximum size of any reference to it, and these symbols are then assigned 34615Sbill * storage locations after their sizes are appropriately rounded. 35615Sbill * The loader now knows all sizes for the eventual output file, and 36615Sbill * can determine the final locations of external symbols before it 37615Sbill * begins a second pass. 38615Sbill * 39615Sbill * On the second pass each normal file and required library member 40615Sbill * is processed again. The symbol table for each such file is 41615Sbill * reread and relevant parts of it are placed in the output. The offsets 42615Sbill * in the local symbol table for externally defined symbols are recorded 43615Sbill * since relocation information refers to symbols in this way. 44615Sbill * Armed with all necessary information, the text and data segments 45615Sbill * are relocated and the result is placed in the output file, which 46615Sbill * is pasted together, ``in place'', by writing to it in several 47615Sbill * different places concurrently. 48615Sbill */ 49615Sbill 50615Sbill /* 51615Sbill * Internal data structures 52615Sbill * 53615Sbill * All internal data structures are segmented and dynamically extended. 54615Sbill * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT) 55615Sbill * referenced library members, and 100 (NSYMPR) private (local) symbols 56615Sbill * per object module. For large programs and/or modules, these structures 57615Sbill * expand to be up to 40 (NSEG) times as large as this as necessary. 58615Sbill */ 59615Sbill #define NSEG 40 /* Number of segments, each data structure */ 60615Sbill #define NSYM 1103 /* Number of symbols per segment */ 61615Sbill #define NROUT 250 /* Number of library references per segment */ 62615Sbill #define NSYMPR 100 /* Number of private symbols per segment */ 63615Sbill 64615Sbill /* 65615Sbill * Structure describing each symbol table segment. 66615Sbill * Each segment has its own hash table. We record the first 67615Sbill * address in and first address beyond both the symbol and hash 68615Sbill * tables, for use in the routine symx and the lookup routine respectively. 69615Sbill * The symfree routine also understands this structure well as it used 70615Sbill * to back out symbols from modules we decide that we don't need in pass 1. 71615Sbill * 72615Sbill * Csymseg points to the current symbol table segment; 73615Sbill * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated, 74615Sbill * (unless csymseg->sy_used == NSYM in which case we will allocate another 75615Sbill * symbol table segment first.) 76615Sbill */ 77615Sbill struct symseg { 78615Sbill struct nlist *sy_first; /* base of this alloc'ed segment */ 79615Sbill struct nlist *sy_last; /* end of this segment, for n_strx */ 80615Sbill int sy_used; /* symbols used in this seg */ 81615Sbill struct nlist **sy_hfirst; /* base of hash table, this seg */ 82615Sbill struct nlist **sy_hlast; /* end of hash table, this seg */ 83615Sbill } symseg[NSEG], *csymseg; 84615Sbill 85615Sbill /* 86615Sbill * The lookup routine uses quadratic rehash. Since a quadratic rehash 87615Sbill * only probes 1/2 of the buckets in the table, and since the hash 88615Sbill * table is segmented the same way the symbol table is, we make the 89615Sbill * hash table have twice as many buckets as there are symbol table slots 90615Sbill * in the segment. This guarantees that the quadratic rehash will never 91615Sbill * fail to find an empty bucket if the segment is not full and the 92615Sbill * symbol is not there. 93615Sbill */ 94615Sbill #define HSIZE (NSYM*2) 95615Sbill 96615Sbill /* 97615Sbill * Xsym converts symbol table indices (ala x) into symbol table pointers. 98615Sbill * Symx (harder, but never used in loops) inverts pointers into the symbol 99615Sbill * table into indices using the symseg[] structure. 100615Sbill */ 101615Sbill #define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM)) 102615Sbill /* symx() is a function, defined below */ 103615Sbill 104615Sbill struct nlist cursym; /* current symbol */ 105615Sbill struct nlist *lastsym; /* last symbol entered */ 106615Sbill struct nlist *nextsym; /* next available symbol table entry */ 107615Sbill struct nlist *addsym; /* first sym defined during incr load */ 108615Sbill int nsym; /* pass2: number of local symbols in a.out */ 109615Sbill /* nsym + symx(nextsym) is the symbol table size during pass2 */ 110615Sbill 111615Sbill struct nlist **lookup(), **slookup(); 112650Sbill struct nlist *p_etext, *p_edata, *p_end, *entrypt; 113615Sbill 114615Sbill /* 115615Sbill * Definitions of segmentation for library member table. 116615Sbill * For each library we encounter on pass 1 we record pointers to all 117615Sbill * members which we will load on pass 2. These are recorded as offsets 118615Sbill * into the archive in the library member table. Libraries are 119615Sbill * separated in the table by the special offset value -1. 120615Sbill */ 121615Sbill off_t li_init[NROUT]; 122615Sbill struct libseg { 123615Sbill off_t *li_first; 124615Sbill int li_used; 125615Sbill int li_used2; 126615Sbill } libseg[NSEG] = { 127615Sbill li_init, 0, 0, 128615Sbill }, *clibseg = libseg; 129615Sbill 130615Sbill /* 131615Sbill * In processing each module on pass 2 we must relocate references 132615Sbill * relative to external symbols. These references are recorded 133615Sbill * in the relocation information as relative to local symbol numbers 134615Sbill * assigned to the external symbols when the module was created. 135615Sbill * Thus before relocating the module in pass 2 we create a table 136615Sbill * which maps these internal numbers to symbol table entries. 137615Sbill * A hash table is constructed, based on the local symbol table indices, 138615Sbill * for quick lookup of these symbols. 139615Sbill */ 140615Sbill #define LHSIZ 31 141615Sbill struct local { 142615Sbill int l_index; /* index to symbol in file */ 143615Sbill struct nlist *l_symbol; /* ptr to symbol table */ 144615Sbill struct local *l_link; /* hash link */ 145615Sbill } *lochash[LHSIZ], lhinit[NSYMPR]; 146615Sbill struct locseg { 147615Sbill struct local *lo_first; 148615Sbill int lo_used; 149615Sbill } locseg[NSEG] = { 150615Sbill lhinit, 0 151615Sbill }, *clocseg; 152615Sbill 153615Sbill /* 154615Sbill * Libraries are typically built with a table of contents, 155615Sbill * which is the first member of a library with special file 156615Sbill * name __.SYMDEF and contains a list of symbol names 157615Sbill * and with each symbol the offset of the library member which defines 158615Sbill * it. The loader uses this table to quickly tell which library members 159615Sbill * are (potentially) useful. The alternative, examining the symbol 160615Sbill * table of each library member, is painfully slow for large archives. 161615Sbill * 162615Sbill * See <ranlib.h> for the definition of the ranlib structure and an 163615Sbill * explanation of the __.SYMDEF file format. 164615Sbill */ 165615Sbill int tnum; /* number of symbols in table of contents */ 166615Sbill int ssiz; /* size of string table for table of contents */ 167615Sbill struct ranlib *tab; /* the table of contents (dynamically allocated) */ 168615Sbill char *tabstr; /* string table for table of contents */ 169615Sbill 170615Sbill /* 171615Sbill * We open each input file or library only once, but in pass2 we 172615Sbill * (historically) read from such a file at 2 different places at the 173615Sbill * same time. These structures are remnants from those days, 174650Sbill * and now serve only to catch ``Premature EOF''. 1756414Smckusic * In order to make I/O more efficient, we provide routines which 176*16068Sralph * use the optimal block size returned by stat(). 177615Sbill */ 1786414Smckusic #define BLKSIZE 1024 179615Sbill typedef struct { 180615Sbill short *fakeptr; 181615Sbill int bno; 182615Sbill int nibuf; 183615Sbill int nuser; 184*16068Sralph char *buff; 185*16068Sralph int bufsize; 186615Sbill } PAGE; 187615Sbill 188615Sbill PAGE page[2]; 189*16068Sralph int p_blksize; 190*16068Sralph int p_blkshift; 191*16068Sralph int p_blkmask; 192615Sbill 193615Sbill struct { 194615Sbill short *fakeptr; 195615Sbill int bno; 196615Sbill int nibuf; 197615Sbill int nuser; 198615Sbill } fpage; 199615Sbill 200615Sbill typedef struct { 201615Sbill char *ptr; 202615Sbill int bno; 203615Sbill int nibuf; 204615Sbill long size; 205615Sbill long pos; 206615Sbill PAGE *pno; 207615Sbill } STREAM; 208615Sbill 209615Sbill STREAM text; 210615Sbill STREAM reloc; 211615Sbill 212615Sbill /* 213615Sbill * Header from the a.out and the archive it is from (if any). 214615Sbill */ 215615Sbill struct exec filhdr; 216615Sbill struct ar_hdr archdr; 217615Sbill #define OARMAG 0177545 218615Sbill 219615Sbill /* 220615Sbill * Options. 221615Sbill */ 222615Sbill int trace; 223615Sbill int xflag; /* discard local symbols */ 224615Sbill int Xflag; /* discard locals starting with 'L' */ 225615Sbill int Sflag; /* discard all except locals and globals*/ 226615Sbill int rflag; /* preserve relocation bits, don't define common */ 227615Sbill int arflag; /* original copy of rflag */ 228615Sbill int sflag; /* discard all symbols */ 229898Sbill int Mflag; /* print rudimentary load map */ 230615Sbill int nflag; /* pure procedure */ 231615Sbill int dflag; /* define common even with rflag */ 232650Sbill int zflag; /* demand paged */ 233615Sbill long hsize; /* size of hole at beginning of data to be squashed */ 234615Sbill int Aflag; /* doing incremental load */ 235650Sbill int Nflag; /* want impure a.out */ 236615Sbill int funding; /* reading fundamental file for incremental load */ 237898Sbill int yflag; /* number of symbols to be traced */ 238898Sbill char **ytab; /* the symbols */ 239615Sbill 240615Sbill /* 241615Sbill * These are the cumulative sizes, set in pass 1, which 242615Sbill * appear in the a.out header when the loader is finished. 243615Sbill */ 244615Sbill off_t tsize, dsize, bsize, trsize, drsize, ssize; 245615Sbill 246615Sbill /* 247615Sbill * Symbol relocation: c?rel is a scale factor which is 248615Sbill * added to an old relocation to convert it to new units; 249615Sbill * i.e. it is the difference between segment origins. 250650Sbill * (Thus if we are loading from a data segment which began at location 251650Sbill * 4 in a .o file into an a.out where it will be loaded starting at 252650Sbill * 1024, cdrel will be 1020.) 253615Sbill */ 254615Sbill long ctrel, cdrel, cbrel; 255615Sbill 256615Sbill /* 257650Sbill * Textbase is the start address of all text, 0 unless given by -T. 258615Sbill * Database is the base of all data, computed before and used during pass2. 259650Sbill */ 260650Sbill long textbase, database; 261650Sbill 262650Sbill /* 263615Sbill * The base addresses for the loaded text, data and bss from the 264615Sbill * current module during pass2 are given by torigin, dorigin and borigin. 265615Sbill */ 266615Sbill long torigin, dorigin, borigin; 267615Sbill 268615Sbill /* 269615Sbill * Errlev is nonzero when errors have occured. 270615Sbill * Delarg is an implicit argument to the routine delexit 271615Sbill * which is called on error. We do ``delarg = errlev'' before normal 272615Sbill * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the 273615Sbill * result file executable. 274615Sbill */ 275615Sbill int errlev; 276615Sbill int delarg = 4; 277615Sbill 278615Sbill /* 279615Sbill * The biobuf structure and associated routines are used to write 280615Sbill * into one file at several places concurrently. Calling bopen 281615Sbill * with a biobuf structure sets it up to write ``biofd'' starting 282615Sbill * at the specified offset. You can then use ``bwrite'' and/or ``bputc'' 283615Sbill * to stuff characters in the stream, much like ``fwrite'' and ``fputc''. 284615Sbill * Calling bflush drains all the buffers and MUST be done before exit. 285615Sbill */ 286615Sbill struct biobuf { 287615Sbill short b_nleft; /* Number free spaces left in b_buf */ 288*16068Sralph /* Initialize to be less than b_bufsize initially, to boundary align in file */ 289615Sbill char *b_ptr; /* Next place to stuff characters */ 290*16068Sralph char *b_buf; /* Pointer to the buffer */ 291*16068Sralph int b_bufsize; /* Size of the buffer */ 292615Sbill off_t b_off; /* Current file offset */ 293615Sbill struct biobuf *b_link; /* Link in chain for bflush() */ 294615Sbill } *biobufs; 295615Sbill #define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \ 296615Sbill : bflushc(b, c)) 297615Sbill int biofd; 298615Sbill off_t boffset; 299615Sbill struct biobuf *tout, *dout, *trout, *drout, *sout, *strout; 300615Sbill 301615Sbill /* 302615Sbill * Offset is the current offset in the string file. 303615Sbill * Its initial value reflects the fact that we will 304615Sbill * eventually stuff the size of the string table at the 305615Sbill * beginning of the string table (i.e. offset itself!). 306615Sbill */ 307615Sbill off_t offset = sizeof (off_t); 308615Sbill 309615Sbill int ofilfnd; /* -o given; otherwise move l.out to a.out */ 310615Sbill char *ofilename = "l.out"; 3113606Ssklower int ofilemode; /* respect umask even for unsucessful ld's */ 312615Sbill int infil; /* current input file descriptor */ 313615Sbill char *filname; /* and its name */ 314615Sbill 315615Sbill /* 316615Sbill * Base of the string table of the current module (pass1 and pass2). 317615Sbill */ 318615Sbill char *curstr; 319615Sbill 32012671Ssam /* 32112671Ssam * System software page size, as returned by getpagesize. 32212671Ssam */ 32312671Ssam int pagesize; 32412671Ssam 325615Sbill char get(); 326615Sbill int delexit(); 327615Sbill char *savestr(); 328615Sbill 329615Sbill main(argc, argv) 330615Sbill char **argv; 331615Sbill { 332615Sbill register int c, i; 333615Sbill int num; 334615Sbill register char *ap, **p; 335615Sbill char save; 336615Sbill 337650Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 338615Sbill signal(SIGINT, delexit); 339650Sbill signal(SIGTERM, delexit); 340650Sbill } 341615Sbill if (argc == 1) 342615Sbill exit(4); 343615Sbill p = argv+1; 34412671Ssam pagesize = getpagesize(); 345615Sbill 346650Sbill /* 347650Sbill * Scan files once to find where symbols are defined. 348650Sbill */ 349615Sbill for (c=1; c<argc; c++) { 350615Sbill if (trace) 351615Sbill printf("%s:\n", *p); 352615Sbill filname = 0; 353615Sbill ap = *p++; 354615Sbill if (*ap != '-') { 355615Sbill load1arg(ap); 356615Sbill continue; 357615Sbill } 358615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 359615Sbill 360615Sbill case 'o': 361615Sbill if (++c >= argc) 362615Sbill error(1, "-o where?"); 363615Sbill ofilename = *p++; 364615Sbill ofilfnd++; 365615Sbill continue; 366615Sbill case 'u': 367615Sbill case 'e': 368615Sbill if (++c >= argc) 369615Sbill error(1, "-u or -c: arg missing"); 370615Sbill enter(slookup(*p++)); 371615Sbill if (ap[i]=='e') 372615Sbill entrypt = lastsym; 373615Sbill continue; 374615Sbill case 'H': 375615Sbill if (++c >= argc) 376615Sbill error(1, "-H: arg missing"); 377615Sbill if (tsize!=0) 378615Sbill error(1, "-H: too late, some text already loaded"); 379615Sbill hsize = atoi(*p++); 380615Sbill continue; 381615Sbill case 'A': 382615Sbill if (++c >= argc) 383615Sbill error(1, "-A: arg missing"); 384615Sbill if (Aflag) 385615Sbill error(1, "-A: only one base file allowed"); 386615Sbill Aflag = 1; 387615Sbill nflag = 0; 388615Sbill funding = 1; 389615Sbill load1arg(*p++); 390615Sbill trsize = drsize = tsize = dsize = bsize = 0; 391615Sbill ctrel = cdrel = cbrel = 0; 392615Sbill funding = 0; 393615Sbill addsym = nextsym; 394615Sbill continue; 395615Sbill case 'D': 396615Sbill if (++c >= argc) 397615Sbill error(1, "-D: arg missing"); 398615Sbill num = htoi(*p++); 399615Sbill if (dsize > num) 400615Sbill error(1, "-D: too small"); 401615Sbill dsize = num; 402615Sbill continue; 403615Sbill case 'T': 404615Sbill if (++c >= argc) 405615Sbill error(1, "-T: arg missing"); 406615Sbill if (tsize!=0) 407615Sbill error(1, "-T: too late, some text already loaded"); 408615Sbill textbase = htoi(*p++); 409615Sbill continue; 410615Sbill case 'l': 411615Sbill save = ap[--i]; 412615Sbill ap[i]='-'; 413615Sbill load1arg(&ap[i]); 414615Sbill ap[i]=save; 415615Sbill goto next; 416898Sbill case 'M': 417898Sbill Mflag++; 418898Sbill continue; 419615Sbill case 'x': 420615Sbill xflag++; 421615Sbill continue; 422615Sbill case 'X': 423615Sbill Xflag++; 424615Sbill continue; 425615Sbill case 'S': 426615Sbill Sflag++; 427615Sbill continue; 428615Sbill case 'r': 429615Sbill rflag++; 430615Sbill arflag++; 431615Sbill continue; 432615Sbill case 's': 433615Sbill sflag++; 434615Sbill xflag++; 435615Sbill continue; 436615Sbill case 'n': 437615Sbill nflag++; 438650Sbill Nflag = zflag = 0; 439615Sbill continue; 440615Sbill case 'N': 441650Sbill Nflag++; 442650Sbill nflag = zflag = 0; 443615Sbill continue; 444615Sbill case 'd': 445615Sbill dflag++; 446615Sbill continue; 447615Sbill case 'i': 448615Sbill printf("ld: -i ignored\n"); 449615Sbill continue; 450615Sbill case 't': 451615Sbill trace++; 452615Sbill continue; 453898Sbill case 'y': 454898Sbill if (ap[i+1] == 0) 455898Sbill error(1, "-y: symbol name missing"); 456898Sbill if (yflag == 0) { 457898Sbill ytab = (char **)calloc(argc, sizeof (char **)); 458898Sbill if (ytab == 0) 459898Sbill error(1, "ran out of memory (-y)"); 460898Sbill } 461898Sbill ytab[yflag++] = &ap[i+1]; 462898Sbill goto next; 463615Sbill case 'z': 464615Sbill zflag++; 465650Sbill Nflag = nflag = 0; 466615Sbill continue; 467615Sbill default: 468615Sbill filname = savestr("-x"); /* kludge */ 469615Sbill filname[1] = ap[i]; /* kludge */ 470615Sbill archdr.ar_name[0] = 0; /* kludge */ 471615Sbill error(1, "bad flag"); 472615Sbill } 473615Sbill next: 474615Sbill ; 475615Sbill } 476650Sbill if (rflag == 0 && Nflag == 0 && nflag == 0) 477650Sbill zflag++; 478615Sbill endload(argc, argv); 479615Sbill exit(0); 480615Sbill } 481615Sbill 482615Sbill /* 483615Sbill * Convert a ascii string which is a hex number. 484615Sbill * Used by -T and -D options. 485615Sbill */ 486615Sbill htoi(p) 487615Sbill register char *p; 488615Sbill { 489615Sbill register int c, n; 490615Sbill 491615Sbill n = 0; 492615Sbill while (c = *p++) { 493615Sbill n <<= 4; 494615Sbill if (isdigit(c)) 495615Sbill n += c - '0'; 496615Sbill else if (c >= 'a' && c <= 'f') 497615Sbill n += 10 + (c - 'a'); 498615Sbill else if (c >= 'A' && c <= 'F') 499615Sbill n += 10 + (c - 'A'); 500615Sbill else 501615Sbill error(1, "badly formed hex number"); 502615Sbill } 503615Sbill return (n); 504615Sbill } 505615Sbill 506615Sbill delexit() 507615Sbill { 5089332Smckusick struct stat stbuf; 5099332Smckusick long size; 5109332Smckusick char c = 0; 511615Sbill 512615Sbill bflush(); 513615Sbill unlink("l.out"); 514615Sbill if (delarg==0 && Aflag==0) 5153606Ssklower chmod(ofilename, ofilemode); 5169332Smckusick /* 5179332Smckusick * We have to insure that the last block of the data segment 518*16068Sralph * is allocated a full pagesize block. If the underlying 519*16068Sralph * file system allocates frags that are smaller than pagesize, 520*16068Sralph * a full zero filled pagesize block needs to be allocated so 5219332Smckusick * that when it is demand paged, the paged in block will be 5229332Smckusick * appropriately filled with zeros. 5239332Smckusick */ 5249332Smckusick fstat(biofd, &stbuf); 525*16068Sralph size = round(stbuf.st_size, pagesize); 52610640Smckusick if (!rflag && size > stbuf.st_size) { 5279332Smckusick lseek(biofd, size - 1, 0); 5289332Smckusick write(biofd, &c, 1); 5299332Smckusick } 530615Sbill exit (delarg); 531615Sbill } 532615Sbill 533615Sbill endload(argc, argv) 534615Sbill int argc; 535615Sbill char **argv; 536615Sbill { 537615Sbill register int c, i; 538615Sbill long dnum; 539615Sbill register char *ap, **p; 540615Sbill 541615Sbill clibseg = libseg; 542615Sbill filname = 0; 543615Sbill middle(); 544615Sbill setupout(); 545615Sbill p = argv+1; 546615Sbill for (c=1; c<argc; c++) { 547615Sbill ap = *p++; 548615Sbill if (trace) 549615Sbill printf("%s:\n", ap); 550615Sbill if (*ap != '-') { 551615Sbill load2arg(ap); 552615Sbill continue; 553615Sbill } 554615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 555615Sbill 556615Sbill case 'D': 557615Sbill dnum = htoi(*p); 558615Sbill if (dorigin < dnum) 559615Sbill while (dorigin < dnum) 560615Sbill bputc(0, dout), dorigin++; 561615Sbill /* fall into ... */ 562615Sbill case 'T': 563615Sbill case 'u': 564615Sbill case 'e': 565615Sbill case 'o': 566615Sbill case 'H': 567615Sbill ++c; 568615Sbill ++p; 569615Sbill /* fall into ... */ 570615Sbill default: 571615Sbill continue; 572615Sbill case 'A': 573615Sbill funding = 1; 574615Sbill load2arg(*p++); 575615Sbill funding = 0; 576615Sbill c++; 577615Sbill continue; 578898Sbill case 'y': 579898Sbill goto next; 580615Sbill case 'l': 581615Sbill ap[--i]='-'; 582615Sbill load2arg(&ap[i]); 583615Sbill goto next; 584615Sbill } 585615Sbill next: 586615Sbill ; 587615Sbill } 588615Sbill finishout(); 589615Sbill } 590615Sbill 591615Sbill /* 592615Sbill * Scan file to find defined symbols. 593615Sbill */ 594615Sbill load1arg(cp) 595615Sbill register char *cp; 596615Sbill { 597615Sbill register struct ranlib *tp; 598615Sbill off_t nloc; 599898Sbill int kind; 600615Sbill 601898Sbill kind = getfile(cp); 602898Sbill if (Mflag) 603898Sbill printf("%s\n", filname); 604898Sbill switch (kind) { 605615Sbill 606615Sbill /* 607615Sbill * Plain file. 608615Sbill */ 609615Sbill case 0: 610615Sbill load1(0, 0L); 611615Sbill break; 612615Sbill 613615Sbill /* 614615Sbill * Archive without table of contents. 615615Sbill * (Slowly) process each member. 616615Sbill */ 617615Sbill case 1: 618898Sbill error(-1, 619898Sbill "warning: archive has no table of contents; add one using ranlib(1)"); 620615Sbill nloc = SARMAG; 621615Sbill while (step(nloc)) 622615Sbill nloc += sizeof(archdr) + 623615Sbill round(atol(archdr.ar_size), sizeof (short)); 624615Sbill break; 625615Sbill 626615Sbill /* 627615Sbill * Archive with table of contents. 628615Sbill * Read the table of contents and its associated string table. 629615Sbill * Pass through the library resolving symbols until nothing changes 630615Sbill * for an entire pass (i.e. you can get away with backward references 631615Sbill * when there is a table of contents!) 632615Sbill */ 633615Sbill case 2: 634615Sbill nloc = SARMAG + sizeof (archdr); 635615Sbill dseek(&text, nloc, sizeof (tnum)); 636615Sbill mget((char *)&tnum, sizeof (tnum), &text); 637615Sbill nloc += sizeof (tnum); 638615Sbill tab = (struct ranlib *)malloc(tnum); 639615Sbill if (tab == 0) 640615Sbill error(1, "ran out of memory (toc)"); 641615Sbill dseek(&text, nloc, tnum); 642615Sbill mget((char *)tab, tnum, &text); 643615Sbill nloc += tnum; 644615Sbill tnum /= sizeof (struct ranlib); 645615Sbill dseek(&text, nloc, sizeof (ssiz)); 646615Sbill mget((char *)&ssiz, sizeof (ssiz), &text); 647615Sbill nloc += sizeof (ssiz); 648615Sbill tabstr = (char *)malloc(ssiz); 649615Sbill if (tabstr == 0) 650615Sbill error(1, "ran out of memory (tocstr)"); 651615Sbill dseek(&text, nloc, ssiz); 652615Sbill mget((char *)tabstr, ssiz, &text); 653615Sbill for (tp = &tab[tnum]; --tp >= tab;) { 654615Sbill if (tp->ran_un.ran_strx < 0 || 655615Sbill tp->ran_un.ran_strx >= ssiz) 656615Sbill error(1, "mangled archive table of contents"); 657615Sbill tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx; 658615Sbill } 659615Sbill while (ldrand()) 660615Sbill continue; 661615Sbill cfree((char *)tab); 662615Sbill cfree(tabstr); 663615Sbill nextlibp(-1); 664615Sbill break; 665615Sbill 666615Sbill /* 667615Sbill * Table of contents is out of date, so search 668615Sbill * as a normal library (but skip the __.SYMDEF file). 669615Sbill */ 670615Sbill case 3: 671898Sbill error(-1, 672898Sbill "warning: table of contents for archive is out of date; rerun ranlib(1)"); 673615Sbill nloc = SARMAG; 674615Sbill do 675615Sbill nloc += sizeof(archdr) + 676615Sbill round(atol(archdr.ar_size), sizeof(short)); 677615Sbill while (step(nloc)); 678615Sbill break; 679615Sbill } 680615Sbill close(infil); 681615Sbill } 682615Sbill 683615Sbill /* 684615Sbill * Advance to the next archive member, which 685615Sbill * is at offset nloc in the archive. If the member 686615Sbill * is useful, record its location in the liblist structure 687615Sbill * for use in pass2. Mark the end of the archive in libilst with a -1. 688615Sbill */ 689615Sbill step(nloc) 690615Sbill off_t nloc; 691615Sbill { 692615Sbill 693615Sbill dseek(&text, nloc, (long) sizeof archdr); 694615Sbill if (text.size <= 0) { 695615Sbill nextlibp(-1); 696615Sbill return (0); 697615Sbill } 698615Sbill getarhdr(); 699615Sbill if (load1(1, nloc + (sizeof archdr))) 700615Sbill nextlibp(nloc); 701615Sbill return (1); 702615Sbill } 703615Sbill 704615Sbill /* 705615Sbill * Record the location of a useful archive member. 706615Sbill * Recording -1 marks the end of files from an archive. 707615Sbill * The liblist data structure is dynamically extended here. 708615Sbill */ 709615Sbill nextlibp(val) 710615Sbill off_t val; 711615Sbill { 712615Sbill 713615Sbill if (clibseg->li_used == NROUT) { 714615Sbill if (++clibseg == &libseg[NSEG]) 715615Sbill error(1, "too many files loaded from libraries"); 716615Sbill clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t)); 717615Sbill if (clibseg->li_first == 0) 718615Sbill error(1, "ran out of memory (nextlibp)"); 719615Sbill } 720615Sbill clibseg->li_first[clibseg->li_used++] = val; 721898Sbill if (val != -1 && Mflag) 722898Sbill printf("\t%s\n", archdr.ar_name); 723615Sbill } 724615Sbill 725615Sbill /* 726615Sbill * One pass over an archive with a table of contents. 727615Sbill * Remember the number of symbols currently defined, 728615Sbill * then call step on members which look promising (i.e. 729615Sbill * that define a symbol which is currently externally undefined). 730615Sbill * Indicate to our caller whether this process netted any more symbols. 731615Sbill */ 732615Sbill ldrand() 733615Sbill { 734615Sbill register struct nlist *sp, **hp; 735615Sbill register struct ranlib *tp, *tplast; 736615Sbill off_t loc; 737615Sbill int nsymt = symx(nextsym); 738615Sbill 739615Sbill tplast = &tab[tnum-1]; 740615Sbill for (tp = tab; tp <= tplast; tp++) { 741615Sbill if ((hp = slookup(tp->ran_un.ran_name)) == 0) 742615Sbill continue; 743615Sbill sp = *hp; 744615Sbill if (sp->n_type != N_EXT+N_UNDF) 745615Sbill continue; 746615Sbill step(tp->ran_off); 747615Sbill loc = tp->ran_off; 748615Sbill while (tp < tplast && (tp+1)->ran_off == loc) 749615Sbill tp++; 750615Sbill } 751615Sbill return (symx(nextsym) != nsymt); 752615Sbill } 753615Sbill 754615Sbill /* 755615Sbill * Examine a single file or archive member on pass 1. 756615Sbill */ 757615Sbill load1(libflg, loc) 758615Sbill off_t loc; 759615Sbill { 760615Sbill register struct nlist *sp; 761615Sbill struct nlist *savnext; 762615Sbill int ndef, nlocal, type, size, nsymt; 763615Sbill register int i; 764615Sbill off_t maxoff; 765615Sbill struct stat stb; 766615Sbill 767615Sbill readhdr(loc); 768615Sbill if (filhdr.a_syms == 0) { 769615Sbill if (filhdr.a_text+filhdr.a_data == 0) 770615Sbill return (0); 771615Sbill error(1, "no namelist"); 772615Sbill } 773615Sbill if (libflg) 774615Sbill maxoff = atol(archdr.ar_size); 775615Sbill else { 776615Sbill fstat(infil, &stb); 777615Sbill maxoff = stb.st_size; 778615Sbill } 779615Sbill if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff) 780615Sbill error(1, "too small (old format .o?)"); 781615Sbill ctrel = tsize; cdrel += dsize; cbrel += bsize; 782615Sbill ndef = 0; 783615Sbill nlocal = sizeof(cursym); 784615Sbill savnext = nextsym; 785615Sbill loc += N_SYMOFF(filhdr); 786615Sbill dseek(&text, loc, filhdr.a_syms); 787615Sbill dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t)); 788615Sbill mget(&size, sizeof (size), &reloc); 789615Sbill dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t)); 790615Sbill curstr = (char *)malloc(size); 791615Sbill if (curstr == NULL) 792615Sbill error(1, "no space for string table"); 793615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc); 794615Sbill while (text.size > 0) { 795615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 796615Sbill if (cursym.n_un.n_strx) { 797615Sbill if (cursym.n_un.n_strx<sizeof(size) || 798615Sbill cursym.n_un.n_strx>=size) 799615Sbill error(1, "bad string table index (pass 1)"); 800615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 801615Sbill } 802615Sbill type = cursym.n_type; 803615Sbill if ((type&N_EXT)==0) { 804615Sbill if (Xflag==0 || cursym.n_un.n_name[0]!='L' || 805615Sbill type & N_STAB) 806615Sbill nlocal += sizeof cursym; 807615Sbill continue; 808615Sbill } 809615Sbill symreloc(); 810615Sbill if (enter(lookup())) 811615Sbill continue; 812615Sbill if ((sp = lastsym)->n_type != N_EXT+N_UNDF) 813615Sbill continue; 814615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 815615Sbill if (cursym.n_value > sp->n_value) 816615Sbill sp->n_value = cursym.n_value; 817615Sbill continue; 818615Sbill } 819615Sbill if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT) 820615Sbill continue; 821615Sbill ndef++; 822615Sbill sp->n_type = cursym.n_type; 823615Sbill sp->n_value = cursym.n_value; 824615Sbill } 825615Sbill if (libflg==0 || ndef) { 826615Sbill tsize += filhdr.a_text; 827615Sbill dsize += round(filhdr.a_data, sizeof (long)); 828615Sbill bsize += round(filhdr.a_bss, sizeof (long)); 829615Sbill ssize += nlocal; 830615Sbill trsize += filhdr.a_trsize; 831615Sbill drsize += filhdr.a_drsize; 832615Sbill if (funding) 833615Sbill textbase = (*slookup("_end"))->n_value; 834615Sbill nsymt = symx(nextsym); 835615Sbill for (i = symx(savnext); i < nsymt; i++) { 836615Sbill sp = xsym(i); 837615Sbill sp->n_un.n_name = savestr(sp->n_un.n_name); 838615Sbill } 839615Sbill free(curstr); 840615Sbill return (1); 841615Sbill } 842615Sbill /* 843615Sbill * No symbols defined by this library member. 844615Sbill * Rip out the hash table entries and reset the symbol table. 845615Sbill */ 846615Sbill symfree(savnext); 847615Sbill free(curstr); 848615Sbill return(0); 849615Sbill } 850615Sbill 851615Sbill middle() 852615Sbill { 853615Sbill register struct nlist *sp; 854615Sbill long csize, t, corigin, ocsize; 855615Sbill int nund, rnd; 856615Sbill char s; 857615Sbill register int i; 858615Sbill int nsymt; 859615Sbill 860615Sbill torigin = 0; 861615Sbill dorigin = 0; 862615Sbill borigin = 0; 863615Sbill 864615Sbill p_etext = *slookup("_etext"); 865615Sbill p_edata = *slookup("_edata"); 866615Sbill p_end = *slookup("_end"); 867615Sbill /* 868615Sbill * If there are any undefined symbols, save the relocation bits. 869615Sbill */ 870615Sbill nsymt = symx(nextsym); 871615Sbill if (rflag==0) { 872615Sbill for (i = 0; i < nsymt; i++) { 873615Sbill sp = xsym(i); 874615Sbill if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 && 875650Sbill sp!=p_end && sp!=p_edata && sp!=p_etext) { 876615Sbill rflag++; 877615Sbill dflag = 0; 878615Sbill break; 879615Sbill } 880615Sbill } 881615Sbill } 882615Sbill if (rflag) 883615Sbill sflag = zflag = 0; 884615Sbill /* 885615Sbill * Assign common locations. 886615Sbill */ 887615Sbill csize = 0; 888615Sbill if (!Aflag) 889615Sbill addsym = symseg[0].sy_first; 890615Sbill database = round(tsize+textbase, 89112671Ssam (nflag||zflag? pagesize : sizeof (long))); 892615Sbill database += hsize; 893615Sbill if (dflag || rflag==0) { 894615Sbill ldrsym(p_etext, tsize, N_EXT+N_TEXT); 895615Sbill ldrsym(p_edata, dsize, N_EXT+N_DATA); 896615Sbill ldrsym(p_end, bsize, N_EXT+N_BSS); 897615Sbill for (i = symx(addsym); i < nsymt; i++) { 898615Sbill sp = xsym(i); 899615Sbill if ((s=sp->n_type)==N_EXT+N_UNDF && 900615Sbill (t = sp->n_value)!=0) { 901615Sbill if (t >= sizeof (double)) 902615Sbill rnd = sizeof (double); 903615Sbill else if (t >= sizeof (long)) 904615Sbill rnd = sizeof (long); 905615Sbill else 906615Sbill rnd = sizeof (short); 907615Sbill csize = round(csize, rnd); 908615Sbill sp->n_value = csize; 909615Sbill sp->n_type = N_EXT+N_COMM; 910615Sbill ocsize = csize; 911615Sbill csize += t; 912615Sbill } 913615Sbill if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) { 914615Sbill sp->n_value = ocsize; 915615Sbill sp->n_type = (s&N_STAB) | (N_EXT+N_COMM); 916615Sbill } 917615Sbill } 918615Sbill } 919615Sbill /* 920615Sbill * Now set symbols to their final value 921615Sbill */ 922615Sbill csize = round(csize, sizeof (long)); 923615Sbill torigin = textbase; 924615Sbill dorigin = database; 925615Sbill corigin = dorigin + dsize; 926615Sbill borigin = corigin + csize; 927615Sbill nund = 0; 928615Sbill nsymt = symx(nextsym); 929615Sbill for (i = symx(addsym); i<nsymt; i++) { 930615Sbill sp = xsym(i); 931615Sbill switch (sp->n_type & (N_TYPE+N_EXT)) { 932615Sbill 933615Sbill case N_EXT+N_UNDF: 9342369Skre if (arflag == 0) 9352369Skre errlev |= 01; 936615Sbill if ((arflag==0 || dflag) && sp->n_value==0) { 937650Sbill if (sp==p_end || sp==p_etext || sp==p_edata) 938650Sbill continue; 939615Sbill if (nund==0) 940615Sbill printf("Undefined:\n"); 941615Sbill nund++; 942615Sbill printf("%s\n", sp->n_un.n_name); 943615Sbill } 944615Sbill continue; 945615Sbill case N_EXT+N_ABS: 946615Sbill default: 947615Sbill continue; 948615Sbill case N_EXT+N_TEXT: 949615Sbill sp->n_value += torigin; 950615Sbill continue; 951615Sbill case N_EXT+N_DATA: 952615Sbill sp->n_value += dorigin; 953615Sbill continue; 954615Sbill case N_EXT+N_BSS: 955615Sbill sp->n_value += borigin; 956615Sbill continue; 957615Sbill case N_EXT+N_COMM: 958615Sbill sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS); 959615Sbill sp->n_value += corigin; 960615Sbill continue; 961615Sbill } 962615Sbill } 963615Sbill if (sflag || xflag) 964615Sbill ssize = 0; 965615Sbill bsize += csize; 966615Sbill nsym = ssize / (sizeof cursym); 967615Sbill if (Aflag) { 968615Sbill fixspec(p_etext,torigin); 969615Sbill fixspec(p_edata,dorigin); 970615Sbill fixspec(p_end,borigin); 971615Sbill } 972615Sbill } 973615Sbill 974615Sbill fixspec(sym,offset) 975615Sbill struct nlist *sym; 976615Sbill long offset; 977615Sbill { 978615Sbill 979615Sbill if(symx(sym) < symx(addsym) && sym!=0) 980615Sbill sym->n_value += offset; 981615Sbill } 982615Sbill 983615Sbill ldrsym(sp, val, type) 984615Sbill register struct nlist *sp; 985615Sbill long val; 986615Sbill { 987615Sbill 988615Sbill if (sp == 0) 989615Sbill return; 990615Sbill if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) { 991615Sbill printf("%s: ", sp->n_un.n_name); 992615Sbill error(0, "user attempt to redfine loader-defined symbol"); 993615Sbill return; 994615Sbill } 995615Sbill sp->n_type = type; 996615Sbill sp->n_value = val; 997615Sbill } 998615Sbill 999615Sbill off_t wroff; 1000615Sbill struct biobuf toutb; 1001615Sbill 1002615Sbill setupout() 1003615Sbill { 1004615Sbill int bss; 1005*16068Sralph struct stat stbuf; 1006898Sbill extern char *sys_errlist[]; 1007898Sbill extern int errno; 1008615Sbill 10093606Ssklower ofilemode = 0777 & ~umask(0); 10103606Ssklower biofd = creat(ofilename, 0666 & ofilemode); 1011898Sbill if (biofd < 0) { 1012898Sbill filname = ofilename; /* kludge */ 1013898Sbill archdr.ar_name[0] = 0; /* kludge */ 1014898Sbill error(1, sys_errlist[errno]); /* kludge */ 1015898Sbill } 1016*16068Sralph fstat(biofd, &stbuf); /* suppose file exists, wrong*/ 1017*16068Sralph if (stbuf.st_mode & 0111) { /* mode, ld fails? */ 1018*16068Sralph chmod(ofilename, stbuf.st_mode & 0666); 1019*16068Sralph ofilemode = stbuf.st_mode; 1020*16068Sralph } 1021615Sbill filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC); 1022615Sbill filhdr.a_text = nflag ? tsize : 102312671Ssam round(tsize, zflag ? pagesize : sizeof (long)); 102412671Ssam filhdr.a_data = zflag ? round(dsize, pagesize) : dsize; 1025615Sbill bss = bsize - (filhdr.a_data - dsize); 1026615Sbill if (bss < 0) 1027615Sbill bss = 0; 1028615Sbill filhdr.a_bss = bss; 1029615Sbill filhdr.a_trsize = trsize; 1030615Sbill filhdr.a_drsize = drsize; 1031615Sbill filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym)); 1032615Sbill if (entrypt) { 1033615Sbill if (entrypt->n_type!=N_EXT+N_TEXT) 1034615Sbill error(0, "entry point not in text"); 1035615Sbill else 1036615Sbill filhdr.a_entry = entrypt->n_value; 1037615Sbill } else 1038615Sbill filhdr.a_entry = 0; 1039615Sbill filhdr.a_trsize = (rflag ? trsize:0); 1040615Sbill filhdr.a_drsize = (rflag ? drsize:0); 1041*16068Sralph tout = &toutb; 1042*16068Sralph bopen(tout, 0, stbuf.st_blksize); 1043615Sbill bwrite((char *)&filhdr, sizeof (filhdr), tout); 1044*16068Sralph if (zflag) 1045*16068Sralph bseek(tout, pagesize); 1046615Sbill wroff = N_TXTOFF(filhdr) + filhdr.a_text; 1047*16068Sralph outb(&dout, filhdr.a_data, stbuf.st_blksize); 1048615Sbill if (rflag) { 1049*16068Sralph outb(&trout, filhdr.a_trsize, stbuf.st_blksize); 1050*16068Sralph outb(&drout, filhdr.a_drsize, stbuf.st_blksize); 1051615Sbill } 1052615Sbill if (sflag==0 || xflag==0) { 1053*16068Sralph outb(&sout, filhdr.a_syms, stbuf.st_blksize); 1054615Sbill wroff += sizeof (offset); 1055*16068Sralph outb(&strout, 0, stbuf.st_blksize); 1056615Sbill } 1057615Sbill } 1058615Sbill 1059*16068Sralph outb(bp, inc, bufsize) 1060615Sbill register struct biobuf **bp; 1061615Sbill { 1062615Sbill 1063615Sbill *bp = (struct biobuf *)malloc(sizeof (struct biobuf)); 1064615Sbill if (*bp == 0) 1065615Sbill error(1, "ran out of memory (outb)"); 1066*16068Sralph bopen(*bp, wroff, bufsize); 1067615Sbill wroff += inc; 1068615Sbill } 1069615Sbill 1070615Sbill load2arg(acp) 1071615Sbill char *acp; 1072615Sbill { 1073615Sbill register char *cp; 1074615Sbill off_t loc; 1075615Sbill 1076615Sbill cp = acp; 1077615Sbill if (getfile(cp) == 0) { 1078615Sbill while (*cp) 1079615Sbill cp++; 1080615Sbill while (cp >= acp && *--cp != '/'); 1081615Sbill mkfsym(++cp); 1082615Sbill load2(0L); 1083615Sbill } else { /* scan archive members referenced */ 1084615Sbill for (;;) { 1085615Sbill if (clibseg->li_used2 == clibseg->li_used) { 1086615Sbill if (clibseg->li_used < NROUT) 1087615Sbill error(1, "libseg botch"); 1088615Sbill clibseg++; 1089615Sbill } 1090615Sbill loc = clibseg->li_first[clibseg->li_used2++]; 1091615Sbill if (loc == -1) 1092615Sbill break; 1093615Sbill dseek(&text, loc, (long)sizeof(archdr)); 1094615Sbill getarhdr(); 1095615Sbill mkfsym(archdr.ar_name); 1096615Sbill load2(loc + (long)sizeof(archdr)); 1097615Sbill } 1098615Sbill } 1099615Sbill close(infil); 1100615Sbill } 1101615Sbill 1102615Sbill load2(loc) 1103615Sbill long loc; 1104615Sbill { 1105615Sbill int size; 1106615Sbill register struct nlist *sp; 1107615Sbill register struct local *lp; 1108615Sbill register int symno, i; 1109615Sbill int type; 1110615Sbill 1111615Sbill readhdr(loc); 1112650Sbill if (!funding) { 1113615Sbill ctrel = torigin; 1114615Sbill cdrel += dorigin; 1115615Sbill cbrel += borigin; 1116615Sbill } 1117615Sbill /* 1118615Sbill * Reread the symbol table, recording the numbering 1119615Sbill * of symbols for fixing external references. 1120615Sbill */ 1121615Sbill for (i = 0; i < LHSIZ; i++) 1122615Sbill lochash[i] = 0; 1123615Sbill clocseg = locseg; 1124615Sbill clocseg->lo_used = 0; 1125615Sbill symno = -1; 1126615Sbill loc += N_TXTOFF(filhdr); 1127615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1128615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t)); 1129615Sbill mget(&size, sizeof(size), &text); 1130615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1131615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t), 1132615Sbill size - sizeof(off_t)); 1133615Sbill curstr = (char *)malloc(size); 1134615Sbill if (curstr == NULL) 1135615Sbill error(1, "out of space reading string table (pass 2)"); 1136615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &text); 1137615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1138615Sbill filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms); 1139615Sbill while (text.size > 0) { 1140615Sbill symno++; 1141615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 1142615Sbill if (cursym.n_un.n_strx) { 1143615Sbill if (cursym.n_un.n_strx<sizeof(size) || 1144615Sbill cursym.n_un.n_strx>=size) 1145615Sbill error(1, "bad string table index (pass 2)"); 1146615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 1147615Sbill } 1148615Sbill /* inline expansion of symreloc() */ 1149615Sbill switch (cursym.n_type & 017) { 1150615Sbill 1151615Sbill case N_TEXT: 1152615Sbill case N_EXT+N_TEXT: 1153615Sbill cursym.n_value += ctrel; 1154615Sbill break; 1155615Sbill case N_DATA: 1156615Sbill case N_EXT+N_DATA: 1157615Sbill cursym.n_value += cdrel; 1158615Sbill break; 1159615Sbill case N_BSS: 1160615Sbill case N_EXT+N_BSS: 1161615Sbill cursym.n_value += cbrel; 1162615Sbill break; 1163615Sbill case N_EXT+N_UNDF: 1164615Sbill break; 1165615Sbill default: 1166615Sbill if (cursym.n_type&N_EXT) 1167615Sbill cursym.n_type = N_EXT+N_ABS; 1168615Sbill } 1169615Sbill /* end inline expansion of symreloc() */ 1170615Sbill type = cursym.n_type; 1171898Sbill if (yflag && cursym.n_un.n_name) 1172898Sbill for (i = 0; i < yflag; i++) 1173898Sbill /* fast check for 2d character! */ 1174898Sbill if (ytab[i][1] == cursym.n_un.n_name[1] && 1175898Sbill !strcmp(ytab[i], cursym.n_un.n_name)) { 1176898Sbill tracesym(); 1177898Sbill break; 1178898Sbill } 1179615Sbill if ((type&N_EXT) == 0) { 1180615Sbill if (!sflag&&!xflag&& 1181615Sbill (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB)) 1182615Sbill symwrite(&cursym, sout); 1183615Sbill continue; 1184615Sbill } 1185615Sbill if (funding) 1186615Sbill continue; 1187615Sbill if ((sp = *lookup()) == 0) 1188615Sbill error(1, "internal error: symbol not found"); 1189615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 1190615Sbill if (clocseg->lo_used == NSYMPR) { 1191615Sbill if (++clocseg == &locseg[NSEG]) 1192615Sbill error(1, "local symbol overflow"); 1193615Sbill clocseg->lo_used = 0; 1194615Sbill } 1195615Sbill if (clocseg->lo_first == 0) { 1196615Sbill clocseg->lo_first = (struct local *) 1197615Sbill malloc(NSYMPR * sizeof (struct local)); 1198615Sbill if (clocseg->lo_first == 0) 1199615Sbill error(1, "out of memory (clocseg)"); 1200615Sbill } 1201615Sbill lp = &clocseg->lo_first[clocseg->lo_used++]; 1202615Sbill lp->l_index = symno; 1203615Sbill lp->l_symbol = sp; 1204615Sbill lp->l_link = lochash[symno % LHSIZ]; 1205615Sbill lochash[symno % LHSIZ] = lp; 1206615Sbill continue; 1207615Sbill } 1208615Sbill if (cursym.n_type & N_STAB) 1209615Sbill continue; 1210615Sbill if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) { 1211615Sbill printf("%s: ", cursym.n_un.n_name); 1212615Sbill error(0, "multiply defined"); 1213615Sbill } 1214615Sbill } 1215615Sbill if (funding) 1216615Sbill return; 1217615Sbill dseek(&text, loc, filhdr.a_text); 1218615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize); 1219650Sbill load2td(ctrel, torigin - textbase, tout, trout); 1220615Sbill dseek(&text, loc+filhdr.a_text, filhdr.a_data); 1221615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, 1222615Sbill filhdr.a_drsize); 1223650Sbill load2td(cdrel, dorigin - database, dout, drout); 1224615Sbill while (filhdr.a_data & (sizeof(long)-1)) { 1225615Sbill bputc(0, dout); 1226615Sbill filhdr.a_data++; 1227615Sbill } 1228615Sbill torigin += filhdr.a_text; 12291752Sbill dorigin += round(filhdr.a_data, sizeof (long)); 12301752Sbill borigin += round(filhdr.a_bss, sizeof (long)); 1231615Sbill free(curstr); 1232615Sbill } 1233615Sbill 1234898Sbill struct tynames { 1235898Sbill int ty_value; 1236898Sbill char *ty_name; 1237898Sbill } tynames[] = { 1238898Sbill N_UNDF, "undefined", 1239898Sbill N_ABS, "absolute", 1240898Sbill N_TEXT, "text", 1241898Sbill N_DATA, "data", 1242898Sbill N_BSS, "bss", 1243898Sbill N_COMM, "common", 1244898Sbill 0, 0, 1245898Sbill }; 1246898Sbill 1247898Sbill tracesym() 1248898Sbill { 1249898Sbill register struct tynames *tp; 1250898Sbill 1251898Sbill if (cursym.n_type & N_STAB) 1252898Sbill return; 1253898Sbill printf("%s", filname); 1254898Sbill if (archdr.ar_name[0]) 1255898Sbill printf("(%s)", archdr.ar_name); 1256898Sbill printf(": "); 1257898Sbill if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) { 1258898Sbill printf("definition of common %s size %d\n", 1259898Sbill cursym.n_un.n_name, cursym.n_value); 1260898Sbill return; 1261898Sbill } 1262898Sbill for (tp = tynames; tp->ty_name; tp++) 1263898Sbill if (tp->ty_value == (cursym.n_type&N_TYPE)) 1264898Sbill break; 1265898Sbill printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to"); 1266898Sbill if (cursym.n_type&N_EXT) 1267898Sbill printf(" external"); 1268898Sbill if (tp->ty_name) 1269898Sbill printf(" %s", tp->ty_name); 1270898Sbill printf(" %s\n", cursym.n_un.n_name); 1271898Sbill } 1272898Sbill 1273650Sbill /* 1274650Sbill * This routine relocates the single text or data segment argument. 1275650Sbill * Offsets from external symbols are resolved by adding the value 1276650Sbill * of the external symbols. Non-external reference are updated to account 1277650Sbill * for the relative motion of the segments (ctrel, cdrel, ...). If 1278650Sbill * a relocation was pc-relative, then we update it to reflect the 1279650Sbill * change in the positioning of the segments by adding the displacement 1280650Sbill * of the referenced segment and subtracting the displacement of the 1281650Sbill * current segment (creloc). 1282650Sbill * 1283650Sbill * If we are saving the relocation information, then we increase 1284650Sbill * each relocation datum address by our base position in the new segment. 1285650Sbill */ 1286650Sbill load2td(creloc, position, b1, b2) 1287650Sbill long creloc, offset; 1288615Sbill struct biobuf *b1, *b2; 1289615Sbill { 1290615Sbill register struct nlist *sp; 1291615Sbill register struct local *lp; 1292615Sbill long tw; 1293615Sbill register struct relocation_info *rp, *rpend; 1294615Sbill struct relocation_info *relp; 1295615Sbill char *codep; 1296615Sbill register char *cp; 1297615Sbill int relsz, codesz; 1298615Sbill 1299615Sbill relsz = reloc.size; 1300615Sbill relp = (struct relocation_info *)malloc(relsz); 1301615Sbill codesz = text.size; 1302615Sbill codep = (char *)malloc(codesz); 1303615Sbill if (relp == 0 || codep == 0) 1304615Sbill error(1, "out of memory (load2td)"); 1305615Sbill mget((char *)relp, relsz, &reloc); 1306615Sbill rpend = &relp[relsz / sizeof (struct relocation_info)]; 1307615Sbill mget(codep, codesz, &text); 1308615Sbill for (rp = relp; rp < rpend; rp++) { 1309615Sbill cp = codep + rp->r_address; 1310650Sbill /* 1311650Sbill * Pick up previous value at location to be relocated. 1312650Sbill */ 1313615Sbill switch (rp->r_length) { 1314615Sbill 1315615Sbill case 0: /* byte */ 1316615Sbill tw = *cp; 1317615Sbill break; 1318615Sbill 1319615Sbill case 1: /* word */ 1320615Sbill tw = *(short *)cp; 1321615Sbill break; 1322615Sbill 1323615Sbill case 2: /* long */ 1324615Sbill tw = *(long *)cp; 1325615Sbill break; 1326615Sbill 1327615Sbill default: 1328615Sbill error(1, "load2td botch: bad length"); 1329615Sbill } 1330650Sbill /* 1331650Sbill * If relative to an external which is defined, 1332650Sbill * resolve to a simpler kind of reference in the 1333650Sbill * result file. If the external is undefined, just 1334650Sbill * convert the symbol number to the number of the 1335650Sbill * symbol in the result file and leave it undefined. 1336650Sbill */ 1337615Sbill if (rp->r_extern) { 1338650Sbill /* 1339650Sbill * Search the hash table which maps local 1340650Sbill * symbol numbers to symbol tables entries 1341650Sbill * in the new a.out file. 1342650Sbill */ 1343615Sbill lp = lochash[rp->r_symbolnum % LHSIZ]; 1344615Sbill while (lp->l_index != rp->r_symbolnum) { 1345615Sbill lp = lp->l_link; 1346615Sbill if (lp == 0) 1347615Sbill error(1, "local symbol botch"); 1348615Sbill } 1349615Sbill sp = lp->l_symbol; 1350615Sbill if (sp->n_type == N_EXT+N_UNDF) 1351615Sbill rp->r_symbolnum = nsym+symx(sp); 1352615Sbill else { 1353615Sbill rp->r_symbolnum = sp->n_type & N_TYPE; 1354615Sbill tw += sp->n_value; 1355615Sbill rp->r_extern = 0; 1356615Sbill } 1357615Sbill } else switch (rp->r_symbolnum & N_TYPE) { 1358650Sbill /* 1359650Sbill * Relocation is relative to the loaded position 1360650Sbill * of another segment. Update by the change in position 1361650Sbill * of that segment. 1362650Sbill */ 1363615Sbill case N_TEXT: 1364615Sbill tw += ctrel; 1365615Sbill break; 1366615Sbill case N_DATA: 1367615Sbill tw += cdrel; 1368615Sbill break; 1369615Sbill case N_BSS: 1370615Sbill tw += cbrel; 1371615Sbill break; 1372615Sbill case N_ABS: 1373615Sbill break; 1374615Sbill default: 1375615Sbill error(1, "relocation format botch (symbol type))"); 1376615Sbill } 1377650Sbill /* 1378650Sbill * Relocation is pc relative, so decrease the relocation 1379650Sbill * by the amount the current segment is displaced. 1380650Sbill * (E.g if we are a relative reference to a text location 1381650Sbill * from data space, we added the increase in the text address 1382650Sbill * above, and subtract the increase in our (data) address 1383650Sbill * here, leaving the net change the relative change in the 1384650Sbill * positioning of our text and data segments.) 1385650Sbill */ 1386615Sbill if (rp->r_pcrel) 1387615Sbill tw -= creloc; 1388650Sbill /* 1389650Sbill * Put the value back in the segment, 1390650Sbill * while checking for overflow. 1391650Sbill */ 1392615Sbill switch (rp->r_length) { 1393615Sbill 1394615Sbill case 0: /* byte */ 1395615Sbill if (tw < -128 || tw > 127) 1396615Sbill error(0, "byte displacement overflow"); 1397615Sbill *cp = tw; 1398615Sbill break; 1399615Sbill case 1: /* word */ 1400615Sbill if (tw < -32768 || tw > 32767) 1401615Sbill error(0, "word displacement overflow"); 1402615Sbill *(short *)cp = tw; 1403615Sbill break; 1404615Sbill case 2: /* long */ 1405615Sbill *(long *)cp = tw; 1406615Sbill break; 1407615Sbill } 1408650Sbill /* 1409650Sbill * If we are saving relocation information, 1410650Sbill * we must convert the address in the segment from 1411650Sbill * the old .o file into an address in the segment in 1412650Sbill * the new a.out, by adding the position of our 1413650Sbill * segment in the new larger segment. 1414650Sbill */ 1415615Sbill if (rflag) 1416650Sbill rp->r_address += position; 1417615Sbill } 1418615Sbill bwrite(codep, codesz, b1); 1419615Sbill if (rflag) 1420615Sbill bwrite(relp, relsz, b2); 1421615Sbill cfree((char *)relp); 1422615Sbill cfree(codep); 1423615Sbill } 1424615Sbill 1425615Sbill finishout() 1426615Sbill { 1427615Sbill register int i; 1428615Sbill int nsymt; 1429615Sbill 1430615Sbill if (sflag==0) { 1431615Sbill nsymt = symx(nextsym); 1432615Sbill for (i = 0; i < nsymt; i++) 1433615Sbill symwrite(xsym(i), sout); 1434615Sbill bwrite(&offset, sizeof offset, sout); 1435615Sbill } 1436615Sbill if (!ofilfnd) { 1437615Sbill unlink("a.out"); 1438898Sbill if (link("l.out", "a.out") < 0) 1439898Sbill error(1, "cannot move l.out to a.out"); 1440615Sbill ofilename = "a.out"; 1441615Sbill } 1442615Sbill delarg = errlev; 1443615Sbill delexit(); 1444615Sbill } 1445615Sbill 1446615Sbill mkfsym(s) 1447615Sbill char *s; 1448615Sbill { 1449615Sbill 1450615Sbill if (sflag || xflag) 1451615Sbill return; 1452615Sbill cursym.n_un.n_name = s; 1453615Sbill cursym.n_type = N_TEXT; 1454615Sbill cursym.n_value = torigin; 1455615Sbill symwrite(&cursym, sout); 1456615Sbill } 1457615Sbill 1458615Sbill getarhdr() 1459615Sbill { 1460615Sbill register char *cp; 1461615Sbill 1462615Sbill mget((char *)&archdr, sizeof archdr, &text); 1463615Sbill for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];) 1464615Sbill if (*cp++ == ' ') { 1465615Sbill cp[-1] = 0; 1466615Sbill return; 1467615Sbill } 1468615Sbill } 1469615Sbill 1470615Sbill mget(loc, n, sp) 1471615Sbill register STREAM *sp; 1472615Sbill register char *loc; 1473615Sbill { 1474615Sbill register char *p; 1475615Sbill register int take; 1476615Sbill 1477615Sbill top: 1478615Sbill if (n == 0) 1479615Sbill return; 1480615Sbill if (sp->size && sp->nibuf) { 1481615Sbill p = sp->ptr; 1482615Sbill take = sp->size; 1483615Sbill if (take > sp->nibuf) 1484615Sbill take = sp->nibuf; 1485615Sbill if (take > n) 1486615Sbill take = n; 1487615Sbill n -= take; 1488615Sbill sp->size -= take; 1489615Sbill sp->nibuf -= take; 1490615Sbill sp->pos += take; 1491615Sbill do 1492615Sbill *loc++ = *p++; 1493615Sbill while (--take > 0); 1494615Sbill sp->ptr = p; 1495615Sbill goto top; 1496615Sbill } 1497*16068Sralph if (n > p_blksize) { 1498*16068Sralph take = n - n % p_blksize; 1499*16068Sralph lseek(infil, (sp->bno+1)<<p_blkshift, 0); 1500615Sbill if (take > sp->size || read(infil, loc, take) != take) 1501615Sbill error(1, "premature EOF"); 1502615Sbill loc += take; 1503615Sbill n -= take; 1504615Sbill sp->size -= take; 1505615Sbill sp->pos += take; 1506*16068Sralph dseek(sp, (sp->bno+1+(take>>p_blkshift))<<p_blkshift, -1); 1507615Sbill goto top; 1508615Sbill } 1509615Sbill *loc++ = get(sp); 1510615Sbill --n; 1511615Sbill goto top; 1512615Sbill } 1513615Sbill 1514615Sbill symwrite(sp, bp) 1515615Sbill struct nlist *sp; 1516615Sbill struct biobuf *bp; 1517615Sbill { 1518615Sbill register int len; 1519615Sbill register char *str; 1520615Sbill 1521615Sbill str = sp->n_un.n_name; 1522615Sbill if (str) { 1523615Sbill sp->n_un.n_strx = offset; 1524615Sbill len = strlen(str) + 1; 1525615Sbill bwrite(str, len, strout); 1526615Sbill offset += len; 1527615Sbill } 1528615Sbill bwrite(sp, sizeof (*sp), bp); 1529615Sbill sp->n_un.n_name = str; 1530615Sbill } 1531615Sbill 1532615Sbill dseek(sp, loc, s) 1533615Sbill register STREAM *sp; 1534615Sbill long loc, s; 1535615Sbill { 1536615Sbill register PAGE *p; 1537615Sbill register b, o; 1538615Sbill int n; 1539615Sbill 1540*16068Sralph b = loc>>p_blkshift; 1541*16068Sralph o = loc&p_blkmask; 1542615Sbill if (o&01) 1543615Sbill error(1, "loader error; odd offset"); 1544615Sbill --sp->pno->nuser; 1545615Sbill if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b) 1546615Sbill if (p->nuser==0 || (p = &page[0])->nuser==0) { 1547615Sbill if (page[0].nuser==0 && page[1].nuser==0) 1548615Sbill if (page[0].bno < page[1].bno) 1549615Sbill p = &page[0]; 1550615Sbill p->bno = b; 1551*16068Sralph lseek(infil, loc & ~(long)p_blkmask, 0); 1552*16068Sralph if ((n = read(infil, p->buff, p_blksize)) < 0) 1553615Sbill n = 0; 1554615Sbill p->nibuf = n; 1555*16068Sralph } else 1556*16068Sralph error(1, "botch: no pages"); 1557615Sbill ++p->nuser; 1558615Sbill sp->bno = b; 1559615Sbill sp->pno = p; 1560615Sbill if (s != -1) {sp->size = s; sp->pos = 0;} 1561615Sbill sp->ptr = (char *)(p->buff + o); 1562615Sbill if ((sp->nibuf = p->nibuf-o) <= 0) 1563615Sbill sp->size = 0; 1564615Sbill } 1565615Sbill 1566615Sbill char 1567615Sbill get(asp) 1568615Sbill STREAM *asp; 1569615Sbill { 1570615Sbill register STREAM *sp; 1571615Sbill 1572615Sbill sp = asp; 1573615Sbill if ((sp->nibuf -= sizeof(char)) < 0) { 1574*16068Sralph dseek(sp, ((long)(sp->bno+1)<<p_blkshift), (long)-1); 1575615Sbill sp->nibuf -= sizeof(char); 1576615Sbill } 1577615Sbill if ((sp->size -= sizeof(char)) <= 0) { 1578615Sbill if (sp->size < 0) 1579615Sbill error(1, "premature EOF"); 1580615Sbill ++fpage.nuser; 1581615Sbill --sp->pno->nuser; 1582615Sbill sp->pno = (PAGE *) &fpage; 1583615Sbill } 1584615Sbill sp->pos += sizeof(char); 1585615Sbill return(*sp->ptr++); 1586615Sbill } 1587615Sbill 1588615Sbill getfile(acp) 1589615Sbill char *acp; 1590615Sbill { 1591615Sbill register char *cp; 1592615Sbill register int c; 1593615Sbill char arcmag[SARMAG+1]; 1594615Sbill struct stat stb; 1595615Sbill 1596615Sbill infil = -1; 1597615Sbill archdr.ar_name[0] = '\0'; 1598*16068Sralph filname = cp = acp; 1599615Sbill if (cp[0]=='-' && cp[1]=='l') { 1600898Sbill char *locfilname = "/usr/local/lib/libxxxxxxxxxxxxxxx"; 1601615Sbill if(cp[2] == '\0') 1602615Sbill cp = "-la"; 1603898Sbill filname = "/usr/lib/libxxxxxxxxxxxxxxx"; 1604615Sbill for(c=0; cp[c+2]; c++) { 1605615Sbill filname[c+12] = cp[c+2]; 1606615Sbill locfilname[c+18] = cp[c+2]; 1607615Sbill } 1608615Sbill filname[c+12] = locfilname[c+18] = '.'; 1609615Sbill filname[c+13] = locfilname[c+19] = 'a'; 1610615Sbill filname[c+14] = locfilname[c+20] = '\0'; 1611615Sbill if ((infil = open(filname+4, 0)) >= 0) { 1612615Sbill filname += 4; 1613615Sbill } else if ((infil = open(filname, 0)) < 0) { 1614615Sbill filname = locfilname; 1615615Sbill } 1616615Sbill } 1617615Sbill if (infil == -1 && (infil = open(filname, 0)) < 0) 1618615Sbill error(1, "cannot open"); 1619*16068Sralph fstat(infil, &stb); 1620615Sbill page[0].bno = page[1].bno = -1; 1621615Sbill page[0].nuser = page[1].nuser = 0; 1622*16068Sralph c = stb.st_blksize; 1623*16068Sralph if (c == 0 || (c & (c - 1)) != 0) { 1624*16068Sralph /* use default size if not a power of two */ 1625*16068Sralph c = BLKSIZE; 1626*16068Sralph } 1627*16068Sralph if (p_blksize != c) { 1628*16068Sralph p_blksize = c; 1629*16068Sralph p_blkmask = c - 1; 1630*16068Sralph for (p_blkshift = 0; c > 1 ; p_blkshift++) 1631*16068Sralph c >>= 1; 1632*16068Sralph if (page[0].buff != NULL) 1633*16068Sralph free(page[0].buff); 1634*16068Sralph page[0].buff = (char *)malloc(p_blksize); 1635*16068Sralph if (page[0].buff == NULL) 1636*16068Sralph error(1, "ran out of memory (getfile)"); 1637*16068Sralph if (page[1].buff != NULL) 1638*16068Sralph free(page[1].buff); 1639*16068Sralph page[1].buff = (char *)malloc(p_blksize); 1640*16068Sralph if (page[1].buff == NULL) 1641*16068Sralph error(1, "ran out of memory (getfile)"); 1642*16068Sralph } 1643615Sbill text.pno = reloc.pno = (PAGE *) &fpage; 1644615Sbill fpage.nuser = 2; 1645615Sbill dseek(&text, 0L, SARMAG); 1646615Sbill if (text.size <= 0) 1647615Sbill error(1, "premature EOF"); 1648615Sbill mget((char *)arcmag, SARMAG, &text); 1649615Sbill arcmag[SARMAG] = 0; 1650615Sbill if (strcmp(arcmag, ARMAG)) 1651615Sbill return (0); 1652615Sbill dseek(&text, SARMAG, sizeof archdr); 1653615Sbill if(text.size <= 0) 1654615Sbill return (1); 1655615Sbill getarhdr(); 1656615Sbill if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0) 1657615Sbill return (1); 1658615Sbill return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2); 1659615Sbill } 1660615Sbill 1661615Sbill struct nlist ** 1662615Sbill lookup() 1663615Sbill { 1664615Sbill register int sh; 1665615Sbill register struct nlist **hp; 1666615Sbill register char *cp, *cp1; 1667615Sbill register struct symseg *gp; 1668615Sbill register int i; 1669615Sbill 1670615Sbill sh = 0; 1671615Sbill for (cp = cursym.n_un.n_name; *cp;) 1672615Sbill sh = (sh<<1) + *cp++; 1673615Sbill sh = (sh & 0x7fffffff) % HSIZE; 1674615Sbill for (gp = symseg; gp < &symseg[NSEG]; gp++) { 1675615Sbill if (gp->sy_first == 0) { 1676615Sbill gp->sy_first = (struct nlist *) 1677615Sbill calloc(NSYM, sizeof (struct nlist)); 1678615Sbill gp->sy_hfirst = (struct nlist **) 1679615Sbill calloc(HSIZE, sizeof (struct nlist *)); 1680615Sbill if (gp->sy_first == 0 || gp->sy_hfirst == 0) 1681615Sbill error(1, "ran out of space for symbol table"); 1682615Sbill gp->sy_last = gp->sy_first + NSYM; 1683615Sbill gp->sy_hlast = gp->sy_hfirst + HSIZE; 1684615Sbill } 1685615Sbill if (gp > csymseg) 1686615Sbill csymseg = gp; 1687615Sbill hp = gp->sy_hfirst + sh; 1688615Sbill i = 1; 1689615Sbill do { 1690615Sbill if (*hp == 0) { 1691615Sbill if (gp->sy_used == NSYM) 1692615Sbill break; 1693615Sbill return (hp); 1694615Sbill } 1695615Sbill cp1 = (*hp)->n_un.n_name; 1696615Sbill for (cp = cursym.n_un.n_name; *cp == *cp1++;) 1697615Sbill if (*cp++ == 0) 1698615Sbill return (hp); 1699615Sbill hp += i; 1700615Sbill i += 2; 1701615Sbill if (hp >= gp->sy_hlast) 1702615Sbill hp -= HSIZE; 1703615Sbill } while (i < HSIZE); 1704615Sbill if (i > HSIZE) 1705615Sbill error(1, "hash table botch"); 1706615Sbill } 1707615Sbill error(1, "symbol table overflow"); 1708615Sbill /*NOTREACHED*/ 1709615Sbill } 1710615Sbill 1711615Sbill symfree(saved) 1712615Sbill struct nlist *saved; 1713615Sbill { 1714615Sbill register struct symseg *gp; 1715615Sbill register struct nlist *sp; 1716615Sbill 1717615Sbill for (gp = csymseg; gp >= symseg; gp--, csymseg--) { 1718615Sbill sp = gp->sy_first + gp->sy_used; 1719615Sbill if (sp == saved) { 1720615Sbill nextsym = sp; 1721615Sbill return; 1722615Sbill } 1723615Sbill for (sp--; sp >= gp->sy_first; sp--) { 1724615Sbill gp->sy_hfirst[sp->n_hash] = 0; 1725615Sbill gp->sy_used--; 1726615Sbill if (sp == saved) { 1727615Sbill nextsym = sp; 1728615Sbill return; 1729615Sbill } 1730615Sbill } 1731615Sbill } 1732615Sbill if (saved == 0) 1733615Sbill return; 1734615Sbill error(1, "symfree botch"); 1735615Sbill } 1736615Sbill 1737615Sbill struct nlist ** 1738615Sbill slookup(s) 1739615Sbill char *s; 1740615Sbill { 1741615Sbill 1742615Sbill cursym.n_un.n_name = s; 1743615Sbill cursym.n_type = N_EXT+N_UNDF; 1744615Sbill cursym.n_value = 0; 1745615Sbill return (lookup()); 1746615Sbill } 1747615Sbill 1748615Sbill enter(hp) 1749615Sbill register struct nlist **hp; 1750615Sbill { 1751615Sbill register struct nlist *sp; 1752615Sbill 1753615Sbill if (*hp==0) { 1754615Sbill if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast) 1755615Sbill error(1, "enter botch"); 1756615Sbill *hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used; 1757615Sbill csymseg->sy_used++; 1758615Sbill sp->n_un.n_name = cursym.n_un.n_name; 1759615Sbill sp->n_type = cursym.n_type; 1760615Sbill sp->n_hash = hp - csymseg->sy_hfirst; 1761615Sbill sp->n_value = cursym.n_value; 1762615Sbill nextsym = lastsym + 1; 1763615Sbill return(1); 1764615Sbill } else { 1765615Sbill lastsym = *hp; 1766615Sbill return(0); 1767615Sbill } 1768615Sbill } 1769615Sbill 1770615Sbill symx(sp) 1771615Sbill struct nlist *sp; 1772615Sbill { 1773615Sbill register struct symseg *gp; 1774615Sbill 1775615Sbill if (sp == 0) 1776615Sbill return (0); 1777615Sbill for (gp = csymseg; gp >= symseg; gp--) 1778615Sbill /* <= is sloppy so nextsym will always work */ 1779615Sbill if (sp >= gp->sy_first && sp <= gp->sy_last) 1780615Sbill return ((gp - symseg) * NSYM + sp - gp->sy_first); 1781615Sbill error(1, "symx botch"); 1782615Sbill /*NOTREACHED*/ 1783615Sbill } 1784615Sbill 1785615Sbill symreloc() 1786615Sbill { 1787615Sbill if(funding) return; 1788615Sbill switch (cursym.n_type & 017) { 1789615Sbill 1790615Sbill case N_TEXT: 1791615Sbill case N_EXT+N_TEXT: 1792615Sbill cursym.n_value += ctrel; 1793615Sbill return; 1794615Sbill 1795615Sbill case N_DATA: 1796615Sbill case N_EXT+N_DATA: 1797615Sbill cursym.n_value += cdrel; 1798615Sbill return; 1799615Sbill 1800615Sbill case N_BSS: 1801615Sbill case N_EXT+N_BSS: 1802615Sbill cursym.n_value += cbrel; 1803615Sbill return; 1804615Sbill 1805615Sbill case N_EXT+N_UNDF: 1806615Sbill return; 1807615Sbill 1808615Sbill default: 1809615Sbill if (cursym.n_type&N_EXT) 1810615Sbill cursym.n_type = N_EXT+N_ABS; 1811615Sbill return; 1812615Sbill } 1813615Sbill } 1814615Sbill 1815615Sbill error(n, s) 1816615Sbill char *s; 1817615Sbill { 1818898Sbill 1819615Sbill if (errlev==0) 1820615Sbill printf("ld:"); 1821615Sbill if (filname) { 1822615Sbill printf("%s", filname); 1823615Sbill if (n != -1 && archdr.ar_name[0]) 1824615Sbill printf("(%s)", archdr.ar_name); 1825615Sbill printf(": "); 1826615Sbill } 1827615Sbill printf("%s\n", s); 1828615Sbill if (n == -1) 1829615Sbill return; 1830615Sbill if (n) 1831615Sbill delexit(); 1832615Sbill errlev = 2; 1833615Sbill } 1834615Sbill 1835615Sbill readhdr(loc) 1836615Sbill off_t loc; 1837615Sbill { 1838615Sbill 1839615Sbill dseek(&text, loc, (long)sizeof(filhdr)); 1840615Sbill mget((short *)&filhdr, sizeof(filhdr), &text); 1841615Sbill if (N_BADMAG(filhdr)) { 1842615Sbill if (filhdr.a_magic == OARMAG) 1843615Sbill error(1, "old archive"); 1844615Sbill error(1, "bad magic number"); 1845615Sbill } 1846615Sbill if (filhdr.a_text&01 || filhdr.a_data&01) 1847615Sbill error(1, "text/data size odd"); 1848615Sbill if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) { 184912671Ssam cdrel = -round(filhdr.a_text, pagesize); 1850615Sbill cbrel = cdrel - filhdr.a_data; 1851615Sbill } else if (filhdr.a_magic == OMAGIC) { 1852615Sbill cdrel = -filhdr.a_text; 1853615Sbill cbrel = cdrel - filhdr.a_data; 1854615Sbill } else 1855615Sbill error(1, "bad format"); 1856615Sbill } 1857615Sbill 1858615Sbill round(v, r) 1859615Sbill int v; 1860615Sbill u_long r; 1861615Sbill { 1862615Sbill 1863615Sbill r--; 1864615Sbill v += r; 1865615Sbill v &= ~(long)r; 1866615Sbill return(v); 1867615Sbill } 1868615Sbill 1869615Sbill #define NSAVETAB 8192 1870615Sbill char *savetab; 1871615Sbill int saveleft; 1872615Sbill 1873615Sbill char * 1874615Sbill savestr(cp) 1875615Sbill register char *cp; 1876615Sbill { 1877615Sbill register int len; 1878615Sbill 1879615Sbill len = strlen(cp) + 1; 1880615Sbill if (len > saveleft) { 1881615Sbill saveleft = NSAVETAB; 1882615Sbill if (len > saveleft) 1883615Sbill saveleft = len; 1884615Sbill savetab = (char *)malloc(saveleft); 1885615Sbill if (savetab == 0) 1886615Sbill error(1, "ran out of memory (savestr)"); 1887615Sbill } 1888615Sbill strncpy(savetab, cp, len); 1889615Sbill cp = savetab; 1890615Sbill savetab += len; 1891615Sbill saveleft -= len; 1892615Sbill return (cp); 1893615Sbill } 1894615Sbill 1895*16068Sralph bopen(bp, off, bufsize) 1896*16068Sralph register struct biobuf *bp; 1897615Sbill { 1898615Sbill 1899*16068Sralph bp->b_ptr = bp->b_buf = (char *)malloc(bufsize); 1900*16068Sralph if (bp->b_ptr == (char *)0) 1901*16068Sralph error(1, "ran out of memory (bopen)"); 1902*16068Sralph bp->b_bufsize = bufsize; 1903*16068Sralph bp->b_nleft = bufsize - (off % bufsize); 1904615Sbill bp->b_off = off; 1905615Sbill bp->b_link = biobufs; 1906615Sbill biobufs = bp; 1907615Sbill } 1908615Sbill 1909615Sbill int bwrerror; 1910615Sbill 1911615Sbill bwrite(p, cnt, bp) 1912615Sbill register char *p; 1913615Sbill register int cnt; 1914615Sbill register struct biobuf *bp; 1915615Sbill { 1916615Sbill register int put; 1917615Sbill register char *to; 1918615Sbill 1919615Sbill top: 1920615Sbill if (cnt == 0) 1921615Sbill return; 1922615Sbill if (bp->b_nleft) { 1923615Sbill put = bp->b_nleft; 1924615Sbill if (put > cnt) 1925615Sbill put = cnt; 1926615Sbill bp->b_nleft -= put; 1927615Sbill to = bp->b_ptr; 1928615Sbill asm("movc3 r8,(r11),(r7)"); 1929615Sbill bp->b_ptr += put; 1930615Sbill p += put; 1931615Sbill cnt -= put; 1932615Sbill goto top; 1933615Sbill } 1934*16068Sralph if (cnt >= bp->b_bufsize) { 1935615Sbill if (bp->b_ptr != bp->b_buf) 1936615Sbill bflush1(bp); 1937*16068Sralph put = cnt - cnt % bp->b_bufsize; 1938615Sbill if (boffset != bp->b_off) 1939615Sbill lseek(biofd, bp->b_off, 0); 1940615Sbill if (write(biofd, p, put) != put) { 1941615Sbill bwrerror = 1; 1942615Sbill error(1, "output write error"); 1943615Sbill } 1944615Sbill bp->b_off += put; 1945615Sbill boffset = bp->b_off; 1946615Sbill p += put; 1947615Sbill cnt -= put; 1948615Sbill goto top; 1949615Sbill } 1950615Sbill bflush1(bp); 1951615Sbill goto top; 1952615Sbill } 1953615Sbill 1954615Sbill bflush() 1955615Sbill { 1956615Sbill register struct biobuf *bp; 1957615Sbill 1958615Sbill if (bwrerror) 1959615Sbill return; 1960615Sbill for (bp = biobufs; bp; bp = bp->b_link) 1961615Sbill bflush1(bp); 1962615Sbill } 1963615Sbill 1964615Sbill bflush1(bp) 1965615Sbill register struct biobuf *bp; 1966615Sbill { 1967615Sbill register int cnt = bp->b_ptr - bp->b_buf; 1968615Sbill 1969615Sbill if (cnt == 0) 1970615Sbill return; 1971615Sbill if (boffset != bp->b_off) 1972615Sbill lseek(biofd, bp->b_off, 0); 1973615Sbill if (write(biofd, bp->b_buf, cnt) != cnt) { 1974615Sbill bwrerror = 1; 1975615Sbill error(1, "output write error"); 1976615Sbill } 1977615Sbill bp->b_off += cnt; 1978615Sbill boffset = bp->b_off; 1979615Sbill bp->b_ptr = bp->b_buf; 1980*16068Sralph bp->b_nleft = bp->b_bufsize; 1981615Sbill } 1982615Sbill 1983615Sbill bflushc(bp, c) 1984615Sbill register struct biobuf *bp; 1985615Sbill { 1986615Sbill 1987615Sbill bflush1(bp); 1988615Sbill bputc(c, bp); 1989615Sbill } 1990*16068Sralph 1991*16068Sralph bseek(bp, off) 1992*16068Sralph register struct biobuf *bp; 1993*16068Sralph register off_t off; 1994*16068Sralph { 1995*16068Sralph bflush1(bp); 1996*16068Sralph 1997*16068Sralph bp->b_nleft = bp->b_bufsize - (off % bp->b_bufsize); 1998*16068Sralph bp->b_off = off; 1999*16068Sralph } 2000