119842Sdist /* 219842Sdist * Copyright (c) 1980 Regents of the University of California. 319842Sdist * All rights reserved. The Berkeley software License Agreement 419842Sdist * specifies the terms and conditions for redistribution. 519842Sdist */ 619842Sdist 712671Ssam #ifndef lint 819842Sdist char copyright[] = 919842Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1019842Sdist All rights reserved.\n"; 1119842Sdist #endif not lint 126414Smckusic 1319842Sdist #ifndef lint 14*29845Ssam static char sccsid[] = "@(#)ld.c 5.5 (Berkeley) 10/13/86"; 1519842Sdist #endif not lint 1619842Sdist 17615Sbill /* 18898Sbill * ld - string table version for VAX 19615Sbill */ 20615Sbill 2117133Ssam #include <sys/param.h> 22615Sbill #include <signal.h> 23615Sbill #include <stdio.h> 24615Sbill #include <ctype.h> 25650Sbill #include <ar.h> 26650Sbill #include <a.out.h> 27615Sbill #include <ranlib.h> 2813591Swnj #include <sys/stat.h> 2917133Ssam #include <sys/file.h> 30615Sbill 31615Sbill /* 32615Sbill * Basic strategy: 33615Sbill * 34615Sbill * The loader takes a number of files and libraries as arguments. 35615Sbill * A first pass examines each file in turn. Normal files are 36615Sbill * unconditionally loaded, and the (external) symbols they define and require 37615Sbill * are noted in the symbol table. Libraries are searched, and the 38615Sbill * library members which define needed symbols are remembered 39615Sbill * in a special data structure so they can be selected on the second 40615Sbill * pass. Symbols defined and required by library members are also 41615Sbill * recorded. 42615Sbill * 43615Sbill * After the first pass, the loader knows the size of the basic text 44615Sbill * data, and bss segments from the sum of the sizes of the modules which 45615Sbill * were required. It has computed, for each ``common'' symbol, the 46615Sbill * maximum size of any reference to it, and these symbols are then assigned 47615Sbill * storage locations after their sizes are appropriately rounded. 48615Sbill * The loader now knows all sizes for the eventual output file, and 49615Sbill * can determine the final locations of external symbols before it 50615Sbill * begins a second pass. 51615Sbill * 52615Sbill * On the second pass each normal file and required library member 53615Sbill * is processed again. The symbol table for each such file is 54615Sbill * reread and relevant parts of it are placed in the output. The offsets 55615Sbill * in the local symbol table for externally defined symbols are recorded 56615Sbill * since relocation information refers to symbols in this way. 57615Sbill * Armed with all necessary information, the text and data segments 58615Sbill * are relocated and the result is placed in the output file, which 59615Sbill * is pasted together, ``in place'', by writing to it in several 60615Sbill * different places concurrently. 61615Sbill */ 62615Sbill 63615Sbill /* 64615Sbill * Internal data structures 65615Sbill * 66615Sbill * All internal data structures are segmented and dynamically extended. 67615Sbill * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT) 68615Sbill * referenced library members, and 100 (NSYMPR) private (local) symbols 69615Sbill * per object module. For large programs and/or modules, these structures 70615Sbill * expand to be up to 40 (NSEG) times as large as this as necessary. 71615Sbill */ 72615Sbill #define NSEG 40 /* Number of segments, each data structure */ 73615Sbill #define NSYM 1103 /* Number of symbols per segment */ 74615Sbill #define NROUT 250 /* Number of library references per segment */ 75615Sbill #define NSYMPR 100 /* Number of private symbols per segment */ 76615Sbill 77615Sbill /* 78615Sbill * Structure describing each symbol table segment. 79615Sbill * Each segment has its own hash table. We record the first 80615Sbill * address in and first address beyond both the symbol and hash 81615Sbill * tables, for use in the routine symx and the lookup routine respectively. 82615Sbill * The symfree routine also understands this structure well as it used 83615Sbill * to back out symbols from modules we decide that we don't need in pass 1. 84615Sbill * 85615Sbill * Csymseg points to the current symbol table segment; 86615Sbill * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated, 87615Sbill * (unless csymseg->sy_used == NSYM in which case we will allocate another 88615Sbill * symbol table segment first.) 89615Sbill */ 90615Sbill struct symseg { 91615Sbill struct nlist *sy_first; /* base of this alloc'ed segment */ 92615Sbill struct nlist *sy_last; /* end of this segment, for n_strx */ 93615Sbill int sy_used; /* symbols used in this seg */ 94615Sbill struct nlist **sy_hfirst; /* base of hash table, this seg */ 95615Sbill struct nlist **sy_hlast; /* end of hash table, this seg */ 96615Sbill } symseg[NSEG], *csymseg; 97615Sbill 98615Sbill /* 99615Sbill * The lookup routine uses quadratic rehash. Since a quadratic rehash 100615Sbill * only probes 1/2 of the buckets in the table, and since the hash 101615Sbill * table is segmented the same way the symbol table is, we make the 102615Sbill * hash table have twice as many buckets as there are symbol table slots 103615Sbill * in the segment. This guarantees that the quadratic rehash will never 104615Sbill * fail to find an empty bucket if the segment is not full and the 105615Sbill * symbol is not there. 106615Sbill */ 107615Sbill #define HSIZE (NSYM*2) 108615Sbill 109615Sbill /* 110615Sbill * Xsym converts symbol table indices (ala x) into symbol table pointers. 111615Sbill * Symx (harder, but never used in loops) inverts pointers into the symbol 112615Sbill * table into indices using the symseg[] structure. 113615Sbill */ 114615Sbill #define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM)) 115615Sbill /* symx() is a function, defined below */ 116615Sbill 117615Sbill struct nlist cursym; /* current symbol */ 118615Sbill struct nlist *lastsym; /* last symbol entered */ 119615Sbill struct nlist *nextsym; /* next available symbol table entry */ 120615Sbill struct nlist *addsym; /* first sym defined during incr load */ 121615Sbill int nsym; /* pass2: number of local symbols in a.out */ 122615Sbill /* nsym + symx(nextsym) is the symbol table size during pass2 */ 123615Sbill 124615Sbill struct nlist **lookup(), **slookup(); 125650Sbill struct nlist *p_etext, *p_edata, *p_end, *entrypt; 126615Sbill 127615Sbill /* 128615Sbill * Definitions of segmentation for library member table. 129615Sbill * For each library we encounter on pass 1 we record pointers to all 130615Sbill * members which we will load on pass 2. These are recorded as offsets 131615Sbill * into the archive in the library member table. Libraries are 132615Sbill * separated in the table by the special offset value -1. 133615Sbill */ 134615Sbill off_t li_init[NROUT]; 135615Sbill struct libseg { 136615Sbill off_t *li_first; 137615Sbill int li_used; 138615Sbill int li_used2; 139615Sbill } libseg[NSEG] = { 140615Sbill li_init, 0, 0, 141615Sbill }, *clibseg = libseg; 142615Sbill 143615Sbill /* 144615Sbill * In processing each module on pass 2 we must relocate references 145615Sbill * relative to external symbols. These references are recorded 146615Sbill * in the relocation information as relative to local symbol numbers 147615Sbill * assigned to the external symbols when the module was created. 148615Sbill * Thus before relocating the module in pass 2 we create a table 149615Sbill * which maps these internal numbers to symbol table entries. 150615Sbill * A hash table is constructed, based on the local symbol table indices, 151615Sbill * for quick lookup of these symbols. 152615Sbill */ 153615Sbill #define LHSIZ 31 154615Sbill struct local { 155615Sbill int l_index; /* index to symbol in file */ 156615Sbill struct nlist *l_symbol; /* ptr to symbol table */ 157615Sbill struct local *l_link; /* hash link */ 158615Sbill } *lochash[LHSIZ], lhinit[NSYMPR]; 159615Sbill struct locseg { 160615Sbill struct local *lo_first; 161615Sbill int lo_used; 162615Sbill } locseg[NSEG] = { 163615Sbill lhinit, 0 164615Sbill }, *clocseg; 165615Sbill 166615Sbill /* 167615Sbill * Libraries are typically built with a table of contents, 168615Sbill * which is the first member of a library with special file 169615Sbill * name __.SYMDEF and contains a list of symbol names 170615Sbill * and with each symbol the offset of the library member which defines 171615Sbill * it. The loader uses this table to quickly tell which library members 172615Sbill * are (potentially) useful. The alternative, examining the symbol 173615Sbill * table of each library member, is painfully slow for large archives. 174615Sbill * 175615Sbill * See <ranlib.h> for the definition of the ranlib structure and an 176615Sbill * explanation of the __.SYMDEF file format. 177615Sbill */ 178615Sbill int tnum; /* number of symbols in table of contents */ 179615Sbill int ssiz; /* size of string table for table of contents */ 180615Sbill struct ranlib *tab; /* the table of contents (dynamically allocated) */ 181615Sbill char *tabstr; /* string table for table of contents */ 182615Sbill 183615Sbill /* 184615Sbill * We open each input file or library only once, but in pass2 we 185615Sbill * (historically) read from such a file at 2 different places at the 186615Sbill * same time. These structures are remnants from those days, 187650Sbill * and now serve only to catch ``Premature EOF''. 1886414Smckusic * In order to make I/O more efficient, we provide routines which 18916068Sralph * use the optimal block size returned by stat(). 190615Sbill */ 1916414Smckusic #define BLKSIZE 1024 192615Sbill typedef struct { 193615Sbill short *fakeptr; 194615Sbill int bno; 195615Sbill int nibuf; 196615Sbill int nuser; 19716068Sralph char *buff; 19816068Sralph int bufsize; 199615Sbill } PAGE; 200615Sbill 201615Sbill PAGE page[2]; 20216068Sralph int p_blksize; 20316068Sralph int p_blkshift; 20416068Sralph int p_blkmask; 205615Sbill 206615Sbill struct { 207615Sbill short *fakeptr; 208615Sbill int bno; 209615Sbill int nibuf; 210615Sbill int nuser; 211615Sbill } fpage; 212615Sbill 213615Sbill typedef struct { 214615Sbill char *ptr; 215615Sbill int bno; 216615Sbill int nibuf; 217615Sbill long size; 218615Sbill long pos; 219615Sbill PAGE *pno; 220615Sbill } STREAM; 221615Sbill 222615Sbill STREAM text; 223615Sbill STREAM reloc; 224615Sbill 225615Sbill /* 226615Sbill * Header from the a.out and the archive it is from (if any). 227615Sbill */ 228615Sbill struct exec filhdr; 229615Sbill struct ar_hdr archdr; 230615Sbill #define OARMAG 0177545 231615Sbill 232615Sbill /* 233615Sbill * Options. 234615Sbill */ 235615Sbill int trace; 236615Sbill int xflag; /* discard local symbols */ 237615Sbill int Xflag; /* discard locals starting with 'L' */ 238615Sbill int Sflag; /* discard all except locals and globals*/ 239615Sbill int rflag; /* preserve relocation bits, don't define common */ 240615Sbill int arflag; /* original copy of rflag */ 241615Sbill int sflag; /* discard all symbols */ 242898Sbill int Mflag; /* print rudimentary load map */ 243615Sbill int nflag; /* pure procedure */ 244615Sbill int dflag; /* define common even with rflag */ 245650Sbill int zflag; /* demand paged */ 246615Sbill long hsize; /* size of hole at beginning of data to be squashed */ 247615Sbill int Aflag; /* doing incremental load */ 248650Sbill int Nflag; /* want impure a.out */ 249615Sbill int funding; /* reading fundamental file for incremental load */ 250898Sbill int yflag; /* number of symbols to be traced */ 251898Sbill char **ytab; /* the symbols */ 252615Sbill 253615Sbill /* 254615Sbill * These are the cumulative sizes, set in pass 1, which 255615Sbill * appear in the a.out header when the loader is finished. 256615Sbill */ 257615Sbill off_t tsize, dsize, bsize, trsize, drsize, ssize; 258615Sbill 259615Sbill /* 260615Sbill * Symbol relocation: c?rel is a scale factor which is 261615Sbill * added to an old relocation to convert it to new units; 262615Sbill * i.e. it is the difference between segment origins. 263650Sbill * (Thus if we are loading from a data segment which began at location 264650Sbill * 4 in a .o file into an a.out where it will be loaded starting at 265650Sbill * 1024, cdrel will be 1020.) 266615Sbill */ 267615Sbill long ctrel, cdrel, cbrel; 268615Sbill 269615Sbill /* 270650Sbill * Textbase is the start address of all text, 0 unless given by -T. 271615Sbill * Database is the base of all data, computed before and used during pass2. 272650Sbill */ 273650Sbill long textbase, database; 274650Sbill 275650Sbill /* 276615Sbill * The base addresses for the loaded text, data and bss from the 277615Sbill * current module during pass2 are given by torigin, dorigin and borigin. 278615Sbill */ 279615Sbill long torigin, dorigin, borigin; 280615Sbill 281615Sbill /* 282615Sbill * Errlev is nonzero when errors have occured. 283615Sbill * Delarg is an implicit argument to the routine delexit 284615Sbill * which is called on error. We do ``delarg = errlev'' before normal 285615Sbill * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the 286615Sbill * result file executable. 287615Sbill */ 288615Sbill int errlev; 289615Sbill int delarg = 4; 290615Sbill 291615Sbill /* 292615Sbill * The biobuf structure and associated routines are used to write 293615Sbill * into one file at several places concurrently. Calling bopen 294615Sbill * with a biobuf structure sets it up to write ``biofd'' starting 295615Sbill * at the specified offset. You can then use ``bwrite'' and/or ``bputc'' 296615Sbill * to stuff characters in the stream, much like ``fwrite'' and ``fputc''. 297615Sbill * Calling bflush drains all the buffers and MUST be done before exit. 298615Sbill */ 299615Sbill struct biobuf { 300615Sbill short b_nleft; /* Number free spaces left in b_buf */ 30116068Sralph /* Initialize to be less than b_bufsize initially, to boundary align in file */ 302615Sbill char *b_ptr; /* Next place to stuff characters */ 30316068Sralph char *b_buf; /* Pointer to the buffer */ 30416068Sralph int b_bufsize; /* Size of the buffer */ 305615Sbill off_t b_off; /* Current file offset */ 306615Sbill struct biobuf *b_link; /* Link in chain for bflush() */ 307615Sbill } *biobufs; 308615Sbill #define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \ 309615Sbill : bflushc(b, c)) 310615Sbill int biofd; 311615Sbill off_t boffset; 312615Sbill struct biobuf *tout, *dout, *trout, *drout, *sout, *strout; 313615Sbill 314615Sbill /* 315615Sbill * Offset is the current offset in the string file. 316615Sbill * Its initial value reflects the fact that we will 317615Sbill * eventually stuff the size of the string table at the 318615Sbill * beginning of the string table (i.e. offset itself!). 319615Sbill */ 320615Sbill off_t offset = sizeof (off_t); 321615Sbill 322615Sbill int ofilfnd; /* -o given; otherwise move l.out to a.out */ 323615Sbill char *ofilename = "l.out"; 3243606Ssklower int ofilemode; /* respect umask even for unsucessful ld's */ 325615Sbill int infil; /* current input file descriptor */ 326615Sbill char *filname; /* and its name */ 327615Sbill 32817133Ssam #define NDIRS 25 32925533Sbloom #define NDEFDIRS 3 /* number of default directories in dirs[] */ 33017133Ssam char *dirs[NDIRS]; /* directories for library search */ 33117133Ssam int ndir; /* number of directories */ 33217133Ssam 333615Sbill /* 334615Sbill * Base of the string table of the current module (pass1 and pass2). 335615Sbill */ 336615Sbill char *curstr; 337615Sbill 33812671Ssam /* 33912671Ssam * System software page size, as returned by getpagesize. 34012671Ssam */ 34112671Ssam int pagesize; 34212671Ssam 343615Sbill char get(); 344615Sbill int delexit(); 345615Sbill char *savestr(); 34617133Ssam char *malloc(); 347615Sbill 348615Sbill main(argc, argv) 349615Sbill char **argv; 350615Sbill { 351615Sbill register int c, i; 352615Sbill int num; 353615Sbill register char *ap, **p; 354615Sbill char save; 355615Sbill 356650Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 357615Sbill signal(SIGINT, delexit); 358650Sbill signal(SIGTERM, delexit); 359650Sbill } 360615Sbill if (argc == 1) 361615Sbill exit(4); 36212671Ssam pagesize = getpagesize(); 363615Sbill 36417133Ssam /* 36517133Ssam * Pull out search directories. 36617133Ssam */ 36717133Ssam for (c = 1; c < argc; c++) { 36817133Ssam ap = argv[c]; 36917133Ssam if (ap[0] == '-' && ap[1] == 'L') { 37017133Ssam if (ap[2] == 0) 37117133Ssam error(1, "-L: pathname missing"); 37225533Sbloom if (ndir >= NDIRS - NDEFDIRS) 37317133Ssam error(1, "-L: too many directories"); 37417133Ssam dirs[ndir++] = &ap[2]; 37517133Ssam } 37617133Ssam } 37717133Ssam /* add default search directories */ 37817133Ssam dirs[ndir++] = "/lib"; 37917133Ssam dirs[ndir++] = "/usr/lib"; 38017133Ssam dirs[ndir++] = "/usr/local/lib"; 38117133Ssam 38217133Ssam p = argv+1; 383650Sbill /* 384650Sbill * Scan files once to find where symbols are defined. 385650Sbill */ 386615Sbill for (c=1; c<argc; c++) { 387615Sbill if (trace) 388615Sbill printf("%s:\n", *p); 389615Sbill filname = 0; 390615Sbill ap = *p++; 391615Sbill if (*ap != '-') { 392615Sbill load1arg(ap); 393615Sbill continue; 394615Sbill } 395615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 396615Sbill 397615Sbill case 'o': 398615Sbill if (++c >= argc) 399615Sbill error(1, "-o where?"); 400615Sbill ofilename = *p++; 401615Sbill ofilfnd++; 402615Sbill continue; 403615Sbill case 'u': 404615Sbill case 'e': 405615Sbill if (++c >= argc) 406615Sbill error(1, "-u or -c: arg missing"); 407615Sbill enter(slookup(*p++)); 408615Sbill if (ap[i]=='e') 409615Sbill entrypt = lastsym; 410615Sbill continue; 411615Sbill case 'H': 412615Sbill if (++c >= argc) 413615Sbill error(1, "-H: arg missing"); 414615Sbill if (tsize!=0) 415615Sbill error(1, "-H: too late, some text already loaded"); 416615Sbill hsize = atoi(*p++); 417615Sbill continue; 418615Sbill case 'A': 419615Sbill if (++c >= argc) 420615Sbill error(1, "-A: arg missing"); 421615Sbill if (Aflag) 422615Sbill error(1, "-A: only one base file allowed"); 423615Sbill Aflag = 1; 424615Sbill nflag = 0; 425615Sbill funding = 1; 426615Sbill load1arg(*p++); 427615Sbill trsize = drsize = tsize = dsize = bsize = 0; 428615Sbill ctrel = cdrel = cbrel = 0; 429615Sbill funding = 0; 430615Sbill addsym = nextsym; 431615Sbill continue; 432615Sbill case 'D': 433615Sbill if (++c >= argc) 434615Sbill error(1, "-D: arg missing"); 435615Sbill num = htoi(*p++); 436615Sbill if (dsize > num) 437615Sbill error(1, "-D: too small"); 438615Sbill dsize = num; 439615Sbill continue; 440615Sbill case 'T': 441615Sbill if (++c >= argc) 442615Sbill error(1, "-T: arg missing"); 443615Sbill if (tsize!=0) 444615Sbill error(1, "-T: too late, some text already loaded"); 445615Sbill textbase = htoi(*p++); 446615Sbill continue; 447615Sbill case 'l': 448615Sbill save = ap[--i]; 449615Sbill ap[i]='-'; 450615Sbill load1arg(&ap[i]); 451615Sbill ap[i]=save; 452615Sbill goto next; 453898Sbill case 'M': 454898Sbill Mflag++; 455898Sbill continue; 456615Sbill case 'x': 457615Sbill xflag++; 458615Sbill continue; 459615Sbill case 'X': 460615Sbill Xflag++; 461615Sbill continue; 462615Sbill case 'S': 463615Sbill Sflag++; 464615Sbill continue; 465615Sbill case 'r': 466615Sbill rflag++; 467615Sbill arflag++; 468615Sbill continue; 469615Sbill case 's': 470615Sbill sflag++; 471615Sbill xflag++; 472615Sbill continue; 473615Sbill case 'n': 474615Sbill nflag++; 475650Sbill Nflag = zflag = 0; 476615Sbill continue; 477615Sbill case 'N': 478650Sbill Nflag++; 479650Sbill nflag = zflag = 0; 480615Sbill continue; 481615Sbill case 'd': 482615Sbill dflag++; 483615Sbill continue; 484615Sbill case 'i': 485615Sbill printf("ld: -i ignored\n"); 486615Sbill continue; 487615Sbill case 't': 488615Sbill trace++; 489615Sbill continue; 490898Sbill case 'y': 491898Sbill if (ap[i+1] == 0) 492898Sbill error(1, "-y: symbol name missing"); 493898Sbill if (yflag == 0) { 494898Sbill ytab = (char **)calloc(argc, sizeof (char **)); 495898Sbill if (ytab == 0) 496898Sbill error(1, "ran out of memory (-y)"); 497898Sbill } 498898Sbill ytab[yflag++] = &ap[i+1]; 499898Sbill goto next; 500615Sbill case 'z': 501615Sbill zflag++; 502650Sbill Nflag = nflag = 0; 503615Sbill continue; 50417133Ssam case 'L': 50517133Ssam goto next; 506615Sbill default: 507615Sbill filname = savestr("-x"); /* kludge */ 508615Sbill filname[1] = ap[i]; /* kludge */ 509615Sbill archdr.ar_name[0] = 0; /* kludge */ 510615Sbill error(1, "bad flag"); 511615Sbill } 512615Sbill next: 513615Sbill ; 514615Sbill } 515650Sbill if (rflag == 0 && Nflag == 0 && nflag == 0) 516650Sbill zflag++; 517615Sbill endload(argc, argv); 518615Sbill exit(0); 519615Sbill } 520615Sbill 521615Sbill /* 522615Sbill * Convert a ascii string which is a hex number. 523615Sbill * Used by -T and -D options. 524615Sbill */ 525615Sbill htoi(p) 526615Sbill register char *p; 527615Sbill { 528615Sbill register int c, n; 529615Sbill 530615Sbill n = 0; 531615Sbill while (c = *p++) { 532615Sbill n <<= 4; 533615Sbill if (isdigit(c)) 534615Sbill n += c - '0'; 535615Sbill else if (c >= 'a' && c <= 'f') 536615Sbill n += 10 + (c - 'a'); 537615Sbill else if (c >= 'A' && c <= 'F') 538615Sbill n += 10 + (c - 'A'); 539615Sbill else 540615Sbill error(1, "badly formed hex number"); 541615Sbill } 542615Sbill return (n); 543615Sbill } 544615Sbill 545615Sbill delexit() 546615Sbill { 5479332Smckusick struct stat stbuf; 5489332Smckusick long size; 5499332Smckusick char c = 0; 550615Sbill 551615Sbill bflush(); 552615Sbill unlink("l.out"); 5539332Smckusick /* 5549332Smckusick * We have to insure that the last block of the data segment 55516068Sralph * is allocated a full pagesize block. If the underlying 55616068Sralph * file system allocates frags that are smaller than pagesize, 55716068Sralph * a full zero filled pagesize block needs to be allocated so 5589332Smckusick * that when it is demand paged, the paged in block will be 5599332Smckusick * appropriately filled with zeros. 5609332Smckusick */ 5619332Smckusick fstat(biofd, &stbuf); 56216068Sralph size = round(stbuf.st_size, pagesize); 56310640Smckusick if (!rflag && size > stbuf.st_size) { 5649332Smckusick lseek(biofd, size - 1, 0); 56525419Sbloom if (write(biofd, &c, 1) != 1) 56625419Sbloom delarg |= 4; 5679332Smckusick } 56825419Sbloom if (delarg==0 && Aflag==0) 56925419Sbloom (void) chmod(ofilename, ofilemode); 570615Sbill exit (delarg); 571615Sbill } 572615Sbill 573615Sbill endload(argc, argv) 574615Sbill int argc; 575615Sbill char **argv; 576615Sbill { 577615Sbill register int c, i; 578615Sbill long dnum; 579615Sbill register char *ap, **p; 580615Sbill 581615Sbill clibseg = libseg; 582615Sbill filname = 0; 583615Sbill middle(); 584615Sbill setupout(); 585615Sbill p = argv+1; 586615Sbill for (c=1; c<argc; c++) { 587615Sbill ap = *p++; 588615Sbill if (trace) 589615Sbill printf("%s:\n", ap); 590615Sbill if (*ap != '-') { 591615Sbill load2arg(ap); 592615Sbill continue; 593615Sbill } 594615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 595615Sbill 596615Sbill case 'D': 597615Sbill dnum = htoi(*p); 598615Sbill if (dorigin < dnum) 599615Sbill while (dorigin < dnum) 600615Sbill bputc(0, dout), dorigin++; 601615Sbill /* fall into ... */ 602615Sbill case 'T': 603615Sbill case 'u': 604615Sbill case 'e': 605615Sbill case 'o': 606615Sbill case 'H': 607615Sbill ++c; 608615Sbill ++p; 609615Sbill /* fall into ... */ 610615Sbill default: 611615Sbill continue; 612615Sbill case 'A': 613615Sbill funding = 1; 614615Sbill load2arg(*p++); 615615Sbill funding = 0; 616615Sbill c++; 617615Sbill continue; 618898Sbill case 'y': 61917133Ssam case 'L': 620898Sbill goto next; 621615Sbill case 'l': 622615Sbill ap[--i]='-'; 623615Sbill load2arg(&ap[i]); 624615Sbill goto next; 625615Sbill } 626615Sbill next: 627615Sbill ; 628615Sbill } 629615Sbill finishout(); 630615Sbill } 631615Sbill 632615Sbill /* 633615Sbill * Scan file to find defined symbols. 634615Sbill */ 635615Sbill load1arg(cp) 636615Sbill register char *cp; 637615Sbill { 638615Sbill register struct ranlib *tp; 639615Sbill off_t nloc; 640898Sbill int kind; 641615Sbill 642898Sbill kind = getfile(cp); 643898Sbill if (Mflag) 644898Sbill printf("%s\n", filname); 645898Sbill switch (kind) { 646615Sbill 647615Sbill /* 648615Sbill * Plain file. 649615Sbill */ 650615Sbill case 0: 651615Sbill load1(0, 0L); 652615Sbill break; 653615Sbill 654615Sbill /* 655615Sbill * Archive without table of contents. 656615Sbill * (Slowly) process each member. 657615Sbill */ 658615Sbill case 1: 659898Sbill error(-1, 660898Sbill "warning: archive has no table of contents; add one using ranlib(1)"); 661615Sbill nloc = SARMAG; 662615Sbill while (step(nloc)) 663615Sbill nloc += sizeof(archdr) + 664615Sbill round(atol(archdr.ar_size), sizeof (short)); 665615Sbill break; 666615Sbill 667615Sbill /* 668615Sbill * Archive with table of contents. 669615Sbill * Read the table of contents and its associated string table. 670615Sbill * Pass through the library resolving symbols until nothing changes 671615Sbill * for an entire pass (i.e. you can get away with backward references 672615Sbill * when there is a table of contents!) 673615Sbill */ 674615Sbill case 2: 675615Sbill nloc = SARMAG + sizeof (archdr); 676615Sbill dseek(&text, nloc, sizeof (tnum)); 677615Sbill mget((char *)&tnum, sizeof (tnum), &text); 678615Sbill nloc += sizeof (tnum); 679615Sbill tab = (struct ranlib *)malloc(tnum); 680615Sbill if (tab == 0) 681615Sbill error(1, "ran out of memory (toc)"); 682615Sbill dseek(&text, nloc, tnum); 683615Sbill mget((char *)tab, tnum, &text); 684615Sbill nloc += tnum; 685615Sbill tnum /= sizeof (struct ranlib); 686615Sbill dseek(&text, nloc, sizeof (ssiz)); 687615Sbill mget((char *)&ssiz, sizeof (ssiz), &text); 688615Sbill nloc += sizeof (ssiz); 689615Sbill tabstr = (char *)malloc(ssiz); 690615Sbill if (tabstr == 0) 691615Sbill error(1, "ran out of memory (tocstr)"); 692615Sbill dseek(&text, nloc, ssiz); 693615Sbill mget((char *)tabstr, ssiz, &text); 694615Sbill for (tp = &tab[tnum]; --tp >= tab;) { 695615Sbill if (tp->ran_un.ran_strx < 0 || 696615Sbill tp->ran_un.ran_strx >= ssiz) 697615Sbill error(1, "mangled archive table of contents"); 698615Sbill tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx; 699615Sbill } 700615Sbill while (ldrand()) 701615Sbill continue; 70225483Slepreau free((char *)tab); 70325483Slepreau free(tabstr); 704615Sbill nextlibp(-1); 705615Sbill break; 706615Sbill 707615Sbill /* 708615Sbill * Table of contents is out of date, so search 709615Sbill * as a normal library (but skip the __.SYMDEF file). 710615Sbill */ 711615Sbill case 3: 712898Sbill error(-1, 713898Sbill "warning: table of contents for archive is out of date; rerun ranlib(1)"); 714615Sbill nloc = SARMAG; 715615Sbill do 716615Sbill nloc += sizeof(archdr) + 717615Sbill round(atol(archdr.ar_size), sizeof(short)); 718615Sbill while (step(nloc)); 719615Sbill break; 720615Sbill } 721615Sbill close(infil); 722615Sbill } 723615Sbill 724615Sbill /* 725615Sbill * Advance to the next archive member, which 726615Sbill * is at offset nloc in the archive. If the member 727615Sbill * is useful, record its location in the liblist structure 728615Sbill * for use in pass2. Mark the end of the archive in libilst with a -1. 729615Sbill */ 730615Sbill step(nloc) 731615Sbill off_t nloc; 732615Sbill { 733615Sbill 734615Sbill dseek(&text, nloc, (long) sizeof archdr); 735615Sbill if (text.size <= 0) { 736615Sbill nextlibp(-1); 737615Sbill return (0); 738615Sbill } 739615Sbill getarhdr(); 740615Sbill if (load1(1, nloc + (sizeof archdr))) 741615Sbill nextlibp(nloc); 742615Sbill return (1); 743615Sbill } 744615Sbill 745615Sbill /* 746615Sbill * Record the location of a useful archive member. 747615Sbill * Recording -1 marks the end of files from an archive. 748615Sbill * The liblist data structure is dynamically extended here. 749615Sbill */ 750615Sbill nextlibp(val) 751615Sbill off_t val; 752615Sbill { 753615Sbill 754615Sbill if (clibseg->li_used == NROUT) { 755615Sbill if (++clibseg == &libseg[NSEG]) 756615Sbill error(1, "too many files loaded from libraries"); 757615Sbill clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t)); 758615Sbill if (clibseg->li_first == 0) 759615Sbill error(1, "ran out of memory (nextlibp)"); 760615Sbill } 761615Sbill clibseg->li_first[clibseg->li_used++] = val; 762898Sbill if (val != -1 && Mflag) 763898Sbill printf("\t%s\n", archdr.ar_name); 764615Sbill } 765615Sbill 766615Sbill /* 767615Sbill * One pass over an archive with a table of contents. 768615Sbill * Remember the number of symbols currently defined, 769615Sbill * then call step on members which look promising (i.e. 770615Sbill * that define a symbol which is currently externally undefined). 771615Sbill * Indicate to our caller whether this process netted any more symbols. 772615Sbill */ 773615Sbill ldrand() 774615Sbill { 775615Sbill register struct nlist *sp, **hp; 776615Sbill register struct ranlib *tp, *tplast; 777615Sbill off_t loc; 778615Sbill int nsymt = symx(nextsym); 779615Sbill 780615Sbill tplast = &tab[tnum-1]; 781615Sbill for (tp = tab; tp <= tplast; tp++) { 78225483Slepreau if ((hp = slookup(tp->ran_un.ran_name)) == 0 || *hp == 0) 783615Sbill continue; 784615Sbill sp = *hp; 785615Sbill if (sp->n_type != N_EXT+N_UNDF) 786615Sbill continue; 787615Sbill step(tp->ran_off); 788615Sbill loc = tp->ran_off; 789615Sbill while (tp < tplast && (tp+1)->ran_off == loc) 790615Sbill tp++; 791615Sbill } 792615Sbill return (symx(nextsym) != nsymt); 793615Sbill } 794615Sbill 795615Sbill /* 796615Sbill * Examine a single file or archive member on pass 1. 797615Sbill */ 798615Sbill load1(libflg, loc) 799615Sbill off_t loc; 800615Sbill { 801615Sbill register struct nlist *sp; 802615Sbill struct nlist *savnext; 803615Sbill int ndef, nlocal, type, size, nsymt; 804615Sbill register int i; 805615Sbill off_t maxoff; 806615Sbill struct stat stb; 807615Sbill 808615Sbill readhdr(loc); 809615Sbill if (filhdr.a_syms == 0) { 810615Sbill if (filhdr.a_text+filhdr.a_data == 0) 811615Sbill return (0); 812615Sbill error(1, "no namelist"); 813615Sbill } 814615Sbill if (libflg) 815615Sbill maxoff = atol(archdr.ar_size); 816615Sbill else { 817615Sbill fstat(infil, &stb); 818615Sbill maxoff = stb.st_size; 819615Sbill } 820615Sbill if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff) 821615Sbill error(1, "too small (old format .o?)"); 822615Sbill ctrel = tsize; cdrel += dsize; cbrel += bsize; 823615Sbill ndef = 0; 824615Sbill nlocal = sizeof(cursym); 825615Sbill savnext = nextsym; 826615Sbill loc += N_SYMOFF(filhdr); 827615Sbill dseek(&text, loc, filhdr.a_syms); 828615Sbill dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t)); 829615Sbill mget(&size, sizeof (size), &reloc); 830615Sbill dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t)); 831615Sbill curstr = (char *)malloc(size); 832615Sbill if (curstr == NULL) 833615Sbill error(1, "no space for string table"); 834615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc); 835615Sbill while (text.size > 0) { 836615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 837615Sbill if (cursym.n_un.n_strx) { 838615Sbill if (cursym.n_un.n_strx<sizeof(size) || 839615Sbill cursym.n_un.n_strx>=size) 840615Sbill error(1, "bad string table index (pass 1)"); 841615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 842615Sbill } 843615Sbill type = cursym.n_type; 844615Sbill if ((type&N_EXT)==0) { 845615Sbill if (Xflag==0 || cursym.n_un.n_name[0]!='L' || 846615Sbill type & N_STAB) 847615Sbill nlocal += sizeof cursym; 848615Sbill continue; 849615Sbill } 850615Sbill symreloc(); 851615Sbill if (enter(lookup())) 852615Sbill continue; 853615Sbill if ((sp = lastsym)->n_type != N_EXT+N_UNDF) 854615Sbill continue; 855615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 856615Sbill if (cursym.n_value > sp->n_value) 857615Sbill sp->n_value = cursym.n_value; 858615Sbill continue; 859615Sbill } 860615Sbill if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT) 861615Sbill continue; 862615Sbill ndef++; 863615Sbill sp->n_type = cursym.n_type; 864615Sbill sp->n_value = cursym.n_value; 865615Sbill } 866615Sbill if (libflg==0 || ndef) { 867615Sbill tsize += filhdr.a_text; 868615Sbill dsize += round(filhdr.a_data, sizeof (long)); 869615Sbill bsize += round(filhdr.a_bss, sizeof (long)); 870615Sbill ssize += nlocal; 871615Sbill trsize += filhdr.a_trsize; 872615Sbill drsize += filhdr.a_drsize; 873615Sbill if (funding) 874615Sbill textbase = (*slookup("_end"))->n_value; 875615Sbill nsymt = symx(nextsym); 876615Sbill for (i = symx(savnext); i < nsymt; i++) { 877615Sbill sp = xsym(i); 878615Sbill sp->n_un.n_name = savestr(sp->n_un.n_name); 879615Sbill } 880615Sbill free(curstr); 881615Sbill return (1); 882615Sbill } 883615Sbill /* 884615Sbill * No symbols defined by this library member. 885615Sbill * Rip out the hash table entries and reset the symbol table. 886615Sbill */ 887615Sbill symfree(savnext); 888615Sbill free(curstr); 889615Sbill return(0); 890615Sbill } 891615Sbill 892615Sbill middle() 893615Sbill { 894615Sbill register struct nlist *sp; 895615Sbill long csize, t, corigin, ocsize; 896615Sbill int nund, rnd; 897615Sbill char s; 898615Sbill register int i; 899615Sbill int nsymt; 900615Sbill 901615Sbill torigin = 0; 902615Sbill dorigin = 0; 903615Sbill borigin = 0; 904615Sbill 905615Sbill p_etext = *slookup("_etext"); 906615Sbill p_edata = *slookup("_edata"); 907615Sbill p_end = *slookup("_end"); 908615Sbill /* 909615Sbill * If there are any undefined symbols, save the relocation bits. 910615Sbill */ 911615Sbill nsymt = symx(nextsym); 912615Sbill if (rflag==0) { 913615Sbill for (i = 0; i < nsymt; i++) { 914615Sbill sp = xsym(i); 915615Sbill if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 && 916650Sbill sp!=p_end && sp!=p_edata && sp!=p_etext) { 917615Sbill rflag++; 918615Sbill dflag = 0; 919615Sbill break; 920615Sbill } 921615Sbill } 922615Sbill } 923615Sbill if (rflag) 924615Sbill sflag = zflag = 0; 925615Sbill /* 926615Sbill * Assign common locations. 927615Sbill */ 928615Sbill csize = 0; 929615Sbill if (!Aflag) 930615Sbill addsym = symseg[0].sy_first; 931615Sbill database = round(tsize+textbase, 93212671Ssam (nflag||zflag? pagesize : sizeof (long))); 933615Sbill database += hsize; 934615Sbill if (dflag || rflag==0) { 935615Sbill ldrsym(p_etext, tsize, N_EXT+N_TEXT); 936615Sbill ldrsym(p_edata, dsize, N_EXT+N_DATA); 937615Sbill ldrsym(p_end, bsize, N_EXT+N_BSS); 938615Sbill for (i = symx(addsym); i < nsymt; i++) { 939615Sbill sp = xsym(i); 940615Sbill if ((s=sp->n_type)==N_EXT+N_UNDF && 941615Sbill (t = sp->n_value)!=0) { 942615Sbill if (t >= sizeof (double)) 943615Sbill rnd = sizeof (double); 944615Sbill else if (t >= sizeof (long)) 945615Sbill rnd = sizeof (long); 946615Sbill else 947615Sbill rnd = sizeof (short); 948615Sbill csize = round(csize, rnd); 949615Sbill sp->n_value = csize; 950615Sbill sp->n_type = N_EXT+N_COMM; 951615Sbill ocsize = csize; 952615Sbill csize += t; 953615Sbill } 954615Sbill if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) { 955615Sbill sp->n_value = ocsize; 956615Sbill sp->n_type = (s&N_STAB) | (N_EXT+N_COMM); 957615Sbill } 958615Sbill } 959615Sbill } 960615Sbill /* 961615Sbill * Now set symbols to their final value 962615Sbill */ 963615Sbill csize = round(csize, sizeof (long)); 964615Sbill torigin = textbase; 965615Sbill dorigin = database; 966615Sbill corigin = dorigin + dsize; 967615Sbill borigin = corigin + csize; 968615Sbill nund = 0; 969615Sbill nsymt = symx(nextsym); 970615Sbill for (i = symx(addsym); i<nsymt; i++) { 971615Sbill sp = xsym(i); 972615Sbill switch (sp->n_type & (N_TYPE+N_EXT)) { 973615Sbill 974615Sbill case N_EXT+N_UNDF: 9752369Skre if (arflag == 0) 9762369Skre errlev |= 01; 977615Sbill if ((arflag==0 || dflag) && sp->n_value==0) { 978650Sbill if (sp==p_end || sp==p_etext || sp==p_edata) 979650Sbill continue; 980615Sbill if (nund==0) 981615Sbill printf("Undefined:\n"); 982615Sbill nund++; 983615Sbill printf("%s\n", sp->n_un.n_name); 984615Sbill } 985615Sbill continue; 986615Sbill case N_EXT+N_ABS: 987615Sbill default: 988615Sbill continue; 989615Sbill case N_EXT+N_TEXT: 990615Sbill sp->n_value += torigin; 991615Sbill continue; 992615Sbill case N_EXT+N_DATA: 993615Sbill sp->n_value += dorigin; 994615Sbill continue; 995615Sbill case N_EXT+N_BSS: 996615Sbill sp->n_value += borigin; 997615Sbill continue; 998615Sbill case N_EXT+N_COMM: 999615Sbill sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS); 1000615Sbill sp->n_value += corigin; 1001615Sbill continue; 1002615Sbill } 1003615Sbill } 1004615Sbill if (sflag || xflag) 1005615Sbill ssize = 0; 1006615Sbill bsize += csize; 1007615Sbill nsym = ssize / (sizeof cursym); 1008615Sbill if (Aflag) { 1009615Sbill fixspec(p_etext,torigin); 1010615Sbill fixspec(p_edata,dorigin); 1011615Sbill fixspec(p_end,borigin); 1012615Sbill } 1013615Sbill } 1014615Sbill 1015615Sbill fixspec(sym,offset) 1016615Sbill struct nlist *sym; 1017615Sbill long offset; 1018615Sbill { 1019615Sbill 1020615Sbill if(symx(sym) < symx(addsym) && sym!=0) 1021615Sbill sym->n_value += offset; 1022615Sbill } 1023615Sbill 1024615Sbill ldrsym(sp, val, type) 1025615Sbill register struct nlist *sp; 1026615Sbill long val; 1027615Sbill { 1028615Sbill 1029615Sbill if (sp == 0) 1030615Sbill return; 1031615Sbill if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) { 1032615Sbill printf("%s: ", sp->n_un.n_name); 1033615Sbill error(0, "user attempt to redfine loader-defined symbol"); 1034615Sbill return; 1035615Sbill } 1036615Sbill sp->n_type = type; 1037615Sbill sp->n_value = val; 1038615Sbill } 1039615Sbill 1040615Sbill off_t wroff; 1041615Sbill struct biobuf toutb; 1042615Sbill 1043615Sbill setupout() 1044615Sbill { 1045615Sbill int bss; 104616068Sralph struct stat stbuf; 1047898Sbill extern char *sys_errlist[]; 1048898Sbill extern int errno; 1049615Sbill 10503606Ssklower ofilemode = 0777 & ~umask(0); 10513606Ssklower biofd = creat(ofilename, 0666 & ofilemode); 1052898Sbill if (biofd < 0) { 1053898Sbill filname = ofilename; /* kludge */ 1054898Sbill archdr.ar_name[0] = 0; /* kludge */ 1055898Sbill error(1, sys_errlist[errno]); /* kludge */ 1056898Sbill } 105716068Sralph fstat(biofd, &stbuf); /* suppose file exists, wrong*/ 105816068Sralph if (stbuf.st_mode & 0111) { /* mode, ld fails? */ 105916068Sralph chmod(ofilename, stbuf.st_mode & 0666); 106016068Sralph ofilemode = stbuf.st_mode; 106116068Sralph } 1062615Sbill filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC); 1063615Sbill filhdr.a_text = nflag ? tsize : 106412671Ssam round(tsize, zflag ? pagesize : sizeof (long)); 106512671Ssam filhdr.a_data = zflag ? round(dsize, pagesize) : dsize; 1066615Sbill bss = bsize - (filhdr.a_data - dsize); 1067615Sbill if (bss < 0) 1068615Sbill bss = 0; 1069615Sbill filhdr.a_bss = bss; 1070615Sbill filhdr.a_trsize = trsize; 1071615Sbill filhdr.a_drsize = drsize; 1072615Sbill filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym)); 1073615Sbill if (entrypt) { 1074615Sbill if (entrypt->n_type!=N_EXT+N_TEXT) 1075615Sbill error(0, "entry point not in text"); 1076615Sbill else 1077615Sbill filhdr.a_entry = entrypt->n_value; 1078615Sbill } else 1079615Sbill filhdr.a_entry = 0; 1080615Sbill filhdr.a_trsize = (rflag ? trsize:0); 1081615Sbill filhdr.a_drsize = (rflag ? drsize:0); 108216068Sralph tout = &toutb; 108316068Sralph bopen(tout, 0, stbuf.st_blksize); 1084615Sbill bwrite((char *)&filhdr, sizeof (filhdr), tout); 108516068Sralph if (zflag) 108616068Sralph bseek(tout, pagesize); 1087615Sbill wroff = N_TXTOFF(filhdr) + filhdr.a_text; 108816068Sralph outb(&dout, filhdr.a_data, stbuf.st_blksize); 1089615Sbill if (rflag) { 109016068Sralph outb(&trout, filhdr.a_trsize, stbuf.st_blksize); 109116068Sralph outb(&drout, filhdr.a_drsize, stbuf.st_blksize); 1092615Sbill } 1093615Sbill if (sflag==0 || xflag==0) { 109416068Sralph outb(&sout, filhdr.a_syms, stbuf.st_blksize); 1095615Sbill wroff += sizeof (offset); 109616068Sralph outb(&strout, 0, stbuf.st_blksize); 1097615Sbill } 1098615Sbill } 1099615Sbill 110016068Sralph outb(bp, inc, bufsize) 1101615Sbill register struct biobuf **bp; 1102615Sbill { 1103615Sbill 1104615Sbill *bp = (struct biobuf *)malloc(sizeof (struct biobuf)); 1105615Sbill if (*bp == 0) 1106615Sbill error(1, "ran out of memory (outb)"); 110716068Sralph bopen(*bp, wroff, bufsize); 1108615Sbill wroff += inc; 1109615Sbill } 1110615Sbill 1111615Sbill load2arg(acp) 1112615Sbill char *acp; 1113615Sbill { 1114615Sbill register char *cp; 1115615Sbill off_t loc; 1116615Sbill 1117615Sbill cp = acp; 1118615Sbill if (getfile(cp) == 0) { 1119615Sbill while (*cp) 1120615Sbill cp++; 1121615Sbill while (cp >= acp && *--cp != '/'); 1122615Sbill mkfsym(++cp); 1123615Sbill load2(0L); 1124615Sbill } else { /* scan archive members referenced */ 1125615Sbill for (;;) { 1126615Sbill if (clibseg->li_used2 == clibseg->li_used) { 1127615Sbill if (clibseg->li_used < NROUT) 1128615Sbill error(1, "libseg botch"); 1129615Sbill clibseg++; 1130615Sbill } 1131615Sbill loc = clibseg->li_first[clibseg->li_used2++]; 1132615Sbill if (loc == -1) 1133615Sbill break; 1134615Sbill dseek(&text, loc, (long)sizeof(archdr)); 1135615Sbill getarhdr(); 1136615Sbill mkfsym(archdr.ar_name); 1137615Sbill load2(loc + (long)sizeof(archdr)); 1138615Sbill } 1139615Sbill } 1140615Sbill close(infil); 1141615Sbill } 1142615Sbill 1143615Sbill load2(loc) 1144615Sbill long loc; 1145615Sbill { 1146615Sbill int size; 1147615Sbill register struct nlist *sp; 1148615Sbill register struct local *lp; 1149615Sbill register int symno, i; 1150615Sbill int type; 1151615Sbill 1152615Sbill readhdr(loc); 1153650Sbill if (!funding) { 1154615Sbill ctrel = torigin; 1155615Sbill cdrel += dorigin; 1156615Sbill cbrel += borigin; 1157615Sbill } 1158615Sbill /* 1159615Sbill * Reread the symbol table, recording the numbering 1160615Sbill * of symbols for fixing external references. 1161615Sbill */ 1162615Sbill for (i = 0; i < LHSIZ; i++) 1163615Sbill lochash[i] = 0; 1164615Sbill clocseg = locseg; 1165615Sbill clocseg->lo_used = 0; 1166615Sbill symno = -1; 1167615Sbill loc += N_TXTOFF(filhdr); 1168615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1169615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t)); 1170615Sbill mget(&size, sizeof(size), &text); 1171615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1172615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t), 1173615Sbill size - sizeof(off_t)); 1174615Sbill curstr = (char *)malloc(size); 1175615Sbill if (curstr == NULL) 1176615Sbill error(1, "out of space reading string table (pass 2)"); 1177615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &text); 1178615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1179615Sbill filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms); 1180615Sbill while (text.size > 0) { 1181615Sbill symno++; 1182615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 1183615Sbill if (cursym.n_un.n_strx) { 1184615Sbill if (cursym.n_un.n_strx<sizeof(size) || 1185615Sbill cursym.n_un.n_strx>=size) 1186615Sbill error(1, "bad string table index (pass 2)"); 1187615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 1188615Sbill } 1189615Sbill /* inline expansion of symreloc() */ 1190615Sbill switch (cursym.n_type & 017) { 1191615Sbill 1192615Sbill case N_TEXT: 1193615Sbill case N_EXT+N_TEXT: 1194615Sbill cursym.n_value += ctrel; 1195615Sbill break; 1196615Sbill case N_DATA: 1197615Sbill case N_EXT+N_DATA: 1198615Sbill cursym.n_value += cdrel; 1199615Sbill break; 1200615Sbill case N_BSS: 1201615Sbill case N_EXT+N_BSS: 1202615Sbill cursym.n_value += cbrel; 1203615Sbill break; 1204615Sbill case N_EXT+N_UNDF: 1205615Sbill break; 1206615Sbill default: 1207615Sbill if (cursym.n_type&N_EXT) 1208615Sbill cursym.n_type = N_EXT+N_ABS; 1209615Sbill } 1210615Sbill /* end inline expansion of symreloc() */ 1211615Sbill type = cursym.n_type; 1212898Sbill if (yflag && cursym.n_un.n_name) 1213898Sbill for (i = 0; i < yflag; i++) 1214898Sbill /* fast check for 2d character! */ 1215898Sbill if (ytab[i][1] == cursym.n_un.n_name[1] && 1216898Sbill !strcmp(ytab[i], cursym.n_un.n_name)) { 1217898Sbill tracesym(); 1218898Sbill break; 1219898Sbill } 1220615Sbill if ((type&N_EXT) == 0) { 1221615Sbill if (!sflag&&!xflag&& 1222615Sbill (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB)) 1223615Sbill symwrite(&cursym, sout); 1224615Sbill continue; 1225615Sbill } 1226615Sbill if (funding) 1227615Sbill continue; 1228615Sbill if ((sp = *lookup()) == 0) 1229615Sbill error(1, "internal error: symbol not found"); 1230615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 1231615Sbill if (clocseg->lo_used == NSYMPR) { 1232615Sbill if (++clocseg == &locseg[NSEG]) 1233615Sbill error(1, "local symbol overflow"); 1234615Sbill clocseg->lo_used = 0; 1235615Sbill } 1236615Sbill if (clocseg->lo_first == 0) { 1237615Sbill clocseg->lo_first = (struct local *) 1238615Sbill malloc(NSYMPR * sizeof (struct local)); 1239615Sbill if (clocseg->lo_first == 0) 1240615Sbill error(1, "out of memory (clocseg)"); 1241615Sbill } 1242615Sbill lp = &clocseg->lo_first[clocseg->lo_used++]; 1243615Sbill lp->l_index = symno; 1244615Sbill lp->l_symbol = sp; 1245615Sbill lp->l_link = lochash[symno % LHSIZ]; 1246615Sbill lochash[symno % LHSIZ] = lp; 1247615Sbill continue; 1248615Sbill } 1249615Sbill if (cursym.n_type & N_STAB) 1250615Sbill continue; 1251615Sbill if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) { 1252615Sbill printf("%s: ", cursym.n_un.n_name); 1253615Sbill error(0, "multiply defined"); 1254615Sbill } 1255615Sbill } 1256615Sbill if (funding) 1257615Sbill return; 1258615Sbill dseek(&text, loc, filhdr.a_text); 1259615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize); 1260650Sbill load2td(ctrel, torigin - textbase, tout, trout); 1261615Sbill dseek(&text, loc+filhdr.a_text, filhdr.a_data); 1262615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, 1263615Sbill filhdr.a_drsize); 1264650Sbill load2td(cdrel, dorigin - database, dout, drout); 1265615Sbill while (filhdr.a_data & (sizeof(long)-1)) { 1266615Sbill bputc(0, dout); 1267615Sbill filhdr.a_data++; 1268615Sbill } 1269615Sbill torigin += filhdr.a_text; 12701752Sbill dorigin += round(filhdr.a_data, sizeof (long)); 12711752Sbill borigin += round(filhdr.a_bss, sizeof (long)); 1272615Sbill free(curstr); 1273615Sbill } 1274615Sbill 1275898Sbill struct tynames { 1276898Sbill int ty_value; 1277898Sbill char *ty_name; 1278898Sbill } tynames[] = { 1279898Sbill N_UNDF, "undefined", 1280898Sbill N_ABS, "absolute", 1281898Sbill N_TEXT, "text", 1282898Sbill N_DATA, "data", 1283898Sbill N_BSS, "bss", 1284898Sbill N_COMM, "common", 1285898Sbill 0, 0, 1286898Sbill }; 1287898Sbill 1288898Sbill tracesym() 1289898Sbill { 1290898Sbill register struct tynames *tp; 1291898Sbill 1292898Sbill if (cursym.n_type & N_STAB) 1293898Sbill return; 1294898Sbill printf("%s", filname); 1295898Sbill if (archdr.ar_name[0]) 1296898Sbill printf("(%s)", archdr.ar_name); 1297898Sbill printf(": "); 1298898Sbill if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) { 1299898Sbill printf("definition of common %s size %d\n", 1300898Sbill cursym.n_un.n_name, cursym.n_value); 1301898Sbill return; 1302898Sbill } 1303898Sbill for (tp = tynames; tp->ty_name; tp++) 1304898Sbill if (tp->ty_value == (cursym.n_type&N_TYPE)) 1305898Sbill break; 1306898Sbill printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to"); 1307898Sbill if (cursym.n_type&N_EXT) 1308898Sbill printf(" external"); 1309898Sbill if (tp->ty_name) 1310898Sbill printf(" %s", tp->ty_name); 1311898Sbill printf(" %s\n", cursym.n_un.n_name); 1312898Sbill } 1313898Sbill 1314*29845Ssam #if !defined(tahoe) 1315*29845Ssam /* for machines which allow arbitrarily aligned word and longword accesses */ 1316*29845Ssam #define getw(cp) (*(short *)(cp)) 1317*29845Ssam #define getl(cp) (*(long *)(cp)) 1318*29845Ssam #define putw(cp, w) (*(short *)(cp) = (w)) 1319*29845Ssam #define putl(cp, l) (*(long *)(cp) = (l)) 1320*29845Ssam #else 1321*29845Ssam short 1322*29845Ssam getw(cp) 1323*29845Ssam char *cp; 1324*29845Ssam { 1325*29845Ssam union { 1326*29845Ssam short w; 1327*29845Ssam char c[2]; 1328*29845Ssam } w; 1329*29845Ssam 1330*29845Ssam w.c[0] = *cp++; 1331*29845Ssam w.c[1] = *cp++; 1332*29845Ssam return (w.w); 1333*29845Ssam } 1334*29845Ssam 1335*29845Ssam getl(cp) 1336*29845Ssam char *cp; 1337*29845Ssam { 1338*29845Ssam union { 1339*29845Ssam long l; 1340*29845Ssam char c[4]; 1341*29845Ssam } l; 1342*29845Ssam 1343*29845Ssam l.c[0] = *cp++; 1344*29845Ssam l.c[1] = *cp++; 1345*29845Ssam l.c[2] = *cp++; 1346*29845Ssam l.c[3] = *cp++; 1347*29845Ssam return (l.l); 1348*29845Ssam } 1349*29845Ssam 1350*29845Ssam putw(cp, v) 1351*29845Ssam char *cp; 1352*29845Ssam short v; 1353*29845Ssam { 1354*29845Ssam union { 1355*29845Ssam short w; 1356*29845Ssam char c[2]; 1357*29845Ssam } w; 1358*29845Ssam 1359*29845Ssam w.w = v; 1360*29845Ssam *cp++ = w.c[0]; 1361*29845Ssam *cp++ = w.c[1]; 1362*29845Ssam } 1363*29845Ssam 1364*29845Ssam putl(cp, v) 1365*29845Ssam char *cp; 1366*29845Ssam long v; 1367*29845Ssam { 1368*29845Ssam union { 1369*29845Ssam long l; 1370*29845Ssam char c[4]; 1371*29845Ssam } l; 1372*29845Ssam 1373*29845Ssam l.l = v; 1374*29845Ssam *cp++ = l.c[0]; 1375*29845Ssam *cp++ = l.c[1]; 1376*29845Ssam *cp++ = l.c[2]; 1377*29845Ssam *cp++ = l.c[3]; 1378*29845Ssam } 1379*29845Ssam #endif 1380*29845Ssam 1381650Sbill /* 1382650Sbill * This routine relocates the single text or data segment argument. 1383650Sbill * Offsets from external symbols are resolved by adding the value 1384650Sbill * of the external symbols. Non-external reference are updated to account 1385650Sbill * for the relative motion of the segments (ctrel, cdrel, ...). If 1386650Sbill * a relocation was pc-relative, then we update it to reflect the 1387650Sbill * change in the positioning of the segments by adding the displacement 1388650Sbill * of the referenced segment and subtracting the displacement of the 1389650Sbill * current segment (creloc). 1390650Sbill * 1391650Sbill * If we are saving the relocation information, then we increase 1392650Sbill * each relocation datum address by our base position in the new segment. 1393650Sbill */ 1394650Sbill load2td(creloc, position, b1, b2) 1395650Sbill long creloc, offset; 1396615Sbill struct biobuf *b1, *b2; 1397615Sbill { 1398615Sbill register struct nlist *sp; 1399615Sbill register struct local *lp; 1400615Sbill long tw; 1401615Sbill register struct relocation_info *rp, *rpend; 1402615Sbill struct relocation_info *relp; 1403615Sbill char *codep; 1404615Sbill register char *cp; 1405615Sbill int relsz, codesz; 1406615Sbill 1407615Sbill relsz = reloc.size; 1408615Sbill relp = (struct relocation_info *)malloc(relsz); 1409615Sbill codesz = text.size; 1410615Sbill codep = (char *)malloc(codesz); 1411615Sbill if (relp == 0 || codep == 0) 1412615Sbill error(1, "out of memory (load2td)"); 1413615Sbill mget((char *)relp, relsz, &reloc); 1414615Sbill rpend = &relp[relsz / sizeof (struct relocation_info)]; 1415615Sbill mget(codep, codesz, &text); 1416615Sbill for (rp = relp; rp < rpend; rp++) { 1417615Sbill cp = codep + rp->r_address; 1418650Sbill /* 1419650Sbill * Pick up previous value at location to be relocated. 1420650Sbill */ 1421615Sbill switch (rp->r_length) { 1422615Sbill 1423615Sbill case 0: /* byte */ 1424615Sbill tw = *cp; 1425615Sbill break; 1426615Sbill 1427615Sbill case 1: /* word */ 1428*29845Ssam tw = getw(cp); 1429615Sbill break; 1430615Sbill 1431615Sbill case 2: /* long */ 1432*29845Ssam tw = getl(cp); 1433615Sbill break; 1434615Sbill 1435615Sbill default: 1436615Sbill error(1, "load2td botch: bad length"); 1437615Sbill } 1438650Sbill /* 1439650Sbill * If relative to an external which is defined, 1440650Sbill * resolve to a simpler kind of reference in the 1441650Sbill * result file. If the external is undefined, just 1442650Sbill * convert the symbol number to the number of the 1443650Sbill * symbol in the result file and leave it undefined. 1444650Sbill */ 1445615Sbill if (rp->r_extern) { 1446650Sbill /* 1447650Sbill * Search the hash table which maps local 1448650Sbill * symbol numbers to symbol tables entries 1449650Sbill * in the new a.out file. 1450650Sbill */ 1451615Sbill lp = lochash[rp->r_symbolnum % LHSIZ]; 1452615Sbill while (lp->l_index != rp->r_symbolnum) { 1453615Sbill lp = lp->l_link; 1454615Sbill if (lp == 0) 1455615Sbill error(1, "local symbol botch"); 1456615Sbill } 1457615Sbill sp = lp->l_symbol; 1458615Sbill if (sp->n_type == N_EXT+N_UNDF) 1459615Sbill rp->r_symbolnum = nsym+symx(sp); 1460615Sbill else { 1461615Sbill rp->r_symbolnum = sp->n_type & N_TYPE; 1462615Sbill tw += sp->n_value; 1463615Sbill rp->r_extern = 0; 1464615Sbill } 1465615Sbill } else switch (rp->r_symbolnum & N_TYPE) { 1466650Sbill /* 1467650Sbill * Relocation is relative to the loaded position 1468650Sbill * of another segment. Update by the change in position 1469650Sbill * of that segment. 1470650Sbill */ 1471615Sbill case N_TEXT: 1472615Sbill tw += ctrel; 1473615Sbill break; 1474615Sbill case N_DATA: 1475615Sbill tw += cdrel; 1476615Sbill break; 1477615Sbill case N_BSS: 1478615Sbill tw += cbrel; 1479615Sbill break; 1480615Sbill case N_ABS: 1481615Sbill break; 1482615Sbill default: 1483615Sbill error(1, "relocation format botch (symbol type))"); 1484615Sbill } 1485650Sbill /* 1486650Sbill * Relocation is pc relative, so decrease the relocation 1487650Sbill * by the amount the current segment is displaced. 1488650Sbill * (E.g if we are a relative reference to a text location 1489650Sbill * from data space, we added the increase in the text address 1490650Sbill * above, and subtract the increase in our (data) address 1491650Sbill * here, leaving the net change the relative change in the 1492650Sbill * positioning of our text and data segments.) 1493650Sbill */ 1494615Sbill if (rp->r_pcrel) 1495615Sbill tw -= creloc; 1496650Sbill /* 1497650Sbill * Put the value back in the segment, 1498650Sbill * while checking for overflow. 1499650Sbill */ 1500615Sbill switch (rp->r_length) { 1501615Sbill 1502615Sbill case 0: /* byte */ 1503615Sbill if (tw < -128 || tw > 127) 1504615Sbill error(0, "byte displacement overflow"); 1505615Sbill *cp = tw; 1506615Sbill break; 1507615Sbill case 1: /* word */ 1508615Sbill if (tw < -32768 || tw > 32767) 1509615Sbill error(0, "word displacement overflow"); 1510*29845Ssam putw(cp, tw); 1511615Sbill break; 1512615Sbill case 2: /* long */ 1513*29845Ssam putl(cp, tw); 1514615Sbill break; 1515615Sbill } 1516650Sbill /* 1517650Sbill * If we are saving relocation information, 1518650Sbill * we must convert the address in the segment from 1519650Sbill * the old .o file into an address in the segment in 1520650Sbill * the new a.out, by adding the position of our 1521650Sbill * segment in the new larger segment. 1522650Sbill */ 1523615Sbill if (rflag) 1524650Sbill rp->r_address += position; 1525615Sbill } 1526615Sbill bwrite(codep, codesz, b1); 1527615Sbill if (rflag) 1528615Sbill bwrite(relp, relsz, b2); 152925483Slepreau free((char *)relp); 153025483Slepreau free(codep); 1531615Sbill } 1532615Sbill 1533615Sbill finishout() 1534615Sbill { 1535615Sbill register int i; 1536615Sbill int nsymt; 1537615Sbill 1538615Sbill if (sflag==0) { 1539615Sbill nsymt = symx(nextsym); 1540615Sbill for (i = 0; i < nsymt; i++) 1541615Sbill symwrite(xsym(i), sout); 1542615Sbill bwrite(&offset, sizeof offset, sout); 1543615Sbill } 1544615Sbill if (!ofilfnd) { 1545615Sbill unlink("a.out"); 1546898Sbill if (link("l.out", "a.out") < 0) 1547898Sbill error(1, "cannot move l.out to a.out"); 1548615Sbill ofilename = "a.out"; 1549615Sbill } 1550615Sbill delarg = errlev; 1551615Sbill delexit(); 1552615Sbill } 1553615Sbill 1554615Sbill mkfsym(s) 1555615Sbill char *s; 1556615Sbill { 1557615Sbill 1558615Sbill if (sflag || xflag) 1559615Sbill return; 1560615Sbill cursym.n_un.n_name = s; 1561615Sbill cursym.n_type = N_TEXT; 1562615Sbill cursym.n_value = torigin; 1563615Sbill symwrite(&cursym, sout); 1564615Sbill } 1565615Sbill 1566615Sbill getarhdr() 1567615Sbill { 1568615Sbill register char *cp; 1569615Sbill 1570615Sbill mget((char *)&archdr, sizeof archdr, &text); 1571615Sbill for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];) 1572615Sbill if (*cp++ == ' ') { 1573615Sbill cp[-1] = 0; 1574615Sbill return; 1575615Sbill } 1576615Sbill } 1577615Sbill 1578615Sbill mget(loc, n, sp) 1579615Sbill register STREAM *sp; 1580615Sbill register char *loc; 1581615Sbill { 1582615Sbill register char *p; 1583615Sbill register int take; 1584615Sbill 1585615Sbill top: 1586615Sbill if (n == 0) 1587615Sbill return; 1588615Sbill if (sp->size && sp->nibuf) { 1589615Sbill p = sp->ptr; 1590615Sbill take = sp->size; 1591615Sbill if (take > sp->nibuf) 1592615Sbill take = sp->nibuf; 1593615Sbill if (take > n) 1594615Sbill take = n; 1595615Sbill n -= take; 1596615Sbill sp->size -= take; 1597615Sbill sp->nibuf -= take; 1598615Sbill sp->pos += take; 1599615Sbill do 1600615Sbill *loc++ = *p++; 1601615Sbill while (--take > 0); 1602615Sbill sp->ptr = p; 1603615Sbill goto top; 1604615Sbill } 160516068Sralph if (n > p_blksize) { 160616068Sralph take = n - n % p_blksize; 160716068Sralph lseek(infil, (sp->bno+1)<<p_blkshift, 0); 1608615Sbill if (take > sp->size || read(infil, loc, take) != take) 1609615Sbill error(1, "premature EOF"); 1610615Sbill loc += take; 1611615Sbill n -= take; 1612615Sbill sp->size -= take; 1613615Sbill sp->pos += take; 161416068Sralph dseek(sp, (sp->bno+1+(take>>p_blkshift))<<p_blkshift, -1); 1615615Sbill goto top; 1616615Sbill } 1617615Sbill *loc++ = get(sp); 1618615Sbill --n; 1619615Sbill goto top; 1620615Sbill } 1621615Sbill 1622615Sbill symwrite(sp, bp) 1623615Sbill struct nlist *sp; 1624615Sbill struct biobuf *bp; 1625615Sbill { 1626615Sbill register int len; 1627615Sbill register char *str; 1628615Sbill 1629615Sbill str = sp->n_un.n_name; 1630615Sbill if (str) { 1631615Sbill sp->n_un.n_strx = offset; 1632615Sbill len = strlen(str) + 1; 1633615Sbill bwrite(str, len, strout); 1634615Sbill offset += len; 1635615Sbill } 1636615Sbill bwrite(sp, sizeof (*sp), bp); 1637615Sbill sp->n_un.n_name = str; 1638615Sbill } 1639615Sbill 1640615Sbill dseek(sp, loc, s) 1641615Sbill register STREAM *sp; 1642615Sbill long loc, s; 1643615Sbill { 1644615Sbill register PAGE *p; 1645615Sbill register b, o; 1646615Sbill int n; 1647615Sbill 164816068Sralph b = loc>>p_blkshift; 164916068Sralph o = loc&p_blkmask; 1650615Sbill if (o&01) 1651615Sbill error(1, "loader error; odd offset"); 1652615Sbill --sp->pno->nuser; 1653615Sbill if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b) 1654615Sbill if (p->nuser==0 || (p = &page[0])->nuser==0) { 1655615Sbill if (page[0].nuser==0 && page[1].nuser==0) 1656615Sbill if (page[0].bno < page[1].bno) 1657615Sbill p = &page[0]; 1658615Sbill p->bno = b; 165916068Sralph lseek(infil, loc & ~(long)p_blkmask, 0); 166016068Sralph if ((n = read(infil, p->buff, p_blksize)) < 0) 1661615Sbill n = 0; 1662615Sbill p->nibuf = n; 166316068Sralph } else 166416068Sralph error(1, "botch: no pages"); 1665615Sbill ++p->nuser; 1666615Sbill sp->bno = b; 1667615Sbill sp->pno = p; 1668615Sbill if (s != -1) {sp->size = s; sp->pos = 0;} 1669615Sbill sp->ptr = (char *)(p->buff + o); 1670615Sbill if ((sp->nibuf = p->nibuf-o) <= 0) 1671615Sbill sp->size = 0; 1672615Sbill } 1673615Sbill 1674615Sbill char 1675615Sbill get(asp) 1676615Sbill STREAM *asp; 1677615Sbill { 1678615Sbill register STREAM *sp; 1679615Sbill 1680615Sbill sp = asp; 1681615Sbill if ((sp->nibuf -= sizeof(char)) < 0) { 168216068Sralph dseek(sp, ((long)(sp->bno+1)<<p_blkshift), (long)-1); 1683615Sbill sp->nibuf -= sizeof(char); 1684615Sbill } 1685615Sbill if ((sp->size -= sizeof(char)) <= 0) { 1686615Sbill if (sp->size < 0) 1687615Sbill error(1, "premature EOF"); 1688615Sbill ++fpage.nuser; 1689615Sbill --sp->pno->nuser; 1690615Sbill sp->pno = (PAGE *) &fpage; 1691615Sbill } 1692615Sbill sp->pos += sizeof(char); 1693615Sbill return(*sp->ptr++); 1694615Sbill } 1695615Sbill 1696615Sbill getfile(acp) 1697615Sbill char *acp; 1698615Sbill { 1699615Sbill register int c; 1700615Sbill char arcmag[SARMAG+1]; 1701615Sbill struct stat stb; 1702615Sbill 1703615Sbill archdr.ar_name[0] = '\0'; 170417133Ssam filname = acp; 170517133Ssam if (filname[0] == '-' && filname[1] == 'l') 170617133Ssam infil = libopen(filname + 2, O_RDONLY); 170717133Ssam else 170817133Ssam infil = open(filname, O_RDONLY); 170917133Ssam if (infil < 0) 1710615Sbill error(1, "cannot open"); 171116068Sralph fstat(infil, &stb); 1712615Sbill page[0].bno = page[1].bno = -1; 1713615Sbill page[0].nuser = page[1].nuser = 0; 171416068Sralph c = stb.st_blksize; 171516068Sralph if (c == 0 || (c & (c - 1)) != 0) { 171616068Sralph /* use default size if not a power of two */ 171716068Sralph c = BLKSIZE; 171816068Sralph } 171916068Sralph if (p_blksize != c) { 172016068Sralph p_blksize = c; 172116068Sralph p_blkmask = c - 1; 172216068Sralph for (p_blkshift = 0; c > 1 ; p_blkshift++) 172316068Sralph c >>= 1; 172416068Sralph if (page[0].buff != NULL) 172516068Sralph free(page[0].buff); 172616068Sralph page[0].buff = (char *)malloc(p_blksize); 172716068Sralph if (page[0].buff == NULL) 172816068Sralph error(1, "ran out of memory (getfile)"); 172916068Sralph if (page[1].buff != NULL) 173016068Sralph free(page[1].buff); 173116068Sralph page[1].buff = (char *)malloc(p_blksize); 173216068Sralph if (page[1].buff == NULL) 173316068Sralph error(1, "ran out of memory (getfile)"); 173416068Sralph } 1735615Sbill text.pno = reloc.pno = (PAGE *) &fpage; 1736615Sbill fpage.nuser = 2; 1737615Sbill dseek(&text, 0L, SARMAG); 1738615Sbill if (text.size <= 0) 1739615Sbill error(1, "premature EOF"); 1740615Sbill mget((char *)arcmag, SARMAG, &text); 1741615Sbill arcmag[SARMAG] = 0; 1742615Sbill if (strcmp(arcmag, ARMAG)) 1743615Sbill return (0); 1744615Sbill dseek(&text, SARMAG, sizeof archdr); 174517133Ssam if (text.size <= 0) 1746615Sbill return (1); 1747615Sbill getarhdr(); 1748615Sbill if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0) 1749615Sbill return (1); 1750615Sbill return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2); 1751615Sbill } 1752615Sbill 175317133Ssam /* 175417133Ssam * Search for a library with given name 175517133Ssam * using the directory search array. 175617133Ssam */ 175717133Ssam libopen(name, oflags) 175817133Ssam char *name; 175917133Ssam int oflags; 176017133Ssam { 176117133Ssam register char *p, *cp; 176217133Ssam register int i; 176317133Ssam static char buf[MAXPATHLEN+1]; 176417133Ssam int fd = -1; 176517133Ssam 176617133Ssam if (*name == '\0') /* backwards compat */ 176717133Ssam name = "a"; 176817133Ssam for (i = 0; i < ndir && fd == -1; i++) { 176917133Ssam p = buf; 177017133Ssam for (cp = dirs[i]; *cp; *p++ = *cp++) 177117133Ssam ; 177217133Ssam *p++ = '/'; 177317133Ssam for (cp = "lib"; *cp; *p++ = *cp++) 177417133Ssam ; 177517133Ssam for (cp = name; *cp; *p++ = *cp++) 177617133Ssam ; 177717133Ssam cp = ".a"; 177817133Ssam while (*p++ = *cp++) 177917133Ssam ; 178017133Ssam fd = open(buf, oflags); 178117133Ssam } 178217133Ssam if (fd != -1) 178317133Ssam filname = buf; 178417133Ssam return (fd); 178517133Ssam } 178617133Ssam 1787615Sbill struct nlist ** 1788615Sbill lookup() 1789615Sbill { 1790615Sbill register int sh; 1791615Sbill register struct nlist **hp; 1792615Sbill register char *cp, *cp1; 1793615Sbill register struct symseg *gp; 1794615Sbill register int i; 1795615Sbill 1796615Sbill sh = 0; 1797615Sbill for (cp = cursym.n_un.n_name; *cp;) 1798615Sbill sh = (sh<<1) + *cp++; 1799615Sbill sh = (sh & 0x7fffffff) % HSIZE; 1800615Sbill for (gp = symseg; gp < &symseg[NSEG]; gp++) { 1801615Sbill if (gp->sy_first == 0) { 1802615Sbill gp->sy_first = (struct nlist *) 1803615Sbill calloc(NSYM, sizeof (struct nlist)); 1804615Sbill gp->sy_hfirst = (struct nlist **) 1805615Sbill calloc(HSIZE, sizeof (struct nlist *)); 1806615Sbill if (gp->sy_first == 0 || gp->sy_hfirst == 0) 1807615Sbill error(1, "ran out of space for symbol table"); 1808615Sbill gp->sy_last = gp->sy_first + NSYM; 1809615Sbill gp->sy_hlast = gp->sy_hfirst + HSIZE; 1810615Sbill } 1811615Sbill if (gp > csymseg) 1812615Sbill csymseg = gp; 1813615Sbill hp = gp->sy_hfirst + sh; 1814615Sbill i = 1; 1815615Sbill do { 1816615Sbill if (*hp == 0) { 1817615Sbill if (gp->sy_used == NSYM) 1818615Sbill break; 1819615Sbill return (hp); 1820615Sbill } 1821615Sbill cp1 = (*hp)->n_un.n_name; 1822615Sbill for (cp = cursym.n_un.n_name; *cp == *cp1++;) 1823615Sbill if (*cp++ == 0) 1824615Sbill return (hp); 1825615Sbill hp += i; 1826615Sbill i += 2; 1827615Sbill if (hp >= gp->sy_hlast) 1828615Sbill hp -= HSIZE; 1829615Sbill } while (i < HSIZE); 1830615Sbill if (i > HSIZE) 1831615Sbill error(1, "hash table botch"); 1832615Sbill } 1833615Sbill error(1, "symbol table overflow"); 1834615Sbill /*NOTREACHED*/ 1835615Sbill } 1836615Sbill 1837615Sbill symfree(saved) 1838615Sbill struct nlist *saved; 1839615Sbill { 1840615Sbill register struct symseg *gp; 1841615Sbill register struct nlist *sp; 1842615Sbill 1843615Sbill for (gp = csymseg; gp >= symseg; gp--, csymseg--) { 1844615Sbill sp = gp->sy_first + gp->sy_used; 1845615Sbill if (sp == saved) { 1846615Sbill nextsym = sp; 1847615Sbill return; 1848615Sbill } 1849615Sbill for (sp--; sp >= gp->sy_first; sp--) { 1850615Sbill gp->sy_hfirst[sp->n_hash] = 0; 1851615Sbill gp->sy_used--; 1852615Sbill if (sp == saved) { 1853615Sbill nextsym = sp; 1854615Sbill return; 1855615Sbill } 1856615Sbill } 1857615Sbill } 1858615Sbill if (saved == 0) 1859615Sbill return; 1860615Sbill error(1, "symfree botch"); 1861615Sbill } 1862615Sbill 1863615Sbill struct nlist ** 1864615Sbill slookup(s) 1865615Sbill char *s; 1866615Sbill { 1867615Sbill 1868615Sbill cursym.n_un.n_name = s; 1869615Sbill cursym.n_type = N_EXT+N_UNDF; 1870615Sbill cursym.n_value = 0; 1871615Sbill return (lookup()); 1872615Sbill } 1873615Sbill 1874615Sbill enter(hp) 1875615Sbill register struct nlist **hp; 1876615Sbill { 1877615Sbill register struct nlist *sp; 1878615Sbill 1879615Sbill if (*hp==0) { 1880615Sbill if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast) 1881615Sbill error(1, "enter botch"); 1882615Sbill *hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used; 1883615Sbill csymseg->sy_used++; 1884615Sbill sp->n_un.n_name = cursym.n_un.n_name; 1885615Sbill sp->n_type = cursym.n_type; 1886615Sbill sp->n_hash = hp - csymseg->sy_hfirst; 1887615Sbill sp->n_value = cursym.n_value; 1888615Sbill nextsym = lastsym + 1; 1889615Sbill return(1); 1890615Sbill } else { 1891615Sbill lastsym = *hp; 1892615Sbill return(0); 1893615Sbill } 1894615Sbill } 1895615Sbill 1896615Sbill symx(sp) 1897615Sbill struct nlist *sp; 1898615Sbill { 1899615Sbill register struct symseg *gp; 1900615Sbill 1901615Sbill if (sp == 0) 1902615Sbill return (0); 1903615Sbill for (gp = csymseg; gp >= symseg; gp--) 1904615Sbill /* <= is sloppy so nextsym will always work */ 1905615Sbill if (sp >= gp->sy_first && sp <= gp->sy_last) 1906615Sbill return ((gp - symseg) * NSYM + sp - gp->sy_first); 1907615Sbill error(1, "symx botch"); 1908615Sbill /*NOTREACHED*/ 1909615Sbill } 1910615Sbill 1911615Sbill symreloc() 1912615Sbill { 1913615Sbill if(funding) return; 1914615Sbill switch (cursym.n_type & 017) { 1915615Sbill 1916615Sbill case N_TEXT: 1917615Sbill case N_EXT+N_TEXT: 1918615Sbill cursym.n_value += ctrel; 1919615Sbill return; 1920615Sbill 1921615Sbill case N_DATA: 1922615Sbill case N_EXT+N_DATA: 1923615Sbill cursym.n_value += cdrel; 1924615Sbill return; 1925615Sbill 1926615Sbill case N_BSS: 1927615Sbill case N_EXT+N_BSS: 1928615Sbill cursym.n_value += cbrel; 1929615Sbill return; 1930615Sbill 1931615Sbill case N_EXT+N_UNDF: 1932615Sbill return; 1933615Sbill 1934615Sbill default: 1935615Sbill if (cursym.n_type&N_EXT) 1936615Sbill cursym.n_type = N_EXT+N_ABS; 1937615Sbill return; 1938615Sbill } 1939615Sbill } 1940615Sbill 1941615Sbill error(n, s) 1942615Sbill char *s; 1943615Sbill { 1944898Sbill 1945615Sbill if (errlev==0) 1946615Sbill printf("ld:"); 1947615Sbill if (filname) { 1948615Sbill printf("%s", filname); 1949615Sbill if (n != -1 && archdr.ar_name[0]) 1950615Sbill printf("(%s)", archdr.ar_name); 1951615Sbill printf(": "); 1952615Sbill } 1953615Sbill printf("%s\n", s); 1954615Sbill if (n == -1) 1955615Sbill return; 1956615Sbill if (n) 1957615Sbill delexit(); 1958615Sbill errlev = 2; 1959615Sbill } 1960615Sbill 1961615Sbill readhdr(loc) 1962615Sbill off_t loc; 1963615Sbill { 1964615Sbill 1965615Sbill dseek(&text, loc, (long)sizeof(filhdr)); 1966615Sbill mget((short *)&filhdr, sizeof(filhdr), &text); 1967615Sbill if (N_BADMAG(filhdr)) { 1968615Sbill if (filhdr.a_magic == OARMAG) 1969615Sbill error(1, "old archive"); 1970615Sbill error(1, "bad magic number"); 1971615Sbill } 1972615Sbill if (filhdr.a_text&01 || filhdr.a_data&01) 1973615Sbill error(1, "text/data size odd"); 1974615Sbill if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) { 197512671Ssam cdrel = -round(filhdr.a_text, pagesize); 1976615Sbill cbrel = cdrel - filhdr.a_data; 1977615Sbill } else if (filhdr.a_magic == OMAGIC) { 1978615Sbill cdrel = -filhdr.a_text; 1979615Sbill cbrel = cdrel - filhdr.a_data; 1980615Sbill } else 1981615Sbill error(1, "bad format"); 1982615Sbill } 1983615Sbill 1984615Sbill round(v, r) 1985615Sbill int v; 1986615Sbill u_long r; 1987615Sbill { 1988615Sbill 1989615Sbill r--; 1990615Sbill v += r; 1991615Sbill v &= ~(long)r; 1992615Sbill return(v); 1993615Sbill } 1994615Sbill 1995615Sbill #define NSAVETAB 8192 1996615Sbill char *savetab; 1997615Sbill int saveleft; 1998615Sbill 1999615Sbill char * 2000615Sbill savestr(cp) 2001615Sbill register char *cp; 2002615Sbill { 2003615Sbill register int len; 2004615Sbill 2005615Sbill len = strlen(cp) + 1; 2006615Sbill if (len > saveleft) { 2007615Sbill saveleft = NSAVETAB; 2008615Sbill if (len > saveleft) 2009615Sbill saveleft = len; 201017133Ssam savetab = malloc(saveleft); 2011615Sbill if (savetab == 0) 2012615Sbill error(1, "ran out of memory (savestr)"); 2013615Sbill } 2014615Sbill strncpy(savetab, cp, len); 2015615Sbill cp = savetab; 2016615Sbill savetab += len; 2017615Sbill saveleft -= len; 2018615Sbill return (cp); 2019615Sbill } 2020615Sbill 202116068Sralph bopen(bp, off, bufsize) 202216068Sralph register struct biobuf *bp; 2023615Sbill { 2024615Sbill 202517133Ssam bp->b_ptr = bp->b_buf = malloc(bufsize); 202616068Sralph if (bp->b_ptr == (char *)0) 202716068Sralph error(1, "ran out of memory (bopen)"); 202816068Sralph bp->b_bufsize = bufsize; 202916068Sralph bp->b_nleft = bufsize - (off % bufsize); 2030615Sbill bp->b_off = off; 2031615Sbill bp->b_link = biobufs; 2032615Sbill biobufs = bp; 2033615Sbill } 2034615Sbill 2035615Sbill int bwrerror; 2036615Sbill 2037615Sbill bwrite(p, cnt, bp) 2038615Sbill register char *p; 2039615Sbill register int cnt; 2040615Sbill register struct biobuf *bp; 2041615Sbill { 2042615Sbill register int put; 2043615Sbill register char *to; 2044615Sbill 2045615Sbill top: 2046615Sbill if (cnt == 0) 2047615Sbill return; 2048615Sbill if (bp->b_nleft) { 2049615Sbill put = bp->b_nleft; 2050615Sbill if (put > cnt) 2051615Sbill put = cnt; 2052615Sbill bp->b_nleft -= put; 2053615Sbill to = bp->b_ptr; 205425419Sbloom bcopy(p, to, put); 2055615Sbill bp->b_ptr += put; 2056615Sbill p += put; 2057615Sbill cnt -= put; 2058615Sbill goto top; 2059615Sbill } 206016068Sralph if (cnt >= bp->b_bufsize) { 2061615Sbill if (bp->b_ptr != bp->b_buf) 2062615Sbill bflush1(bp); 206316068Sralph put = cnt - cnt % bp->b_bufsize; 2064615Sbill if (boffset != bp->b_off) 2065615Sbill lseek(biofd, bp->b_off, 0); 2066615Sbill if (write(biofd, p, put) != put) { 2067615Sbill bwrerror = 1; 2068615Sbill error(1, "output write error"); 2069615Sbill } 2070615Sbill bp->b_off += put; 2071615Sbill boffset = bp->b_off; 2072615Sbill p += put; 2073615Sbill cnt -= put; 2074615Sbill goto top; 2075615Sbill } 2076615Sbill bflush1(bp); 2077615Sbill goto top; 2078615Sbill } 2079615Sbill 2080615Sbill bflush() 2081615Sbill { 2082615Sbill register struct biobuf *bp; 2083615Sbill 2084615Sbill if (bwrerror) 2085615Sbill return; 2086615Sbill for (bp = biobufs; bp; bp = bp->b_link) 2087615Sbill bflush1(bp); 2088615Sbill } 2089615Sbill 2090615Sbill bflush1(bp) 2091615Sbill register struct biobuf *bp; 2092615Sbill { 2093615Sbill register int cnt = bp->b_ptr - bp->b_buf; 2094615Sbill 2095615Sbill if (cnt == 0) 2096615Sbill return; 2097615Sbill if (boffset != bp->b_off) 2098615Sbill lseek(biofd, bp->b_off, 0); 2099615Sbill if (write(biofd, bp->b_buf, cnt) != cnt) { 2100615Sbill bwrerror = 1; 2101615Sbill error(1, "output write error"); 2102615Sbill } 2103615Sbill bp->b_off += cnt; 2104615Sbill boffset = bp->b_off; 2105615Sbill bp->b_ptr = bp->b_buf; 210616068Sralph bp->b_nleft = bp->b_bufsize; 2107615Sbill } 2108615Sbill 2109615Sbill bflushc(bp, c) 2110615Sbill register struct biobuf *bp; 2111615Sbill { 2112615Sbill 2113615Sbill bflush1(bp); 2114615Sbill bputc(c, bp); 2115615Sbill } 211616068Sralph 211716068Sralph bseek(bp, off) 211816068Sralph register struct biobuf *bp; 211916068Sralph register off_t off; 212016068Sralph { 212116068Sralph bflush1(bp); 212216068Sralph 212316068Sralph bp->b_nleft = bp->b_bufsize - (off % bp->b_bufsize); 212416068Sralph bp->b_off = off; 212516068Sralph } 2126