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*46696Sbostic static char sccsid[] = "@(#)ld.c 5.18 (Berkeley) 02/26/91"; 1519842Sdist #endif not lint 1619842Sdist 17615Sbill /* 18898Sbill * ld - string table version for VAX 19615Sbill */ 20615Sbill 2117133Ssam #include <sys/param.h> 2242415Sbostic #include <sys/stat.h> 23*46696Sbostic #include <fcntl.h> 24*46696Sbostic #include <signal.h> 25650Sbill #include <ar.h> 26650Sbill #include <a.out.h> 27615Sbill #include <ranlib.h> 28*46696Sbostic #include <unistd.h> 2942415Sbostic #include <stdio.h> 3042415Sbostic #include <ctype.h> 31*46696Sbostic #include <stdlib.h> 3242415Sbostic #include <string.h> 3337031Sbostic #include "pathnames.h" 34615Sbill 35615Sbill /* 36615Sbill * Basic strategy: 37615Sbill * 38615Sbill * The loader takes a number of files and libraries as arguments. 39615Sbill * A first pass examines each file in turn. Normal files are 40615Sbill * unconditionally loaded, and the (external) symbols they define and require 41615Sbill * are noted in the symbol table. Libraries are searched, and the 42615Sbill * library members which define needed symbols are remembered 43615Sbill * in a special data structure so they can be selected on the second 44615Sbill * pass. Symbols defined and required by library members are also 45615Sbill * recorded. 46615Sbill * 47615Sbill * After the first pass, the loader knows the size of the basic text 48615Sbill * data, and bss segments from the sum of the sizes of the modules which 49615Sbill * were required. It has computed, for each ``common'' symbol, the 50615Sbill * maximum size of any reference to it, and these symbols are then assigned 51615Sbill * storage locations after their sizes are appropriately rounded. 52615Sbill * The loader now knows all sizes for the eventual output file, and 53615Sbill * can determine the final locations of external symbols before it 54615Sbill * begins a second pass. 55615Sbill * 56615Sbill * On the second pass each normal file and required library member 57615Sbill * is processed again. The symbol table for each such file is 58615Sbill * reread and relevant parts of it are placed in the output. The offsets 59615Sbill * in the local symbol table for externally defined symbols are recorded 60615Sbill * since relocation information refers to symbols in this way. 61615Sbill * Armed with all necessary information, the text and data segments 62615Sbill * are relocated and the result is placed in the output file, which 63615Sbill * is pasted together, ``in place'', by writing to it in several 64615Sbill * different places concurrently. 65615Sbill */ 66615Sbill 67615Sbill /* 68615Sbill * Internal data structures 69615Sbill * 70615Sbill * All internal data structures are segmented and dynamically extended. 71615Sbill * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT) 72615Sbill * referenced library members, and 100 (NSYMPR) private (local) symbols 73615Sbill * per object module. For large programs and/or modules, these structures 74615Sbill * expand to be up to 40 (NSEG) times as large as this as necessary. 75615Sbill */ 76615Sbill #define NSEG 40 /* Number of segments, each data structure */ 77615Sbill #define NSYM 1103 /* Number of symbols per segment */ 78615Sbill #define NROUT 250 /* Number of library references per segment */ 79615Sbill #define NSYMPR 100 /* Number of private symbols per segment */ 80615Sbill 81615Sbill /* 82615Sbill * Structure describing each symbol table segment. 83615Sbill * Each segment has its own hash table. We record the first 84615Sbill * address in and first address beyond both the symbol and hash 85615Sbill * tables, for use in the routine symx and the lookup routine respectively. 86615Sbill * The symfree routine also understands this structure well as it used 87615Sbill * to back out symbols from modules we decide that we don't need in pass 1. 88615Sbill * 89615Sbill * Csymseg points to the current symbol table segment; 90615Sbill * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated, 91615Sbill * (unless csymseg->sy_used == NSYM in which case we will allocate another 92615Sbill * symbol table segment first.) 93615Sbill */ 94615Sbill struct symseg { 95615Sbill struct nlist *sy_first; /* base of this alloc'ed segment */ 96615Sbill struct nlist *sy_last; /* end of this segment, for n_strx */ 97615Sbill int sy_used; /* symbols used in this seg */ 98615Sbill struct nlist **sy_hfirst; /* base of hash table, this seg */ 99615Sbill struct nlist **sy_hlast; /* end of hash table, this seg */ 100615Sbill } symseg[NSEG], *csymseg; 101615Sbill 102615Sbill /* 103615Sbill * The lookup routine uses quadratic rehash. Since a quadratic rehash 104615Sbill * only probes 1/2 of the buckets in the table, and since the hash 105615Sbill * table is segmented the same way the symbol table is, we make the 106615Sbill * hash table have twice as many buckets as there are symbol table slots 107615Sbill * in the segment. This guarantees that the quadratic rehash will never 108615Sbill * fail to find an empty bucket if the segment is not full and the 109615Sbill * symbol is not there. 110615Sbill */ 111615Sbill #define HSIZE (NSYM*2) 112615Sbill 113615Sbill /* 114615Sbill * Xsym converts symbol table indices (ala x) into symbol table pointers. 115615Sbill * Symx (harder, but never used in loops) inverts pointers into the symbol 116615Sbill * table into indices using the symseg[] structure. 117615Sbill */ 118615Sbill #define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM)) 119615Sbill /* symx() is a function, defined below */ 120615Sbill 121615Sbill struct nlist cursym; /* current symbol */ 122615Sbill struct nlist *lastsym; /* last symbol entered */ 123615Sbill struct nlist *nextsym; /* next available symbol table entry */ 124615Sbill struct nlist *addsym; /* first sym defined during incr load */ 125615Sbill int nsym; /* pass2: number of local symbols in a.out */ 126615Sbill /* nsym + symx(nextsym) is the symbol table size during pass2 */ 127615Sbill 128615Sbill struct nlist **lookup(), **slookup(); 129650Sbill struct nlist *p_etext, *p_edata, *p_end, *entrypt; 130615Sbill 131615Sbill /* 132615Sbill * Definitions of segmentation for library member table. 133615Sbill * For each library we encounter on pass 1 we record pointers to all 134615Sbill * members which we will load on pass 2. These are recorded as offsets 135615Sbill * into the archive in the library member table. Libraries are 136615Sbill * separated in the table by the special offset value -1. 137615Sbill */ 138615Sbill off_t li_init[NROUT]; 139615Sbill struct libseg { 140615Sbill off_t *li_first; 141615Sbill int li_used; 142615Sbill int li_used2; 143615Sbill } libseg[NSEG] = { 144615Sbill li_init, 0, 0, 145615Sbill }, *clibseg = libseg; 146615Sbill 147615Sbill /* 148615Sbill * In processing each module on pass 2 we must relocate references 149615Sbill * relative to external symbols. These references are recorded 150615Sbill * in the relocation information as relative to local symbol numbers 151615Sbill * assigned to the external symbols when the module was created. 152615Sbill * Thus before relocating the module in pass 2 we create a table 153615Sbill * which maps these internal numbers to symbol table entries. 154615Sbill * A hash table is constructed, based on the local symbol table indices, 155615Sbill * for quick lookup of these symbols. 156615Sbill */ 157615Sbill #define LHSIZ 31 158615Sbill struct local { 159615Sbill int l_index; /* index to symbol in file */ 160615Sbill struct nlist *l_symbol; /* ptr to symbol table */ 161615Sbill struct local *l_link; /* hash link */ 162615Sbill } *lochash[LHSIZ], lhinit[NSYMPR]; 163615Sbill struct locseg { 164615Sbill struct local *lo_first; 165615Sbill int lo_used; 166615Sbill } locseg[NSEG] = { 167615Sbill lhinit, 0 168615Sbill }, *clocseg; 169615Sbill 170615Sbill /* 171615Sbill * Libraries are typically built with a table of contents, 172615Sbill * which is the first member of a library with special file 173615Sbill * name __.SYMDEF and contains a list of symbol names 174615Sbill * and with each symbol the offset of the library member which defines 175615Sbill * it. The loader uses this table to quickly tell which library members 176615Sbill * are (potentially) useful. The alternative, examining the symbol 177615Sbill * table of each library member, is painfully slow for large archives. 178615Sbill * 179615Sbill * See <ranlib.h> for the definition of the ranlib structure and an 180615Sbill * explanation of the __.SYMDEF file format. 181615Sbill */ 182615Sbill int tnum; /* number of symbols in table of contents */ 183615Sbill int ssiz; /* size of string table for table of contents */ 184615Sbill struct ranlib *tab; /* the table of contents (dynamically allocated) */ 185615Sbill char *tabstr; /* string table for table of contents */ 186615Sbill 187615Sbill /* 188615Sbill * We open each input file or library only once, but in pass2 we 189615Sbill * (historically) read from such a file at 2 different places at the 190615Sbill * same time. These structures are remnants from those days, 191650Sbill * and now serve only to catch ``Premature EOF''. 1926414Smckusic * In order to make I/O more efficient, we provide routines which 19316068Sralph * use the optimal block size returned by stat(). 194615Sbill */ 1956414Smckusic #define BLKSIZE 1024 196615Sbill typedef struct { 197615Sbill short *fakeptr; 198615Sbill int bno; 199615Sbill int nibuf; 200615Sbill int nuser; 20116068Sralph char *buff; 20216068Sralph int bufsize; 203615Sbill } PAGE; 204615Sbill 205615Sbill PAGE page[2]; 20616068Sralph int p_blksize; 20716068Sralph int p_blkshift; 20816068Sralph int p_blkmask; 209615Sbill 210615Sbill struct { 211615Sbill short *fakeptr; 212615Sbill int bno; 213615Sbill int nibuf; 214615Sbill int nuser; 215615Sbill } fpage; 216615Sbill 217615Sbill typedef struct { 218615Sbill char *ptr; 219615Sbill int bno; 220615Sbill int nibuf; 221615Sbill long size; 222615Sbill long pos; 223615Sbill PAGE *pno; 224615Sbill } STREAM; 225615Sbill 226615Sbill STREAM text; 227615Sbill STREAM reloc; 228615Sbill 229615Sbill /* 230615Sbill * Header from the a.out and the archive it is from (if any). 231615Sbill */ 232615Sbill struct exec filhdr; 233615Sbill struct ar_hdr archdr; 234615Sbill #define OARMAG 0177545 235615Sbill 236615Sbill /* 237615Sbill * Options. 238615Sbill */ 239615Sbill int trace; 240615Sbill int xflag; /* discard local symbols */ 241615Sbill int Xflag; /* discard locals starting with 'L' */ 242615Sbill int Sflag; /* discard all except locals and globals*/ 243615Sbill int rflag; /* preserve relocation bits, don't define common */ 244615Sbill int arflag; /* original copy of rflag */ 245615Sbill int sflag; /* discard all symbols */ 246898Sbill int Mflag; /* print rudimentary load map */ 247615Sbill int nflag; /* pure procedure */ 248615Sbill int dflag; /* define common even with rflag */ 249650Sbill int zflag; /* demand paged */ 250615Sbill long hsize; /* size of hole at beginning of data to be squashed */ 251615Sbill int Aflag; /* doing incremental load */ 252650Sbill int Nflag; /* want impure a.out */ 253615Sbill int funding; /* reading fundamental file for incremental load */ 254898Sbill int yflag; /* number of symbols to be traced */ 255898Sbill char **ytab; /* the symbols */ 256615Sbill 257615Sbill /* 258615Sbill * These are the cumulative sizes, set in pass 1, which 259615Sbill * appear in the a.out header when the loader is finished. 260615Sbill */ 261615Sbill off_t tsize, dsize, bsize, trsize, drsize, ssize; 262615Sbill 263615Sbill /* 264615Sbill * Symbol relocation: c?rel is a scale factor which is 265615Sbill * added to an old relocation to convert it to new units; 266615Sbill * i.e. it is the difference between segment origins. 267650Sbill * (Thus if we are loading from a data segment which began at location 268650Sbill * 4 in a .o file into an a.out where it will be loaded starting at 269650Sbill * 1024, cdrel will be 1020.) 270615Sbill */ 271615Sbill long ctrel, cdrel, cbrel; 272615Sbill 273615Sbill /* 274650Sbill * Textbase is the start address of all text, 0 unless given by -T. 275615Sbill * Database is the base of all data, computed before and used during pass2. 276650Sbill */ 277650Sbill long textbase, database; 278650Sbill 279650Sbill /* 280615Sbill * The base addresses for the loaded text, data and bss from the 281615Sbill * current module during pass2 are given by torigin, dorigin and borigin. 282615Sbill */ 283615Sbill long torigin, dorigin, borigin; 284615Sbill 285615Sbill /* 286615Sbill * Errlev is nonzero when errors have occured. 287615Sbill * Delarg is an implicit argument to the routine delexit 288615Sbill * which is called on error. We do ``delarg = errlev'' before normal 289615Sbill * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the 290615Sbill * result file executable. 291615Sbill */ 292615Sbill int errlev; 293615Sbill int delarg = 4; 294615Sbill 295615Sbill /* 296615Sbill * The biobuf structure and associated routines are used to write 297615Sbill * into one file at several places concurrently. Calling bopen 298615Sbill * with a biobuf structure sets it up to write ``biofd'' starting 299615Sbill * at the specified offset. You can then use ``bwrite'' and/or ``bputc'' 300615Sbill * to stuff characters in the stream, much like ``fwrite'' and ``fputc''. 301615Sbill * Calling bflush drains all the buffers and MUST be done before exit. 302615Sbill */ 303615Sbill struct biobuf { 304615Sbill short b_nleft; /* Number free spaces left in b_buf */ 30516068Sralph /* Initialize to be less than b_bufsize initially, to boundary align in file */ 306615Sbill char *b_ptr; /* Next place to stuff characters */ 30716068Sralph char *b_buf; /* Pointer to the buffer */ 30816068Sralph int b_bufsize; /* Size of the buffer */ 309615Sbill off_t b_off; /* Current file offset */ 310615Sbill struct biobuf *b_link; /* Link in chain for bflush() */ 311615Sbill } *biobufs; 312615Sbill #define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \ 313615Sbill : bflushc(b, c)) 314615Sbill int biofd; 315615Sbill off_t boffset; 316615Sbill struct biobuf *tout, *dout, *trout, *drout, *sout, *strout; 317615Sbill 318615Sbill /* 319615Sbill * Offset is the current offset in the string file. 320615Sbill * Its initial value reflects the fact that we will 321615Sbill * eventually stuff the size of the string table at the 322615Sbill * beginning of the string table (i.e. offset itself!). 323615Sbill */ 324615Sbill off_t offset = sizeof (off_t); 325615Sbill 326615Sbill int ofilfnd; /* -o given; otherwise move l.out to a.out */ 32744768Sbostic char *ofilename = "l.out"; 3283606Ssklower int ofilemode; /* respect umask even for unsucessful ld's */ 329615Sbill int infil; /* current input file descriptor */ 330615Sbill char *filname; /* and its name */ 331615Sbill 33217133Ssam #define NDIRS 25 33325533Sbloom #define NDEFDIRS 3 /* number of default directories in dirs[] */ 33417133Ssam char *dirs[NDIRS]; /* directories for library search */ 33517133Ssam int ndir; /* number of directories */ 33617133Ssam 337615Sbill /* 338615Sbill * Base of the string table of the current module (pass1 and pass2). 339615Sbill */ 340615Sbill char *curstr; 341615Sbill 34212671Ssam /* 34312671Ssam * System software page size, as returned by getpagesize. 34412671Ssam */ 34512671Ssam int pagesize; 34612671Ssam 347615Sbill char get(); 348*46696Sbostic void delexit(); 349615Sbill char *savestr(); 350615Sbill 351615Sbill main(argc, argv) 352*46696Sbostic int argc; 353*46696Sbostic char **argv; 354615Sbill { 355615Sbill register int c, i; 356615Sbill int num; 357615Sbill register char *ap, **p; 358615Sbill char save; 359615Sbill 360650Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 361615Sbill signal(SIGINT, delexit); 362650Sbill signal(SIGTERM, delexit); 363650Sbill } 364615Sbill if (argc == 1) 365615Sbill exit(4); 36612671Ssam pagesize = getpagesize(); 367615Sbill 36817133Ssam /* 36917133Ssam * Pull out search directories. 37017133Ssam */ 37117133Ssam for (c = 1; c < argc; c++) { 37217133Ssam ap = argv[c]; 37317133Ssam if (ap[0] == '-' && ap[1] == 'L') { 37417133Ssam if (ap[2] == 0) 37517133Ssam error(1, "-L: pathname missing"); 37625533Sbloom if (ndir >= NDIRS - NDEFDIRS) 37717133Ssam error(1, "-L: too many directories"); 37817133Ssam dirs[ndir++] = &ap[2]; 37917133Ssam } 38017133Ssam } 38117133Ssam /* add default search directories */ 38237031Sbostic dirs[ndir++] = _PATH_USRLIB; 38337031Sbostic dirs[ndir++] = _PATH_LOCALLIB; 38417133Ssam 38517133Ssam p = argv+1; 386650Sbill /* 387650Sbill * Scan files once to find where symbols are defined. 388650Sbill */ 389615Sbill for (c=1; c<argc; c++) { 390615Sbill if (trace) 391615Sbill printf("%s:\n", *p); 392615Sbill filname = 0; 393615Sbill ap = *p++; 394615Sbill if (*ap != '-') { 395615Sbill load1arg(ap); 396615Sbill continue; 397615Sbill } 398615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 399615Sbill 400615Sbill case 'o': 401615Sbill if (++c >= argc) 402615Sbill error(1, "-o where?"); 40344768Sbostic ofilename = *p++; 404615Sbill ofilfnd++; 405615Sbill continue; 406615Sbill case 'u': 407615Sbill case 'e': 408615Sbill if (++c >= argc) 40933997Sbostic error(1, " -u or -e: arg missing"); 410615Sbill enter(slookup(*p++)); 411615Sbill if (ap[i]=='e') 412615Sbill entrypt = lastsym; 413615Sbill continue; 414615Sbill case 'H': 415615Sbill if (++c >= argc) 416615Sbill error(1, "-H: arg missing"); 417615Sbill if (tsize!=0) 418615Sbill error(1, "-H: too late, some text already loaded"); 419615Sbill hsize = atoi(*p++); 420615Sbill continue; 421615Sbill case 'A': 422615Sbill if (++c >= argc) 423615Sbill error(1, "-A: arg missing"); 424615Sbill if (Aflag) 425615Sbill error(1, "-A: only one base file allowed"); 426615Sbill Aflag = 1; 427615Sbill nflag = 0; 428615Sbill funding = 1; 429615Sbill load1arg(*p++); 430615Sbill trsize = drsize = tsize = dsize = bsize = 0; 431615Sbill ctrel = cdrel = cbrel = 0; 432615Sbill funding = 0; 433615Sbill addsym = nextsym; 434615Sbill continue; 435615Sbill case 'D': 436615Sbill if (++c >= argc) 437615Sbill error(1, "-D: arg missing"); 438615Sbill num = htoi(*p++); 439615Sbill if (dsize > num) 440615Sbill error(1, "-D: too small"); 441615Sbill dsize = num; 442615Sbill continue; 443615Sbill case 'T': 444615Sbill if (++c >= argc) 445615Sbill error(1, "-T: arg missing"); 446615Sbill if (tsize!=0) 447615Sbill error(1, "-T: too late, some text already loaded"); 448615Sbill textbase = htoi(*p++); 449615Sbill continue; 450615Sbill case 'l': 451615Sbill save = ap[--i]; 452615Sbill ap[i]='-'; 453615Sbill load1arg(&ap[i]); 454615Sbill ap[i]=save; 455615Sbill goto next; 456898Sbill case 'M': 457898Sbill Mflag++; 458898Sbill continue; 459615Sbill case 'x': 460615Sbill xflag++; 461615Sbill continue; 462615Sbill case 'X': 463615Sbill Xflag++; 464615Sbill continue; 465615Sbill case 'S': 466615Sbill Sflag++; 467615Sbill continue; 468615Sbill case 'r': 469615Sbill rflag++; 470615Sbill arflag++; 471615Sbill continue; 472615Sbill case 's': 473615Sbill sflag++; 474615Sbill xflag++; 475615Sbill continue; 476615Sbill case 'n': 477615Sbill nflag++; 478650Sbill Nflag = zflag = 0; 479615Sbill continue; 480615Sbill case 'N': 481650Sbill Nflag++; 482650Sbill nflag = zflag = 0; 483615Sbill continue; 484615Sbill case 'd': 485615Sbill dflag++; 486615Sbill continue; 487615Sbill case 'i': 488615Sbill printf("ld: -i ignored\n"); 489615Sbill continue; 490615Sbill case 't': 491615Sbill trace++; 492615Sbill continue; 493898Sbill case 'y': 494898Sbill if (ap[i+1] == 0) 495898Sbill error(1, "-y: symbol name missing"); 496898Sbill if (yflag == 0) { 497898Sbill ytab = (char **)calloc(argc, sizeof (char **)); 498898Sbill if (ytab == 0) 499898Sbill error(1, "ran out of memory (-y)"); 500898Sbill } 501898Sbill ytab[yflag++] = &ap[i+1]; 502898Sbill goto next; 503615Sbill case 'z': 504615Sbill zflag++; 505650Sbill Nflag = nflag = 0; 506615Sbill continue; 50717133Ssam case 'L': 50817133Ssam goto next; 509615Sbill default: 510615Sbill filname = savestr("-x"); /* kludge */ 511615Sbill filname[1] = ap[i]; /* kludge */ 512615Sbill archdr.ar_name[0] = 0; /* kludge */ 513615Sbill error(1, "bad flag"); 514615Sbill } 515615Sbill next: 516615Sbill ; 517615Sbill } 518650Sbill if (rflag == 0 && Nflag == 0 && nflag == 0) 519650Sbill zflag++; 520615Sbill endload(argc, argv); 521615Sbill exit(0); 522615Sbill } 523615Sbill 524615Sbill /* 525615Sbill * Convert a ascii string which is a hex number. 526615Sbill * Used by -T and -D options. 527615Sbill */ 528615Sbill htoi(p) 529615Sbill register char *p; 530615Sbill { 531615Sbill register int c, n; 532615Sbill 533615Sbill n = 0; 534615Sbill while (c = *p++) { 535615Sbill n <<= 4; 536615Sbill if (isdigit(c)) 537615Sbill n += c - '0'; 538615Sbill else if (c >= 'a' && c <= 'f') 539615Sbill n += 10 + (c - 'a'); 540615Sbill else if (c >= 'A' && c <= 'F') 541615Sbill n += 10 + (c - 'A'); 542615Sbill else 543615Sbill error(1, "badly formed hex number"); 544615Sbill } 545615Sbill return (n); 546615Sbill } 547615Sbill 548*46696Sbostic void 549615Sbill delexit() 550615Sbill { 5519332Smckusick struct stat stbuf; 5529332Smckusick long size; 5539332Smckusick char c = 0; 554615Sbill 555615Sbill bflush(); 55644768Sbostic unlink("l.out"); 5579332Smckusick /* 5589332Smckusick * We have to insure that the last block of the data segment 55916068Sralph * is allocated a full pagesize block. If the underlying 56016068Sralph * file system allocates frags that are smaller than pagesize, 56116068Sralph * a full zero filled pagesize block needs to be allocated so 5629332Smckusick * that when it is demand paged, the paged in block will be 5639332Smckusick * appropriately filled with zeros. 5649332Smckusick */ 5659332Smckusick fstat(biofd, &stbuf); 56616068Sralph size = round(stbuf.st_size, pagesize); 56710640Smckusick if (!rflag && size > stbuf.st_size) { 5689332Smckusick lseek(biofd, size - 1, 0); 56925419Sbloom if (write(biofd, &c, 1) != 1) 57025419Sbloom delarg |= 4; 5719332Smckusick } 57225419Sbloom if (delarg==0 && Aflag==0) 57325419Sbloom (void) chmod(ofilename, ofilemode); 574615Sbill exit (delarg); 575615Sbill } 576615Sbill 577615Sbill endload(argc, argv) 578615Sbill int argc; 579615Sbill char **argv; 580615Sbill { 581615Sbill register int c, i; 582615Sbill long dnum; 583615Sbill register char *ap, **p; 584615Sbill 585615Sbill clibseg = libseg; 586615Sbill filname = 0; 587615Sbill middle(); 588615Sbill setupout(); 589615Sbill p = argv+1; 590615Sbill for (c=1; c<argc; c++) { 591615Sbill ap = *p++; 592615Sbill if (trace) 593615Sbill printf("%s:\n", ap); 594615Sbill if (*ap != '-') { 595615Sbill load2arg(ap); 596615Sbill continue; 597615Sbill } 598615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 599615Sbill 600615Sbill case 'D': 601615Sbill dnum = htoi(*p); 602615Sbill if (dorigin < dnum) 603615Sbill while (dorigin < dnum) 604615Sbill bputc(0, dout), dorigin++; 605615Sbill /* fall into ... */ 606615Sbill case 'T': 607615Sbill case 'u': 608615Sbill case 'e': 609615Sbill case 'o': 610615Sbill case 'H': 611615Sbill ++c; 612615Sbill ++p; 613615Sbill /* fall into ... */ 614615Sbill default: 615615Sbill continue; 616615Sbill case 'A': 617615Sbill funding = 1; 618615Sbill load2arg(*p++); 619615Sbill funding = 0; 620615Sbill c++; 621615Sbill continue; 622898Sbill case 'y': 62317133Ssam case 'L': 624898Sbill goto next; 625615Sbill case 'l': 626615Sbill ap[--i]='-'; 627615Sbill load2arg(&ap[i]); 628615Sbill goto next; 629615Sbill } 630615Sbill next: 631615Sbill ; 632615Sbill } 633615Sbill finishout(); 634615Sbill } 635615Sbill 636615Sbill /* 637615Sbill * Scan file to find defined symbols. 638615Sbill */ 639615Sbill load1arg(cp) 640615Sbill register char *cp; 641615Sbill { 642615Sbill register struct ranlib *tp; 643615Sbill off_t nloc; 644898Sbill int kind; 645615Sbill 646898Sbill kind = getfile(cp); 647898Sbill if (Mflag) 648898Sbill printf("%s\n", filname); 649898Sbill switch (kind) { 650615Sbill 651615Sbill /* 652615Sbill * Plain file. 653615Sbill */ 654615Sbill case 0: 655615Sbill load1(0, 0L); 656615Sbill break; 657615Sbill 658615Sbill /* 659615Sbill * Archive without table of contents. 660615Sbill * (Slowly) process each member. 661615Sbill */ 662615Sbill case 1: 663898Sbill error(-1, 664898Sbill "warning: archive has no table of contents; add one using ranlib(1)"); 665615Sbill nloc = SARMAG; 666615Sbill while (step(nloc)) 667615Sbill nloc += sizeof(archdr) + 668615Sbill round(atol(archdr.ar_size), sizeof (short)); 669615Sbill break; 670615Sbill 671615Sbill /* 672615Sbill * Archive with table of contents. 673615Sbill * Read the table of contents and its associated string table. 674615Sbill * Pass through the library resolving symbols until nothing changes 675615Sbill * for an entire pass (i.e. you can get away with backward references 676615Sbill * when there is a table of contents!) 677615Sbill */ 678615Sbill case 2: 679615Sbill nloc = SARMAG + sizeof (archdr); 680615Sbill dseek(&text, nloc, sizeof (tnum)); 681615Sbill mget((char *)&tnum, sizeof (tnum), &text); 682615Sbill nloc += sizeof (tnum); 683615Sbill tab = (struct ranlib *)malloc(tnum); 684615Sbill if (tab == 0) 685615Sbill error(1, "ran out of memory (toc)"); 686615Sbill dseek(&text, nloc, tnum); 687615Sbill mget((char *)tab, tnum, &text); 688615Sbill nloc += tnum; 689615Sbill tnum /= sizeof (struct ranlib); 690615Sbill dseek(&text, nloc, sizeof (ssiz)); 691615Sbill mget((char *)&ssiz, sizeof (ssiz), &text); 692615Sbill nloc += sizeof (ssiz); 693615Sbill tabstr = (char *)malloc(ssiz); 694615Sbill if (tabstr == 0) 695615Sbill error(1, "ran out of memory (tocstr)"); 696615Sbill dseek(&text, nloc, ssiz); 697615Sbill mget((char *)tabstr, ssiz, &text); 698615Sbill for (tp = &tab[tnum]; --tp >= tab;) { 699615Sbill if (tp->ran_un.ran_strx < 0 || 700615Sbill tp->ran_un.ran_strx >= ssiz) 701615Sbill error(1, "mangled archive table of contents"); 702615Sbill tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx; 703615Sbill } 704615Sbill while (ldrand()) 705615Sbill continue; 70625483Slepreau free((char *)tab); 70725483Slepreau free(tabstr); 708615Sbill nextlibp(-1); 709615Sbill break; 710615Sbill 711615Sbill /* 712615Sbill * Table of contents is out of date, so search 713615Sbill * as a normal library (but skip the __.SYMDEF file). 714615Sbill */ 715615Sbill case 3: 716898Sbill error(-1, 717898Sbill "warning: table of contents for archive is out of date; rerun ranlib(1)"); 718615Sbill nloc = SARMAG; 719615Sbill do 720615Sbill nloc += sizeof(archdr) + 721615Sbill round(atol(archdr.ar_size), sizeof(short)); 722615Sbill while (step(nloc)); 723615Sbill break; 724615Sbill } 725615Sbill close(infil); 726615Sbill } 727615Sbill 728615Sbill /* 729615Sbill * Advance to the next archive member, which 730615Sbill * is at offset nloc in the archive. If the member 731615Sbill * is useful, record its location in the liblist structure 732615Sbill * for use in pass2. Mark the end of the archive in libilst with a -1. 733615Sbill */ 734615Sbill step(nloc) 735615Sbill off_t nloc; 736615Sbill { 737615Sbill 738615Sbill dseek(&text, nloc, (long) sizeof archdr); 739615Sbill if (text.size <= 0) { 740615Sbill nextlibp(-1); 741615Sbill return (0); 742615Sbill } 743615Sbill getarhdr(); 744615Sbill if (load1(1, nloc + (sizeof archdr))) 745615Sbill nextlibp(nloc); 746615Sbill return (1); 747615Sbill } 748615Sbill 749615Sbill /* 750615Sbill * Record the location of a useful archive member. 751615Sbill * Recording -1 marks the end of files from an archive. 752615Sbill * The liblist data structure is dynamically extended here. 753615Sbill */ 754615Sbill nextlibp(val) 755615Sbill off_t val; 756615Sbill { 757615Sbill 758615Sbill if (clibseg->li_used == NROUT) { 759615Sbill if (++clibseg == &libseg[NSEG]) 760615Sbill error(1, "too many files loaded from libraries"); 761615Sbill clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t)); 762615Sbill if (clibseg->li_first == 0) 763615Sbill error(1, "ran out of memory (nextlibp)"); 764615Sbill } 765615Sbill clibseg->li_first[clibseg->li_used++] = val; 766898Sbill if (val != -1 && Mflag) 767898Sbill printf("\t%s\n", archdr.ar_name); 768615Sbill } 769615Sbill 770615Sbill /* 771615Sbill * One pass over an archive with a table of contents. 772615Sbill * Remember the number of symbols currently defined, 773615Sbill * then call step on members which look promising (i.e. 774615Sbill * that define a symbol which is currently externally undefined). 775615Sbill * Indicate to our caller whether this process netted any more symbols. 776615Sbill */ 777615Sbill ldrand() 778615Sbill { 779615Sbill register struct nlist *sp, **hp; 780615Sbill register struct ranlib *tp, *tplast; 781615Sbill off_t loc; 782615Sbill int nsymt = symx(nextsym); 783615Sbill 784615Sbill tplast = &tab[tnum-1]; 785615Sbill for (tp = tab; tp <= tplast; tp++) { 78625483Slepreau if ((hp = slookup(tp->ran_un.ran_name)) == 0 || *hp == 0) 787615Sbill continue; 788615Sbill sp = *hp; 789615Sbill if (sp->n_type != N_EXT+N_UNDF) 790615Sbill continue; 791615Sbill step(tp->ran_off); 792615Sbill loc = tp->ran_off; 793615Sbill while (tp < tplast && (tp+1)->ran_off == loc) 794615Sbill tp++; 795615Sbill } 796615Sbill return (symx(nextsym) != nsymt); 797615Sbill } 798615Sbill 799615Sbill /* 800615Sbill * Examine a single file or archive member on pass 1. 801615Sbill */ 802615Sbill load1(libflg, loc) 803615Sbill off_t loc; 804615Sbill { 805615Sbill register struct nlist *sp; 806615Sbill struct nlist *savnext; 807615Sbill int ndef, nlocal, type, size, nsymt; 808615Sbill register int i; 809615Sbill off_t maxoff; 810615Sbill struct stat stb; 811615Sbill 812615Sbill readhdr(loc); 813615Sbill if (filhdr.a_syms == 0) { 81429999Sbostic if (filhdr.a_text+filhdr.a_data == 0) { 81529999Sbostic /* load2() adds a symbol for the file name */ 81629999Sbostic if (!libflg) 81729999Sbostic ssize += sizeof (cursym); 818615Sbill return (0); 81929999Sbostic } 820615Sbill error(1, "no namelist"); 821615Sbill } 822615Sbill if (libflg) 823615Sbill maxoff = atol(archdr.ar_size); 824615Sbill else { 825615Sbill fstat(infil, &stb); 826615Sbill maxoff = stb.st_size; 827615Sbill } 828615Sbill if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff) 829615Sbill error(1, "too small (old format .o?)"); 830615Sbill ctrel = tsize; cdrel += dsize; cbrel += bsize; 831615Sbill ndef = 0; 832615Sbill nlocal = sizeof(cursym); 833615Sbill savnext = nextsym; 834615Sbill loc += N_SYMOFF(filhdr); 835615Sbill dseek(&text, loc, filhdr.a_syms); 836615Sbill dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t)); 837615Sbill mget(&size, sizeof (size), &reloc); 838615Sbill dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t)); 839615Sbill curstr = (char *)malloc(size); 840615Sbill if (curstr == NULL) 841615Sbill error(1, "no space for string table"); 842615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc); 843615Sbill while (text.size > 0) { 844615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 845615Sbill if (cursym.n_un.n_strx) { 846615Sbill if (cursym.n_un.n_strx<sizeof(size) || 847615Sbill cursym.n_un.n_strx>=size) 848615Sbill error(1, "bad string table index (pass 1)"); 849615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 850615Sbill } 851615Sbill type = cursym.n_type; 852615Sbill if ((type&N_EXT)==0) { 853615Sbill if (Xflag==0 || cursym.n_un.n_name[0]!='L' || 854615Sbill type & N_STAB) 855615Sbill nlocal += sizeof cursym; 856615Sbill continue; 857615Sbill } 858615Sbill symreloc(); 859615Sbill if (enter(lookup())) 860615Sbill continue; 861615Sbill if ((sp = lastsym)->n_type != N_EXT+N_UNDF) 862615Sbill continue; 863615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 864615Sbill if (cursym.n_value > sp->n_value) 865615Sbill sp->n_value = cursym.n_value; 866615Sbill continue; 867615Sbill } 868615Sbill if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT) 869615Sbill continue; 870615Sbill ndef++; 871615Sbill sp->n_type = cursym.n_type; 872615Sbill sp->n_value = cursym.n_value; 873615Sbill } 874615Sbill if (libflg==0 || ndef) { 875615Sbill tsize += filhdr.a_text; 876615Sbill dsize += round(filhdr.a_data, sizeof (long)); 877615Sbill bsize += round(filhdr.a_bss, sizeof (long)); 878615Sbill ssize += nlocal; 879615Sbill trsize += filhdr.a_trsize; 880615Sbill drsize += filhdr.a_drsize; 881615Sbill if (funding) 882615Sbill textbase = (*slookup("_end"))->n_value; 883615Sbill nsymt = symx(nextsym); 884615Sbill for (i = symx(savnext); i < nsymt; i++) { 885615Sbill sp = xsym(i); 886615Sbill sp->n_un.n_name = savestr(sp->n_un.n_name); 887615Sbill } 888615Sbill free(curstr); 889615Sbill return (1); 890615Sbill } 891615Sbill /* 892615Sbill * No symbols defined by this library member. 893615Sbill * Rip out the hash table entries and reset the symbol table. 894615Sbill */ 895615Sbill symfree(savnext); 896615Sbill free(curstr); 897615Sbill return(0); 898615Sbill } 899615Sbill 900615Sbill middle() 901615Sbill { 902615Sbill register struct nlist *sp; 903615Sbill long csize, t, corigin, ocsize; 904615Sbill int nund, rnd; 905615Sbill char s; 906615Sbill register int i; 907615Sbill int nsymt; 908615Sbill 909615Sbill torigin = 0; 910615Sbill dorigin = 0; 911615Sbill borigin = 0; 912615Sbill 913615Sbill p_etext = *slookup("_etext"); 914615Sbill p_edata = *slookup("_edata"); 915615Sbill p_end = *slookup("_end"); 916615Sbill /* 917615Sbill * If there are any undefined symbols, save the relocation bits. 918615Sbill */ 919615Sbill nsymt = symx(nextsym); 920615Sbill if (rflag==0) { 921615Sbill for (i = 0; i < nsymt; i++) { 922615Sbill sp = xsym(i); 923615Sbill if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 && 924650Sbill sp!=p_end && sp!=p_edata && sp!=p_etext) { 925615Sbill rflag++; 926615Sbill dflag = 0; 927615Sbill break; 928615Sbill } 929615Sbill } 930615Sbill } 931615Sbill if (rflag) 932615Sbill sflag = zflag = 0; 933615Sbill /* 934615Sbill * Assign common locations. 935615Sbill */ 936615Sbill csize = 0; 937615Sbill if (!Aflag) 938615Sbill addsym = symseg[0].sy_first; 939615Sbill database = round(tsize+textbase, 94012671Ssam (nflag||zflag? pagesize : sizeof (long))); 941615Sbill database += hsize; 942615Sbill if (dflag || rflag==0) { 943615Sbill ldrsym(p_etext, tsize, N_EXT+N_TEXT); 944615Sbill ldrsym(p_edata, dsize, N_EXT+N_DATA); 945615Sbill ldrsym(p_end, bsize, N_EXT+N_BSS); 946615Sbill for (i = symx(addsym); i < nsymt; i++) { 947615Sbill sp = xsym(i); 948615Sbill if ((s=sp->n_type)==N_EXT+N_UNDF && 949615Sbill (t = sp->n_value)!=0) { 950615Sbill if (t >= sizeof (double)) 951615Sbill rnd = sizeof (double); 952615Sbill else if (t >= sizeof (long)) 953615Sbill rnd = sizeof (long); 954615Sbill else 955615Sbill rnd = sizeof (short); 956615Sbill csize = round(csize, rnd); 957615Sbill sp->n_value = csize; 958615Sbill sp->n_type = N_EXT+N_COMM; 959615Sbill ocsize = csize; 960615Sbill csize += t; 961615Sbill } 962615Sbill if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) { 963615Sbill sp->n_value = ocsize; 964615Sbill sp->n_type = (s&N_STAB) | (N_EXT+N_COMM); 965615Sbill } 966615Sbill } 967615Sbill } 968615Sbill /* 969615Sbill * Now set symbols to their final value 970615Sbill */ 971615Sbill csize = round(csize, sizeof (long)); 972615Sbill torigin = textbase; 973615Sbill dorigin = database; 974615Sbill corigin = dorigin + dsize; 975615Sbill borigin = corigin + csize; 976615Sbill nund = 0; 977615Sbill nsymt = symx(nextsym); 978615Sbill for (i = symx(addsym); i<nsymt; i++) { 979615Sbill sp = xsym(i); 980615Sbill switch (sp->n_type & (N_TYPE+N_EXT)) { 981615Sbill 982615Sbill case N_EXT+N_UNDF: 9832369Skre if (arflag == 0) 9842369Skre errlev |= 01; 985615Sbill if ((arflag==0 || dflag) && sp->n_value==0) { 986650Sbill if (sp==p_end || sp==p_etext || sp==p_edata) 987650Sbill continue; 988615Sbill if (nund==0) 989615Sbill printf("Undefined:\n"); 990615Sbill nund++; 991615Sbill printf("%s\n", sp->n_un.n_name); 992615Sbill } 993615Sbill continue; 994615Sbill case N_EXT+N_ABS: 995615Sbill default: 996615Sbill continue; 997615Sbill case N_EXT+N_TEXT: 998615Sbill sp->n_value += torigin; 999615Sbill continue; 1000615Sbill case N_EXT+N_DATA: 1001615Sbill sp->n_value += dorigin; 1002615Sbill continue; 1003615Sbill case N_EXT+N_BSS: 1004615Sbill sp->n_value += borigin; 1005615Sbill continue; 1006615Sbill case N_EXT+N_COMM: 1007615Sbill sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS); 1008615Sbill sp->n_value += corigin; 1009615Sbill continue; 1010615Sbill } 1011615Sbill } 1012615Sbill if (sflag || xflag) 1013615Sbill ssize = 0; 1014615Sbill bsize += csize; 1015615Sbill nsym = ssize / (sizeof cursym); 1016615Sbill if (Aflag) { 1017615Sbill fixspec(p_etext,torigin); 1018615Sbill fixspec(p_edata,dorigin); 1019615Sbill fixspec(p_end,borigin); 1020615Sbill } 1021615Sbill } 1022615Sbill 1023615Sbill fixspec(sym,offset) 1024615Sbill struct nlist *sym; 1025615Sbill long offset; 1026615Sbill { 1027615Sbill 1028615Sbill if(symx(sym) < symx(addsym) && sym!=0) 1029615Sbill sym->n_value += offset; 1030615Sbill } 1031615Sbill 1032615Sbill ldrsym(sp, val, type) 1033615Sbill register struct nlist *sp; 1034615Sbill long val; 1035615Sbill { 1036615Sbill 1037615Sbill if (sp == 0) 1038615Sbill return; 1039615Sbill if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) { 1040615Sbill printf("%s: ", sp->n_un.n_name); 1041615Sbill error(0, "user attempt to redfine loader-defined symbol"); 1042615Sbill return; 1043615Sbill } 1044615Sbill sp->n_type = type; 1045615Sbill sp->n_value = val; 1046615Sbill } 1047615Sbill 1048615Sbill off_t wroff; 1049615Sbill struct biobuf toutb; 1050615Sbill 1051615Sbill setupout() 1052615Sbill { 105342415Sbostic extern int errno; 1054615Sbill int bss; 105516068Sralph struct stat stbuf; 1056615Sbill 10573606Ssklower ofilemode = 0777 & ~umask(0); 10583606Ssklower biofd = creat(ofilename, 0666 & ofilemode); 1059898Sbill if (biofd < 0) { 1060898Sbill filname = ofilename; /* kludge */ 1061898Sbill archdr.ar_name[0] = 0; /* kludge */ 106242415Sbostic error(1, strerror(errno)); /* kludge */ 1063898Sbill } 106416068Sralph fstat(biofd, &stbuf); /* suppose file exists, wrong*/ 106516068Sralph if (stbuf.st_mode & 0111) { /* mode, ld fails? */ 106616068Sralph chmod(ofilename, stbuf.st_mode & 0666); 106716068Sralph ofilemode = stbuf.st_mode; 106816068Sralph } 106944293Sbostic #ifdef hp300 107044293Sbostic filhdr.a_mid = (rflag ? MID_ZERO : MID_HP300); 107144293Sbostic #endif 1072615Sbill filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC); 1073615Sbill filhdr.a_text = nflag ? tsize : 107412671Ssam round(tsize, zflag ? pagesize : sizeof (long)); 107512671Ssam filhdr.a_data = zflag ? round(dsize, pagesize) : dsize; 1076615Sbill bss = bsize - (filhdr.a_data - dsize); 1077615Sbill if (bss < 0) 1078615Sbill bss = 0; 1079615Sbill filhdr.a_bss = bss; 1080615Sbill filhdr.a_trsize = trsize; 1081615Sbill filhdr.a_drsize = drsize; 1082615Sbill filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym)); 1083615Sbill if (entrypt) { 1084615Sbill if (entrypt->n_type!=N_EXT+N_TEXT) 1085615Sbill error(0, "entry point not in text"); 1086615Sbill else 1087615Sbill filhdr.a_entry = entrypt->n_value; 1088615Sbill } else 1089615Sbill filhdr.a_entry = 0; 1090615Sbill filhdr.a_trsize = (rflag ? trsize:0); 1091615Sbill filhdr.a_drsize = (rflag ? drsize:0); 109216068Sralph tout = &toutb; 109316068Sralph bopen(tout, 0, stbuf.st_blksize); 1094615Sbill bwrite((char *)&filhdr, sizeof (filhdr), tout); 109516068Sralph if (zflag) 109616068Sralph bseek(tout, pagesize); 1097615Sbill wroff = N_TXTOFF(filhdr) + filhdr.a_text; 109816068Sralph outb(&dout, filhdr.a_data, stbuf.st_blksize); 1099615Sbill if (rflag) { 110016068Sralph outb(&trout, filhdr.a_trsize, stbuf.st_blksize); 110116068Sralph outb(&drout, filhdr.a_drsize, stbuf.st_blksize); 1102615Sbill } 1103615Sbill if (sflag==0 || xflag==0) { 110416068Sralph outb(&sout, filhdr.a_syms, stbuf.st_blksize); 1105615Sbill wroff += sizeof (offset); 110616068Sralph outb(&strout, 0, stbuf.st_blksize); 1107615Sbill } 1108615Sbill } 1109615Sbill 111016068Sralph outb(bp, inc, bufsize) 1111615Sbill register struct biobuf **bp; 1112615Sbill { 1113615Sbill 1114615Sbill *bp = (struct biobuf *)malloc(sizeof (struct biobuf)); 1115615Sbill if (*bp == 0) 1116615Sbill error(1, "ran out of memory (outb)"); 111716068Sralph bopen(*bp, wroff, bufsize); 1118615Sbill wroff += inc; 1119615Sbill } 1120615Sbill 1121615Sbill load2arg(acp) 1122615Sbill char *acp; 1123615Sbill { 1124615Sbill register char *cp; 1125615Sbill off_t loc; 1126615Sbill 1127615Sbill cp = acp; 1128615Sbill if (getfile(cp) == 0) { 1129615Sbill while (*cp) 1130615Sbill cp++; 1131615Sbill while (cp >= acp && *--cp != '/'); 1132615Sbill mkfsym(++cp); 1133615Sbill load2(0L); 1134615Sbill } else { /* scan archive members referenced */ 1135615Sbill for (;;) { 1136615Sbill if (clibseg->li_used2 == clibseg->li_used) { 1137615Sbill if (clibseg->li_used < NROUT) 1138615Sbill error(1, "libseg botch"); 1139615Sbill clibseg++; 1140615Sbill } 1141615Sbill loc = clibseg->li_first[clibseg->li_used2++]; 1142615Sbill if (loc == -1) 1143615Sbill break; 1144615Sbill dseek(&text, loc, (long)sizeof(archdr)); 1145615Sbill getarhdr(); 1146615Sbill mkfsym(archdr.ar_name); 1147615Sbill load2(loc + (long)sizeof(archdr)); 1148615Sbill } 1149615Sbill } 1150615Sbill close(infil); 1151615Sbill } 1152615Sbill 1153615Sbill load2(loc) 1154615Sbill long loc; 1155615Sbill { 1156615Sbill int size; 1157615Sbill register struct nlist *sp; 1158615Sbill register struct local *lp; 1159615Sbill register int symno, i; 1160615Sbill int type; 1161615Sbill 1162615Sbill readhdr(loc); 1163650Sbill if (!funding) { 1164615Sbill ctrel = torigin; 1165615Sbill cdrel += dorigin; 1166615Sbill cbrel += borigin; 1167615Sbill } 1168615Sbill /* 1169615Sbill * Reread the symbol table, recording the numbering 1170615Sbill * of symbols for fixing external references. 1171615Sbill */ 1172615Sbill for (i = 0; i < LHSIZ; i++) 1173615Sbill lochash[i] = 0; 1174615Sbill clocseg = locseg; 1175615Sbill clocseg->lo_used = 0; 1176615Sbill symno = -1; 1177615Sbill loc += N_TXTOFF(filhdr); 1178615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1179615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t)); 1180615Sbill mget(&size, sizeof(size), &text); 1181615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1182615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t), 1183615Sbill size - sizeof(off_t)); 1184615Sbill curstr = (char *)malloc(size); 1185615Sbill if (curstr == NULL) 1186615Sbill error(1, "out of space reading string table (pass 2)"); 1187615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &text); 1188615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1189615Sbill filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms); 1190615Sbill while (text.size > 0) { 1191615Sbill symno++; 1192615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 1193615Sbill if (cursym.n_un.n_strx) { 1194615Sbill if (cursym.n_un.n_strx<sizeof(size) || 1195615Sbill cursym.n_un.n_strx>=size) 1196615Sbill error(1, "bad string table index (pass 2)"); 1197615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 1198615Sbill } 1199615Sbill /* inline expansion of symreloc() */ 1200615Sbill switch (cursym.n_type & 017) { 1201615Sbill 1202615Sbill case N_TEXT: 1203615Sbill case N_EXT+N_TEXT: 1204615Sbill cursym.n_value += ctrel; 1205615Sbill break; 1206615Sbill case N_DATA: 1207615Sbill case N_EXT+N_DATA: 1208615Sbill cursym.n_value += cdrel; 1209615Sbill break; 1210615Sbill case N_BSS: 1211615Sbill case N_EXT+N_BSS: 1212615Sbill cursym.n_value += cbrel; 1213615Sbill break; 1214615Sbill case N_EXT+N_UNDF: 1215615Sbill break; 1216615Sbill default: 1217615Sbill if (cursym.n_type&N_EXT) 1218615Sbill cursym.n_type = N_EXT+N_ABS; 1219615Sbill } 1220615Sbill /* end inline expansion of symreloc() */ 1221615Sbill type = cursym.n_type; 1222898Sbill if (yflag && cursym.n_un.n_name) 1223898Sbill for (i = 0; i < yflag; i++) 1224898Sbill /* fast check for 2d character! */ 1225898Sbill if (ytab[i][1] == cursym.n_un.n_name[1] && 1226898Sbill !strcmp(ytab[i], cursym.n_un.n_name)) { 1227898Sbill tracesym(); 1228898Sbill break; 1229898Sbill } 1230615Sbill if ((type&N_EXT) == 0) { 1231615Sbill if (!sflag&&!xflag&& 1232615Sbill (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB)) 1233615Sbill symwrite(&cursym, sout); 1234615Sbill continue; 1235615Sbill } 1236615Sbill if (funding) 1237615Sbill continue; 1238615Sbill if ((sp = *lookup()) == 0) 1239615Sbill error(1, "internal error: symbol not found"); 1240615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 1241615Sbill if (clocseg->lo_used == NSYMPR) { 1242615Sbill if (++clocseg == &locseg[NSEG]) 1243615Sbill error(1, "local symbol overflow"); 1244615Sbill clocseg->lo_used = 0; 1245615Sbill } 1246615Sbill if (clocseg->lo_first == 0) { 1247615Sbill clocseg->lo_first = (struct local *) 1248615Sbill malloc(NSYMPR * sizeof (struct local)); 1249615Sbill if (clocseg->lo_first == 0) 1250615Sbill error(1, "out of memory (clocseg)"); 1251615Sbill } 1252615Sbill lp = &clocseg->lo_first[clocseg->lo_used++]; 1253615Sbill lp->l_index = symno; 1254615Sbill lp->l_symbol = sp; 1255615Sbill lp->l_link = lochash[symno % LHSIZ]; 1256615Sbill lochash[symno % LHSIZ] = lp; 1257615Sbill continue; 1258615Sbill } 1259615Sbill if (cursym.n_type & N_STAB) 1260615Sbill continue; 1261615Sbill if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) { 1262615Sbill printf("%s: ", cursym.n_un.n_name); 1263615Sbill error(0, "multiply defined"); 1264615Sbill } 1265615Sbill } 1266615Sbill if (funding) 1267615Sbill return; 1268615Sbill dseek(&text, loc, filhdr.a_text); 1269615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize); 1270650Sbill load2td(ctrel, torigin - textbase, tout, trout); 1271615Sbill dseek(&text, loc+filhdr.a_text, filhdr.a_data); 1272615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, 1273615Sbill filhdr.a_drsize); 1274650Sbill load2td(cdrel, dorigin - database, dout, drout); 1275615Sbill while (filhdr.a_data & (sizeof(long)-1)) { 1276615Sbill bputc(0, dout); 1277615Sbill filhdr.a_data++; 1278615Sbill } 1279615Sbill torigin += filhdr.a_text; 12801752Sbill dorigin += round(filhdr.a_data, sizeof (long)); 12811752Sbill borigin += round(filhdr.a_bss, sizeof (long)); 1282615Sbill free(curstr); 1283615Sbill } 1284615Sbill 1285898Sbill struct tynames { 1286898Sbill int ty_value; 1287898Sbill char *ty_name; 1288898Sbill } tynames[] = { 1289898Sbill N_UNDF, "undefined", 1290898Sbill N_ABS, "absolute", 1291898Sbill N_TEXT, "text", 1292898Sbill N_DATA, "data", 1293898Sbill N_BSS, "bss", 1294898Sbill N_COMM, "common", 1295898Sbill 0, 0, 1296898Sbill }; 1297898Sbill 1298898Sbill tracesym() 1299898Sbill { 1300898Sbill register struct tynames *tp; 1301898Sbill 1302898Sbill if (cursym.n_type & N_STAB) 1303898Sbill return; 1304898Sbill printf("%s", filname); 1305898Sbill if (archdr.ar_name[0]) 1306898Sbill printf("(%s)", archdr.ar_name); 1307898Sbill printf(": "); 1308898Sbill if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) { 1309898Sbill printf("definition of common %s size %d\n", 1310898Sbill cursym.n_un.n_name, cursym.n_value); 1311898Sbill return; 1312898Sbill } 1313898Sbill for (tp = tynames; tp->ty_name; tp++) 1314898Sbill if (tp->ty_value == (cursym.n_type&N_TYPE)) 1315898Sbill break; 1316898Sbill printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to"); 1317898Sbill if (cursym.n_type&N_EXT) 1318898Sbill printf(" external"); 1319898Sbill if (tp->ty_name) 1320898Sbill printf(" %s", tp->ty_name); 1321898Sbill printf(" %s\n", cursym.n_un.n_name); 1322898Sbill } 1323898Sbill 132429845Ssam #if !defined(tahoe) 132529845Ssam /* for machines which allow arbitrarily aligned word and longword accesses */ 132646419Sbostic #define getword(cp) (*(short *)(cp)) 132729845Ssam #define getl(cp) (*(long *)(cp)) 132829845Ssam #define putw(cp, w) (*(short *)(cp) = (w)) 132929845Ssam #define putl(cp, l) (*(long *)(cp) = (l)) 133029845Ssam #else 133129845Ssam short 133246419Sbostic getword(cp) 133329845Ssam char *cp; 133429845Ssam { 133529845Ssam union { 133629845Ssam short w; 133729845Ssam char c[2]; 133829845Ssam } w; 133929845Ssam 134029845Ssam w.c[0] = *cp++; 134129845Ssam w.c[1] = *cp++; 134229845Ssam return (w.w); 134329845Ssam } 134429845Ssam 134529845Ssam getl(cp) 134629845Ssam char *cp; 134729845Ssam { 134829845Ssam union { 134929845Ssam long l; 135029845Ssam char c[4]; 135129845Ssam } l; 135229845Ssam 135329845Ssam l.c[0] = *cp++; 135429845Ssam l.c[1] = *cp++; 135529845Ssam l.c[2] = *cp++; 135629845Ssam l.c[3] = *cp++; 135729845Ssam return (l.l); 135829845Ssam } 135929845Ssam 136029845Ssam putw(cp, v) 136129845Ssam char *cp; 136229845Ssam short v; 136329845Ssam { 136429845Ssam union { 136529845Ssam short w; 136629845Ssam char c[2]; 136729845Ssam } w; 136829845Ssam 136929845Ssam w.w = v; 137029845Ssam *cp++ = w.c[0]; 137129845Ssam *cp++ = w.c[1]; 137229845Ssam } 137329845Ssam 137429845Ssam putl(cp, v) 137529845Ssam char *cp; 137629845Ssam long v; 137729845Ssam { 137829845Ssam union { 137929845Ssam long l; 138029845Ssam char c[4]; 138129845Ssam } l; 138229845Ssam 138329845Ssam l.l = v; 138429845Ssam *cp++ = l.c[0]; 138529845Ssam *cp++ = l.c[1]; 138629845Ssam *cp++ = l.c[2]; 138729845Ssam *cp++ = l.c[3]; 138829845Ssam } 138929845Ssam #endif 139029845Ssam 1391650Sbill /* 1392650Sbill * This routine relocates the single text or data segment argument. 1393650Sbill * Offsets from external symbols are resolved by adding the value 1394650Sbill * of the external symbols. Non-external reference are updated to account 1395650Sbill * for the relative motion of the segments (ctrel, cdrel, ...). If 1396650Sbill * a relocation was pc-relative, then we update it to reflect the 1397650Sbill * change in the positioning of the segments by adding the displacement 1398650Sbill * of the referenced segment and subtracting the displacement of the 1399650Sbill * current segment (creloc). 1400650Sbill * 1401650Sbill * If we are saving the relocation information, then we increase 1402650Sbill * each relocation datum address by our base position in the new segment. 1403650Sbill */ 1404650Sbill load2td(creloc, position, b1, b2) 140530647Slepreau long creloc, position; 1406615Sbill struct biobuf *b1, *b2; 1407615Sbill { 1408615Sbill register struct nlist *sp; 1409615Sbill register struct local *lp; 1410615Sbill long tw; 1411615Sbill register struct relocation_info *rp, *rpend; 1412615Sbill struct relocation_info *relp; 1413615Sbill char *codep; 1414615Sbill register char *cp; 1415615Sbill int relsz, codesz; 1416615Sbill 1417615Sbill relsz = reloc.size; 1418615Sbill relp = (struct relocation_info *)malloc(relsz); 1419615Sbill codesz = text.size; 1420615Sbill codep = (char *)malloc(codesz); 1421615Sbill if (relp == 0 || codep == 0) 1422615Sbill error(1, "out of memory (load2td)"); 1423615Sbill mget((char *)relp, relsz, &reloc); 1424615Sbill rpend = &relp[relsz / sizeof (struct relocation_info)]; 1425615Sbill mget(codep, codesz, &text); 1426615Sbill for (rp = relp; rp < rpend; rp++) { 1427615Sbill cp = codep + rp->r_address; 1428650Sbill /* 1429650Sbill * Pick up previous value at location to be relocated. 1430650Sbill */ 1431615Sbill switch (rp->r_length) { 1432615Sbill 1433615Sbill case 0: /* byte */ 1434615Sbill tw = *cp; 1435615Sbill break; 1436615Sbill 1437615Sbill case 1: /* word */ 143846419Sbostic tw = getword(cp); 1439615Sbill break; 1440615Sbill 1441615Sbill case 2: /* long */ 144229845Ssam tw = getl(cp); 1443615Sbill break; 1444615Sbill 1445615Sbill default: 1446615Sbill error(1, "load2td botch: bad length"); 1447615Sbill } 1448650Sbill /* 1449650Sbill * If relative to an external which is defined, 1450650Sbill * resolve to a simpler kind of reference in the 1451650Sbill * result file. If the external is undefined, just 1452650Sbill * convert the symbol number to the number of the 1453650Sbill * symbol in the result file and leave it undefined. 1454650Sbill */ 1455615Sbill if (rp->r_extern) { 1456650Sbill /* 1457650Sbill * Search the hash table which maps local 1458650Sbill * symbol numbers to symbol tables entries 1459650Sbill * in the new a.out file. 1460650Sbill */ 1461615Sbill lp = lochash[rp->r_symbolnum % LHSIZ]; 1462615Sbill while (lp->l_index != rp->r_symbolnum) { 1463615Sbill lp = lp->l_link; 1464615Sbill if (lp == 0) 1465615Sbill error(1, "local symbol botch"); 1466615Sbill } 1467615Sbill sp = lp->l_symbol; 1468615Sbill if (sp->n_type == N_EXT+N_UNDF) 1469615Sbill rp->r_symbolnum = nsym+symx(sp); 1470615Sbill else { 1471615Sbill rp->r_symbolnum = sp->n_type & N_TYPE; 1472615Sbill tw += sp->n_value; 1473615Sbill rp->r_extern = 0; 1474615Sbill } 1475615Sbill } else switch (rp->r_symbolnum & N_TYPE) { 1476650Sbill /* 1477650Sbill * Relocation is relative to the loaded position 1478650Sbill * of another segment. Update by the change in position 1479650Sbill * of that segment. 1480650Sbill */ 1481615Sbill case N_TEXT: 1482615Sbill tw += ctrel; 1483615Sbill break; 1484615Sbill case N_DATA: 1485615Sbill tw += cdrel; 1486615Sbill break; 1487615Sbill case N_BSS: 1488615Sbill tw += cbrel; 1489615Sbill break; 1490615Sbill case N_ABS: 1491615Sbill break; 1492615Sbill default: 1493615Sbill error(1, "relocation format botch (symbol type))"); 1494615Sbill } 1495650Sbill /* 1496650Sbill * Relocation is pc relative, so decrease the relocation 1497650Sbill * by the amount the current segment is displaced. 1498650Sbill * (E.g if we are a relative reference to a text location 1499650Sbill * from data space, we added the increase in the text address 1500650Sbill * above, and subtract the increase in our (data) address 1501650Sbill * here, leaving the net change the relative change in the 1502650Sbill * positioning of our text and data segments.) 1503650Sbill */ 1504615Sbill if (rp->r_pcrel) 1505615Sbill tw -= creloc; 1506650Sbill /* 1507650Sbill * Put the value back in the segment, 1508650Sbill * while checking for overflow. 1509650Sbill */ 1510615Sbill switch (rp->r_length) { 1511615Sbill 1512615Sbill case 0: /* byte */ 1513615Sbill if (tw < -128 || tw > 127) 1514615Sbill error(0, "byte displacement overflow"); 1515615Sbill *cp = tw; 1516615Sbill break; 1517615Sbill case 1: /* word */ 1518615Sbill if (tw < -32768 || tw > 32767) 1519615Sbill error(0, "word displacement overflow"); 152029845Ssam putw(cp, tw); 1521615Sbill break; 1522615Sbill case 2: /* long */ 152329845Ssam putl(cp, tw); 1524615Sbill break; 1525615Sbill } 1526650Sbill /* 1527650Sbill * If we are saving relocation information, 1528650Sbill * we must convert the address in the segment from 1529650Sbill * the old .o file into an address in the segment in 1530650Sbill * the new a.out, by adding the position of our 1531650Sbill * segment in the new larger segment. 1532650Sbill */ 1533615Sbill if (rflag) 1534650Sbill rp->r_address += position; 1535615Sbill } 1536615Sbill bwrite(codep, codesz, b1); 1537615Sbill if (rflag) 1538615Sbill bwrite(relp, relsz, b2); 153925483Slepreau free((char *)relp); 154025483Slepreau free(codep); 1541615Sbill } 1542615Sbill 1543615Sbill finishout() 1544615Sbill { 1545615Sbill register int i; 1546615Sbill int nsymt; 1547615Sbill 1548615Sbill if (sflag==0) { 1549615Sbill nsymt = symx(nextsym); 1550615Sbill for (i = 0; i < nsymt; i++) 1551615Sbill symwrite(xsym(i), sout); 1552615Sbill bwrite(&offset, sizeof offset, sout); 1553615Sbill } 1554615Sbill if (!ofilfnd) { 155544768Sbostic unlink("a.out"); 155644768Sbostic if (link("l.out", "a.out") < 0) 1557898Sbill error(1, "cannot move l.out to a.out"); 155844768Sbostic ofilename = "a.out"; 1559615Sbill } 1560615Sbill delarg = errlev; 1561615Sbill delexit(); 1562615Sbill } 1563615Sbill 1564615Sbill mkfsym(s) 1565615Sbill char *s; 1566615Sbill { 1567615Sbill 1568615Sbill if (sflag || xflag) 1569615Sbill return; 1570615Sbill cursym.n_un.n_name = s; 157130836Sbostic cursym.n_type = N_EXT | N_FN; 1572615Sbill cursym.n_value = torigin; 1573615Sbill symwrite(&cursym, sout); 1574615Sbill } 1575615Sbill 1576615Sbill getarhdr() 1577615Sbill { 1578615Sbill register char *cp; 1579615Sbill 1580615Sbill mget((char *)&archdr, sizeof archdr, &text); 1581615Sbill for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];) 1582615Sbill if (*cp++ == ' ') { 1583615Sbill cp[-1] = 0; 1584615Sbill return; 1585615Sbill } 1586615Sbill } 1587615Sbill 1588615Sbill mget(loc, n, sp) 1589615Sbill register STREAM *sp; 1590615Sbill register char *loc; 1591615Sbill { 1592615Sbill register char *p; 1593615Sbill register int take; 1594615Sbill 1595615Sbill top: 1596615Sbill if (n == 0) 1597615Sbill return; 1598615Sbill if (sp->size && sp->nibuf) { 1599615Sbill p = sp->ptr; 1600615Sbill take = sp->size; 1601615Sbill if (take > sp->nibuf) 1602615Sbill take = sp->nibuf; 1603615Sbill if (take > n) 1604615Sbill take = n; 1605615Sbill n -= take; 1606615Sbill sp->size -= take; 1607615Sbill sp->nibuf -= take; 1608615Sbill sp->pos += take; 1609615Sbill do 1610615Sbill *loc++ = *p++; 1611615Sbill while (--take > 0); 1612615Sbill sp->ptr = p; 1613615Sbill goto top; 1614615Sbill } 161516068Sralph if (n > p_blksize) { 161616068Sralph take = n - n % p_blksize; 161716068Sralph lseek(infil, (sp->bno+1)<<p_blkshift, 0); 1618615Sbill if (take > sp->size || read(infil, loc, take) != take) 1619615Sbill error(1, "premature EOF"); 1620615Sbill loc += take; 1621615Sbill n -= take; 1622615Sbill sp->size -= take; 1623615Sbill sp->pos += take; 162416068Sralph dseek(sp, (sp->bno+1+(take>>p_blkshift))<<p_blkshift, -1); 1625615Sbill goto top; 1626615Sbill } 1627615Sbill *loc++ = get(sp); 1628615Sbill --n; 1629615Sbill goto top; 1630615Sbill } 1631615Sbill 1632615Sbill symwrite(sp, bp) 1633615Sbill struct nlist *sp; 1634615Sbill struct biobuf *bp; 1635615Sbill { 1636615Sbill register int len; 1637615Sbill register char *str; 1638615Sbill 1639615Sbill str = sp->n_un.n_name; 1640615Sbill if (str) { 1641615Sbill sp->n_un.n_strx = offset; 1642615Sbill len = strlen(str) + 1; 1643615Sbill bwrite(str, len, strout); 1644615Sbill offset += len; 1645615Sbill } 1646615Sbill bwrite(sp, sizeof (*sp), bp); 1647615Sbill sp->n_un.n_name = str; 1648615Sbill } 1649615Sbill 1650615Sbill dseek(sp, loc, s) 1651615Sbill register STREAM *sp; 1652615Sbill long loc, s; 1653615Sbill { 1654615Sbill register PAGE *p; 1655615Sbill register b, o; 1656615Sbill int n; 1657615Sbill 165816068Sralph b = loc>>p_blkshift; 165916068Sralph o = loc&p_blkmask; 1660615Sbill if (o&01) 1661615Sbill error(1, "loader error; odd offset"); 1662615Sbill --sp->pno->nuser; 1663615Sbill if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b) 1664615Sbill if (p->nuser==0 || (p = &page[0])->nuser==0) { 1665615Sbill if (page[0].nuser==0 && page[1].nuser==0) 1666615Sbill if (page[0].bno < page[1].bno) 1667615Sbill p = &page[0]; 1668615Sbill p->bno = b; 166916068Sralph lseek(infil, loc & ~(long)p_blkmask, 0); 167016068Sralph if ((n = read(infil, p->buff, p_blksize)) < 0) 1671615Sbill n = 0; 1672615Sbill p->nibuf = n; 167316068Sralph } else 167416068Sralph error(1, "botch: no pages"); 1675615Sbill ++p->nuser; 1676615Sbill sp->bno = b; 1677615Sbill sp->pno = p; 1678615Sbill if (s != -1) {sp->size = s; sp->pos = 0;} 1679615Sbill sp->ptr = (char *)(p->buff + o); 1680615Sbill if ((sp->nibuf = p->nibuf-o) <= 0) 1681615Sbill sp->size = 0; 1682615Sbill } 1683615Sbill 1684615Sbill char 1685615Sbill get(asp) 1686615Sbill STREAM *asp; 1687615Sbill { 1688615Sbill register STREAM *sp; 1689615Sbill 1690615Sbill sp = asp; 1691615Sbill if ((sp->nibuf -= sizeof(char)) < 0) { 169216068Sralph dseek(sp, ((long)(sp->bno+1)<<p_blkshift), (long)-1); 1693615Sbill sp->nibuf -= sizeof(char); 1694615Sbill } 1695615Sbill if ((sp->size -= sizeof(char)) <= 0) { 1696615Sbill if (sp->size < 0) 1697615Sbill error(1, "premature EOF"); 1698615Sbill ++fpage.nuser; 1699615Sbill --sp->pno->nuser; 1700615Sbill sp->pno = (PAGE *) &fpage; 1701615Sbill } 1702615Sbill sp->pos += sizeof(char); 1703615Sbill return(*sp->ptr++); 1704615Sbill } 1705615Sbill 1706615Sbill getfile(acp) 1707615Sbill char *acp; 1708615Sbill { 1709615Sbill register int c; 1710615Sbill char arcmag[SARMAG+1]; 1711615Sbill struct stat stb; 1712615Sbill 1713615Sbill archdr.ar_name[0] = '\0'; 171417133Ssam filname = acp; 171517133Ssam if (filname[0] == '-' && filname[1] == 'l') 171617133Ssam infil = libopen(filname + 2, O_RDONLY); 171717133Ssam else 171844768Sbostic infil = open(filname, O_RDONLY); 171917133Ssam if (infil < 0) 1720615Sbill error(1, "cannot open"); 172116068Sralph fstat(infil, &stb); 1722615Sbill page[0].bno = page[1].bno = -1; 1723615Sbill page[0].nuser = page[1].nuser = 0; 172416068Sralph c = stb.st_blksize; 172516068Sralph if (c == 0 || (c & (c - 1)) != 0) { 172616068Sralph /* use default size if not a power of two */ 172716068Sralph c = BLKSIZE; 172816068Sralph } 172916068Sralph if (p_blksize != c) { 173016068Sralph p_blksize = c; 173116068Sralph p_blkmask = c - 1; 173216068Sralph for (p_blkshift = 0; c > 1 ; p_blkshift++) 173316068Sralph c >>= 1; 173416068Sralph if (page[0].buff != NULL) 173516068Sralph free(page[0].buff); 173616068Sralph page[0].buff = (char *)malloc(p_blksize); 173716068Sralph if (page[0].buff == NULL) 173816068Sralph error(1, "ran out of memory (getfile)"); 173916068Sralph if (page[1].buff != NULL) 174016068Sralph free(page[1].buff); 174116068Sralph page[1].buff = (char *)malloc(p_blksize); 174216068Sralph if (page[1].buff == NULL) 174316068Sralph error(1, "ran out of memory (getfile)"); 174416068Sralph } 1745615Sbill text.pno = reloc.pno = (PAGE *) &fpage; 1746615Sbill fpage.nuser = 2; 1747615Sbill dseek(&text, 0L, SARMAG); 1748615Sbill if (text.size <= 0) 1749615Sbill error(1, "premature EOF"); 1750615Sbill mget((char *)arcmag, SARMAG, &text); 1751615Sbill arcmag[SARMAG] = 0; 1752615Sbill if (strcmp(arcmag, ARMAG)) 1753615Sbill return (0); 1754615Sbill dseek(&text, SARMAG, sizeof archdr); 175517133Ssam if (text.size <= 0) 1756615Sbill return (1); 1757615Sbill getarhdr(); 175830828Sbostic if (strncmp(archdr.ar_name, RANLIBMAG, sizeof(archdr.ar_name)) != 0) 1759615Sbill return (1); 1760615Sbill return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2); 1761615Sbill } 1762615Sbill 176317133Ssam /* 176417133Ssam * Search for a library with given name 176517133Ssam * using the directory search array. 176617133Ssam */ 176717133Ssam libopen(name, oflags) 176817133Ssam char *name; 176917133Ssam int oflags; 177017133Ssam { 177117133Ssam register char *p, *cp; 177217133Ssam register int i; 177317133Ssam static char buf[MAXPATHLEN+1]; 177417133Ssam int fd = -1; 177517133Ssam 177617133Ssam if (*name == '\0') /* backwards compat */ 177717133Ssam name = "a"; 177817133Ssam for (i = 0; i < ndir && fd == -1; i++) { 177917133Ssam p = buf; 178017133Ssam for (cp = dirs[i]; *cp; *p++ = *cp++) 178117133Ssam ; 178217133Ssam *p++ = '/'; 178317133Ssam for (cp = "lib"; *cp; *p++ = *cp++) 178417133Ssam ; 178517133Ssam for (cp = name; *cp; *p++ = *cp++) 178617133Ssam ; 178717133Ssam cp = ".a"; 178817133Ssam while (*p++ = *cp++) 178917133Ssam ; 179017133Ssam fd = open(buf, oflags); 179117133Ssam } 179217133Ssam if (fd != -1) 179317133Ssam filname = buf; 179417133Ssam return (fd); 179517133Ssam } 179617133Ssam 1797615Sbill struct nlist ** 1798615Sbill lookup() 1799615Sbill { 1800615Sbill register int sh; 1801615Sbill register struct nlist **hp; 1802615Sbill register char *cp, *cp1; 1803615Sbill register struct symseg *gp; 1804615Sbill register int i; 1805615Sbill 1806615Sbill sh = 0; 1807615Sbill for (cp = cursym.n_un.n_name; *cp;) 1808615Sbill sh = (sh<<1) + *cp++; 1809615Sbill sh = (sh & 0x7fffffff) % HSIZE; 1810615Sbill for (gp = symseg; gp < &symseg[NSEG]; gp++) { 1811615Sbill if (gp->sy_first == 0) { 1812615Sbill gp->sy_first = (struct nlist *) 1813615Sbill calloc(NSYM, sizeof (struct nlist)); 1814615Sbill gp->sy_hfirst = (struct nlist **) 1815615Sbill calloc(HSIZE, sizeof (struct nlist *)); 1816615Sbill if (gp->sy_first == 0 || gp->sy_hfirst == 0) 1817615Sbill error(1, "ran out of space for symbol table"); 1818615Sbill gp->sy_last = gp->sy_first + NSYM; 1819615Sbill gp->sy_hlast = gp->sy_hfirst + HSIZE; 1820615Sbill } 1821615Sbill if (gp > csymseg) 1822615Sbill csymseg = gp; 1823615Sbill hp = gp->sy_hfirst + sh; 1824615Sbill i = 1; 1825615Sbill do { 1826615Sbill if (*hp == 0) { 1827615Sbill if (gp->sy_used == NSYM) 1828615Sbill break; 1829615Sbill return (hp); 1830615Sbill } 1831615Sbill cp1 = (*hp)->n_un.n_name; 1832615Sbill for (cp = cursym.n_un.n_name; *cp == *cp1++;) 1833615Sbill if (*cp++ == 0) 1834615Sbill return (hp); 1835615Sbill hp += i; 1836615Sbill i += 2; 1837615Sbill if (hp >= gp->sy_hlast) 1838615Sbill hp -= HSIZE; 1839615Sbill } while (i < HSIZE); 1840615Sbill if (i > HSIZE) 1841615Sbill error(1, "hash table botch"); 1842615Sbill } 1843615Sbill error(1, "symbol table overflow"); 1844615Sbill /*NOTREACHED*/ 1845615Sbill } 1846615Sbill 1847615Sbill symfree(saved) 1848615Sbill struct nlist *saved; 1849615Sbill { 1850615Sbill register struct symseg *gp; 1851615Sbill register struct nlist *sp; 1852615Sbill 1853615Sbill for (gp = csymseg; gp >= symseg; gp--, csymseg--) { 1854615Sbill sp = gp->sy_first + gp->sy_used; 1855615Sbill if (sp == saved) { 1856615Sbill nextsym = sp; 1857615Sbill return; 1858615Sbill } 1859615Sbill for (sp--; sp >= gp->sy_first; sp--) { 1860615Sbill gp->sy_hfirst[sp->n_hash] = 0; 1861615Sbill gp->sy_used--; 1862615Sbill if (sp == saved) { 1863615Sbill nextsym = sp; 1864615Sbill return; 1865615Sbill } 1866615Sbill } 1867615Sbill } 1868615Sbill if (saved == 0) 1869615Sbill return; 1870615Sbill error(1, "symfree botch"); 1871615Sbill } 1872615Sbill 1873615Sbill struct nlist ** 1874615Sbill slookup(s) 1875615Sbill char *s; 1876615Sbill { 1877615Sbill 1878615Sbill cursym.n_un.n_name = s; 1879615Sbill cursym.n_type = N_EXT+N_UNDF; 1880615Sbill cursym.n_value = 0; 1881615Sbill return (lookup()); 1882615Sbill } 1883615Sbill 1884615Sbill enter(hp) 1885615Sbill register struct nlist **hp; 1886615Sbill { 1887615Sbill register struct nlist *sp; 1888615Sbill 1889615Sbill if (*hp==0) { 1890615Sbill if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast) 1891615Sbill error(1, "enter botch"); 1892615Sbill *hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used; 1893615Sbill csymseg->sy_used++; 1894615Sbill sp->n_un.n_name = cursym.n_un.n_name; 1895615Sbill sp->n_type = cursym.n_type; 1896615Sbill sp->n_hash = hp - csymseg->sy_hfirst; 1897615Sbill sp->n_value = cursym.n_value; 1898615Sbill nextsym = lastsym + 1; 1899615Sbill return(1); 1900615Sbill } else { 1901615Sbill lastsym = *hp; 1902615Sbill return(0); 1903615Sbill } 1904615Sbill } 1905615Sbill 1906615Sbill symx(sp) 1907615Sbill struct nlist *sp; 1908615Sbill { 1909615Sbill register struct symseg *gp; 1910615Sbill 1911615Sbill if (sp == 0) 1912615Sbill return (0); 1913615Sbill for (gp = csymseg; gp >= symseg; gp--) 1914615Sbill /* <= is sloppy so nextsym will always work */ 1915615Sbill if (sp >= gp->sy_first && sp <= gp->sy_last) 1916615Sbill return ((gp - symseg) * NSYM + sp - gp->sy_first); 1917615Sbill error(1, "symx botch"); 1918615Sbill /*NOTREACHED*/ 1919615Sbill } 1920615Sbill 1921615Sbill symreloc() 1922615Sbill { 1923615Sbill if(funding) return; 1924615Sbill switch (cursym.n_type & 017) { 1925615Sbill 1926615Sbill case N_TEXT: 1927615Sbill case N_EXT+N_TEXT: 1928615Sbill cursym.n_value += ctrel; 1929615Sbill return; 1930615Sbill 1931615Sbill case N_DATA: 1932615Sbill case N_EXT+N_DATA: 1933615Sbill cursym.n_value += cdrel; 1934615Sbill return; 1935615Sbill 1936615Sbill case N_BSS: 1937615Sbill case N_EXT+N_BSS: 1938615Sbill cursym.n_value += cbrel; 1939615Sbill return; 1940615Sbill 1941615Sbill case N_EXT+N_UNDF: 1942615Sbill return; 1943615Sbill 1944615Sbill default: 1945615Sbill if (cursym.n_type&N_EXT) 1946615Sbill cursym.n_type = N_EXT+N_ABS; 1947615Sbill return; 1948615Sbill } 1949615Sbill } 1950615Sbill 1951615Sbill error(n, s) 1952615Sbill char *s; 1953615Sbill { 1954898Sbill 1955615Sbill if (errlev==0) 1956615Sbill printf("ld:"); 1957615Sbill if (filname) { 1958615Sbill printf("%s", filname); 1959615Sbill if (n != -1 && archdr.ar_name[0]) 1960615Sbill printf("(%s)", archdr.ar_name); 1961615Sbill printf(": "); 1962615Sbill } 1963615Sbill printf("%s\n", s); 1964615Sbill if (n == -1) 1965615Sbill return; 1966615Sbill if (n) 1967615Sbill delexit(); 1968615Sbill errlev = 2; 1969615Sbill } 1970615Sbill 1971615Sbill readhdr(loc) 1972615Sbill off_t loc; 1973615Sbill { 1974615Sbill 1975615Sbill dseek(&text, loc, (long)sizeof(filhdr)); 1976615Sbill mget((short *)&filhdr, sizeof(filhdr), &text); 1977615Sbill if (N_BADMAG(filhdr)) { 1978615Sbill if (filhdr.a_magic == OARMAG) 1979615Sbill error(1, "old archive"); 1980615Sbill error(1, "bad magic number"); 1981615Sbill } 1982615Sbill if (filhdr.a_text&01 || filhdr.a_data&01) 1983615Sbill error(1, "text/data size odd"); 1984615Sbill if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) { 198512671Ssam cdrel = -round(filhdr.a_text, pagesize); 1986615Sbill cbrel = cdrel - filhdr.a_data; 1987615Sbill } else if (filhdr.a_magic == OMAGIC) { 1988615Sbill cdrel = -filhdr.a_text; 1989615Sbill cbrel = cdrel - filhdr.a_data; 1990615Sbill } else 1991615Sbill error(1, "bad format"); 1992615Sbill } 1993615Sbill 1994615Sbill round(v, r) 1995615Sbill int v; 1996615Sbill u_long r; 1997615Sbill { 1998615Sbill 1999615Sbill r--; 2000615Sbill v += r; 2001615Sbill v &= ~(long)r; 2002615Sbill return(v); 2003615Sbill } 2004615Sbill 2005615Sbill #define NSAVETAB 8192 2006615Sbill char *savetab; 2007615Sbill int saveleft; 2008615Sbill 2009615Sbill char * 2010615Sbill savestr(cp) 2011615Sbill register char *cp; 2012615Sbill { 2013615Sbill register int len; 2014615Sbill 2015615Sbill len = strlen(cp) + 1; 2016615Sbill if (len > saveleft) { 2017615Sbill saveleft = NSAVETAB; 2018615Sbill if (len > saveleft) 2019615Sbill saveleft = len; 202017133Ssam savetab = malloc(saveleft); 2021615Sbill if (savetab == 0) 2022615Sbill error(1, "ran out of memory (savestr)"); 2023615Sbill } 2024615Sbill strncpy(savetab, cp, len); 2025615Sbill cp = savetab; 2026615Sbill savetab += len; 2027615Sbill saveleft -= len; 2028615Sbill return (cp); 2029615Sbill } 2030615Sbill 203116068Sralph bopen(bp, off, bufsize) 203216068Sralph register struct biobuf *bp; 2033615Sbill { 2034615Sbill 203517133Ssam bp->b_ptr = bp->b_buf = malloc(bufsize); 203616068Sralph if (bp->b_ptr == (char *)0) 203716068Sralph error(1, "ran out of memory (bopen)"); 203816068Sralph bp->b_bufsize = bufsize; 203916068Sralph bp->b_nleft = bufsize - (off % bufsize); 2040615Sbill bp->b_off = off; 2041615Sbill bp->b_link = biobufs; 2042615Sbill biobufs = bp; 2043615Sbill } 2044615Sbill 2045615Sbill int bwrerror; 2046615Sbill 2047615Sbill bwrite(p, cnt, bp) 2048615Sbill register char *p; 2049615Sbill register int cnt; 2050615Sbill register struct biobuf *bp; 2051615Sbill { 2052615Sbill register int put; 2053615Sbill register char *to; 2054615Sbill 2055615Sbill top: 2056615Sbill if (cnt == 0) 2057615Sbill return; 2058615Sbill if (bp->b_nleft) { 2059615Sbill put = bp->b_nleft; 2060615Sbill if (put > cnt) 2061615Sbill put = cnt; 2062615Sbill bp->b_nleft -= put; 2063615Sbill to = bp->b_ptr; 206425419Sbloom bcopy(p, to, put); 2065615Sbill bp->b_ptr += put; 2066615Sbill p += put; 2067615Sbill cnt -= put; 2068615Sbill goto top; 2069615Sbill } 207016068Sralph if (cnt >= bp->b_bufsize) { 2071615Sbill if (bp->b_ptr != bp->b_buf) 2072615Sbill bflush1(bp); 207316068Sralph put = cnt - cnt % bp->b_bufsize; 2074615Sbill if (boffset != bp->b_off) 2075615Sbill lseek(biofd, bp->b_off, 0); 2076615Sbill if (write(biofd, p, put) != put) { 2077615Sbill bwrerror = 1; 2078615Sbill error(1, "output write error"); 2079615Sbill } 2080615Sbill bp->b_off += put; 2081615Sbill boffset = bp->b_off; 2082615Sbill p += put; 2083615Sbill cnt -= put; 2084615Sbill goto top; 2085615Sbill } 2086615Sbill bflush1(bp); 2087615Sbill goto top; 2088615Sbill } 2089615Sbill 2090615Sbill bflush() 2091615Sbill { 2092615Sbill register struct biobuf *bp; 2093615Sbill 2094615Sbill if (bwrerror) 2095615Sbill return; 2096615Sbill for (bp = biobufs; bp; bp = bp->b_link) 2097615Sbill bflush1(bp); 2098615Sbill } 2099615Sbill 2100615Sbill bflush1(bp) 2101615Sbill register struct biobuf *bp; 2102615Sbill { 2103615Sbill register int cnt = bp->b_ptr - bp->b_buf; 2104615Sbill 2105615Sbill if (cnt == 0) 2106615Sbill return; 2107615Sbill if (boffset != bp->b_off) 2108615Sbill lseek(biofd, bp->b_off, 0); 2109615Sbill if (write(biofd, bp->b_buf, cnt) != cnt) { 2110615Sbill bwrerror = 1; 2111615Sbill error(1, "output write error"); 2112615Sbill } 2113615Sbill bp->b_off += cnt; 2114615Sbill boffset = bp->b_off; 2115615Sbill bp->b_ptr = bp->b_buf; 211616068Sralph bp->b_nleft = bp->b_bufsize; 2117615Sbill } 2118615Sbill 2119615Sbill bflushc(bp, c) 2120615Sbill register struct biobuf *bp; 2121615Sbill { 2122615Sbill 2123615Sbill bflush1(bp); 2124615Sbill bputc(c, bp); 2125615Sbill } 212616068Sralph 212716068Sralph bseek(bp, off) 212816068Sralph register struct biobuf *bp; 212916068Sralph register off_t off; 213016068Sralph { 213116068Sralph bflush1(bp); 213216068Sralph 213316068Sralph bp->b_nleft = bp->b_bufsize - (off % bp->b_bufsize); 213416068Sralph bp->b_off = off; 213516068Sralph } 2136