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*46419Sbostic static char sccsid[] = "@(#)ld.c 5.17 (Berkeley) 02/14/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> 2342415Sbostic #include <sys/file.h> 2442415Sbostic #include <sys/signal.h> 25650Sbill #include <ar.h> 26650Sbill #include <a.out.h> 27615Sbill #include <ranlib.h> 2842415Sbostic #include <stdio.h> 2942415Sbostic #include <ctype.h> 3042415Sbostic #include <string.h> 3137031Sbostic #include "pathnames.h" 32615Sbill 33615Sbill /* 34615Sbill * Basic strategy: 35615Sbill * 36615Sbill * The loader takes a number of files and libraries as arguments. 37615Sbill * A first pass examines each file in turn. Normal files are 38615Sbill * unconditionally loaded, and the (external) symbols they define and require 39615Sbill * are noted in the symbol table. Libraries are searched, and the 40615Sbill * library members which define needed symbols are remembered 41615Sbill * in a special data structure so they can be selected on the second 42615Sbill * pass. Symbols defined and required by library members are also 43615Sbill * recorded. 44615Sbill * 45615Sbill * After the first pass, the loader knows the size of the basic text 46615Sbill * data, and bss segments from the sum of the sizes of the modules which 47615Sbill * were required. It has computed, for each ``common'' symbol, the 48615Sbill * maximum size of any reference to it, and these symbols are then assigned 49615Sbill * storage locations after their sizes are appropriately rounded. 50615Sbill * The loader now knows all sizes for the eventual output file, and 51615Sbill * can determine the final locations of external symbols before it 52615Sbill * begins a second pass. 53615Sbill * 54615Sbill * On the second pass each normal file and required library member 55615Sbill * is processed again. The symbol table for each such file is 56615Sbill * reread and relevant parts of it are placed in the output. The offsets 57615Sbill * in the local symbol table for externally defined symbols are recorded 58615Sbill * since relocation information refers to symbols in this way. 59615Sbill * Armed with all necessary information, the text and data segments 60615Sbill * are relocated and the result is placed in the output file, which 61615Sbill * is pasted together, ``in place'', by writing to it in several 62615Sbill * different places concurrently. 63615Sbill */ 64615Sbill 65615Sbill /* 66615Sbill * Internal data structures 67615Sbill * 68615Sbill * All internal data structures are segmented and dynamically extended. 69615Sbill * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT) 70615Sbill * referenced library members, and 100 (NSYMPR) private (local) symbols 71615Sbill * per object module. For large programs and/or modules, these structures 72615Sbill * expand to be up to 40 (NSEG) times as large as this as necessary. 73615Sbill */ 74615Sbill #define NSEG 40 /* Number of segments, each data structure */ 75615Sbill #define NSYM 1103 /* Number of symbols per segment */ 76615Sbill #define NROUT 250 /* Number of library references per segment */ 77615Sbill #define NSYMPR 100 /* Number of private symbols per segment */ 78615Sbill 79615Sbill /* 80615Sbill * Structure describing each symbol table segment. 81615Sbill * Each segment has its own hash table. We record the first 82615Sbill * address in and first address beyond both the symbol and hash 83615Sbill * tables, for use in the routine symx and the lookup routine respectively. 84615Sbill * The symfree routine also understands this structure well as it used 85615Sbill * to back out symbols from modules we decide that we don't need in pass 1. 86615Sbill * 87615Sbill * Csymseg points to the current symbol table segment; 88615Sbill * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated, 89615Sbill * (unless csymseg->sy_used == NSYM in which case we will allocate another 90615Sbill * symbol table segment first.) 91615Sbill */ 92615Sbill struct symseg { 93615Sbill struct nlist *sy_first; /* base of this alloc'ed segment */ 94615Sbill struct nlist *sy_last; /* end of this segment, for n_strx */ 95615Sbill int sy_used; /* symbols used in this seg */ 96615Sbill struct nlist **sy_hfirst; /* base of hash table, this seg */ 97615Sbill struct nlist **sy_hlast; /* end of hash table, this seg */ 98615Sbill } symseg[NSEG], *csymseg; 99615Sbill 100615Sbill /* 101615Sbill * The lookup routine uses quadratic rehash. Since a quadratic rehash 102615Sbill * only probes 1/2 of the buckets in the table, and since the hash 103615Sbill * table is segmented the same way the symbol table is, we make the 104615Sbill * hash table have twice as many buckets as there are symbol table slots 105615Sbill * in the segment. This guarantees that the quadratic rehash will never 106615Sbill * fail to find an empty bucket if the segment is not full and the 107615Sbill * symbol is not there. 108615Sbill */ 109615Sbill #define HSIZE (NSYM*2) 110615Sbill 111615Sbill /* 112615Sbill * Xsym converts symbol table indices (ala x) into symbol table pointers. 113615Sbill * Symx (harder, but never used in loops) inverts pointers into the symbol 114615Sbill * table into indices using the symseg[] structure. 115615Sbill */ 116615Sbill #define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM)) 117615Sbill /* symx() is a function, defined below */ 118615Sbill 119615Sbill struct nlist cursym; /* current symbol */ 120615Sbill struct nlist *lastsym; /* last symbol entered */ 121615Sbill struct nlist *nextsym; /* next available symbol table entry */ 122615Sbill struct nlist *addsym; /* first sym defined during incr load */ 123615Sbill int nsym; /* pass2: number of local symbols in a.out */ 124615Sbill /* nsym + symx(nextsym) is the symbol table size during pass2 */ 125615Sbill 126615Sbill struct nlist **lookup(), **slookup(); 127650Sbill struct nlist *p_etext, *p_edata, *p_end, *entrypt; 128615Sbill 129615Sbill /* 130615Sbill * Definitions of segmentation for library member table. 131615Sbill * For each library we encounter on pass 1 we record pointers to all 132615Sbill * members which we will load on pass 2. These are recorded as offsets 133615Sbill * into the archive in the library member table. Libraries are 134615Sbill * separated in the table by the special offset value -1. 135615Sbill */ 136615Sbill off_t li_init[NROUT]; 137615Sbill struct libseg { 138615Sbill off_t *li_first; 139615Sbill int li_used; 140615Sbill int li_used2; 141615Sbill } libseg[NSEG] = { 142615Sbill li_init, 0, 0, 143615Sbill }, *clibseg = libseg; 144615Sbill 145615Sbill /* 146615Sbill * In processing each module on pass 2 we must relocate references 147615Sbill * relative to external symbols. These references are recorded 148615Sbill * in the relocation information as relative to local symbol numbers 149615Sbill * assigned to the external symbols when the module was created. 150615Sbill * Thus before relocating the module in pass 2 we create a table 151615Sbill * which maps these internal numbers to symbol table entries. 152615Sbill * A hash table is constructed, based on the local symbol table indices, 153615Sbill * for quick lookup of these symbols. 154615Sbill */ 155615Sbill #define LHSIZ 31 156615Sbill struct local { 157615Sbill int l_index; /* index to symbol in file */ 158615Sbill struct nlist *l_symbol; /* ptr to symbol table */ 159615Sbill struct local *l_link; /* hash link */ 160615Sbill } *lochash[LHSIZ], lhinit[NSYMPR]; 161615Sbill struct locseg { 162615Sbill struct local *lo_first; 163615Sbill int lo_used; 164615Sbill } locseg[NSEG] = { 165615Sbill lhinit, 0 166615Sbill }, *clocseg; 167615Sbill 168615Sbill /* 169615Sbill * Libraries are typically built with a table of contents, 170615Sbill * which is the first member of a library with special file 171615Sbill * name __.SYMDEF and contains a list of symbol names 172615Sbill * and with each symbol the offset of the library member which defines 173615Sbill * it. The loader uses this table to quickly tell which library members 174615Sbill * are (potentially) useful. The alternative, examining the symbol 175615Sbill * table of each library member, is painfully slow for large archives. 176615Sbill * 177615Sbill * See <ranlib.h> for the definition of the ranlib structure and an 178615Sbill * explanation of the __.SYMDEF file format. 179615Sbill */ 180615Sbill int tnum; /* number of symbols in table of contents */ 181615Sbill int ssiz; /* size of string table for table of contents */ 182615Sbill struct ranlib *tab; /* the table of contents (dynamically allocated) */ 183615Sbill char *tabstr; /* string table for table of contents */ 184615Sbill 185615Sbill /* 186615Sbill * We open each input file or library only once, but in pass2 we 187615Sbill * (historically) read from such a file at 2 different places at the 188615Sbill * same time. These structures are remnants from those days, 189650Sbill * and now serve only to catch ``Premature EOF''. 1906414Smckusic * In order to make I/O more efficient, we provide routines which 19116068Sralph * use the optimal block size returned by stat(). 192615Sbill */ 1936414Smckusic #define BLKSIZE 1024 194615Sbill typedef struct { 195615Sbill short *fakeptr; 196615Sbill int bno; 197615Sbill int nibuf; 198615Sbill int nuser; 19916068Sralph char *buff; 20016068Sralph int bufsize; 201615Sbill } PAGE; 202615Sbill 203615Sbill PAGE page[2]; 20416068Sralph int p_blksize; 20516068Sralph int p_blkshift; 20616068Sralph int p_blkmask; 207615Sbill 208615Sbill struct { 209615Sbill short *fakeptr; 210615Sbill int bno; 211615Sbill int nibuf; 212615Sbill int nuser; 213615Sbill } fpage; 214615Sbill 215615Sbill typedef struct { 216615Sbill char *ptr; 217615Sbill int bno; 218615Sbill int nibuf; 219615Sbill long size; 220615Sbill long pos; 221615Sbill PAGE *pno; 222615Sbill } STREAM; 223615Sbill 224615Sbill STREAM text; 225615Sbill STREAM reloc; 226615Sbill 227615Sbill /* 228615Sbill * Header from the a.out and the archive it is from (if any). 229615Sbill */ 230615Sbill struct exec filhdr; 231615Sbill struct ar_hdr archdr; 232615Sbill #define OARMAG 0177545 233615Sbill 234615Sbill /* 235615Sbill * Options. 236615Sbill */ 237615Sbill int trace; 238615Sbill int xflag; /* discard local symbols */ 239615Sbill int Xflag; /* discard locals starting with 'L' */ 240615Sbill int Sflag; /* discard all except locals and globals*/ 241615Sbill int rflag; /* preserve relocation bits, don't define common */ 242615Sbill int arflag; /* original copy of rflag */ 243615Sbill int sflag; /* discard all symbols */ 244898Sbill int Mflag; /* print rudimentary load map */ 245615Sbill int nflag; /* pure procedure */ 246615Sbill int dflag; /* define common even with rflag */ 247650Sbill int zflag; /* demand paged */ 248615Sbill long hsize; /* size of hole at beginning of data to be squashed */ 249615Sbill int Aflag; /* doing incremental load */ 250650Sbill int Nflag; /* want impure a.out */ 251615Sbill int funding; /* reading fundamental file for incremental load */ 252898Sbill int yflag; /* number of symbols to be traced */ 253898Sbill char **ytab; /* the symbols */ 254615Sbill 255615Sbill /* 256615Sbill * These are the cumulative sizes, set in pass 1, which 257615Sbill * appear in the a.out header when the loader is finished. 258615Sbill */ 259615Sbill off_t tsize, dsize, bsize, trsize, drsize, ssize; 260615Sbill 261615Sbill /* 262615Sbill * Symbol relocation: c?rel is a scale factor which is 263615Sbill * added to an old relocation to convert it to new units; 264615Sbill * i.e. it is the difference between segment origins. 265650Sbill * (Thus if we are loading from a data segment which began at location 266650Sbill * 4 in a .o file into an a.out where it will be loaded starting at 267650Sbill * 1024, cdrel will be 1020.) 268615Sbill */ 269615Sbill long ctrel, cdrel, cbrel; 270615Sbill 271615Sbill /* 272650Sbill * Textbase is the start address of all text, 0 unless given by -T. 273615Sbill * Database is the base of all data, computed before and used during pass2. 274650Sbill */ 275650Sbill long textbase, database; 276650Sbill 277650Sbill /* 278615Sbill * The base addresses for the loaded text, data and bss from the 279615Sbill * current module during pass2 are given by torigin, dorigin and borigin. 280615Sbill */ 281615Sbill long torigin, dorigin, borigin; 282615Sbill 283615Sbill /* 284615Sbill * Errlev is nonzero when errors have occured. 285615Sbill * Delarg is an implicit argument to the routine delexit 286615Sbill * which is called on error. We do ``delarg = errlev'' before normal 287615Sbill * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the 288615Sbill * result file executable. 289615Sbill */ 290615Sbill int errlev; 291615Sbill int delarg = 4; 292615Sbill 293615Sbill /* 294615Sbill * The biobuf structure and associated routines are used to write 295615Sbill * into one file at several places concurrently. Calling bopen 296615Sbill * with a biobuf structure sets it up to write ``biofd'' starting 297615Sbill * at the specified offset. You can then use ``bwrite'' and/or ``bputc'' 298615Sbill * to stuff characters in the stream, much like ``fwrite'' and ``fputc''. 299615Sbill * Calling bflush drains all the buffers and MUST be done before exit. 300615Sbill */ 301615Sbill struct biobuf { 302615Sbill short b_nleft; /* Number free spaces left in b_buf */ 30316068Sralph /* Initialize to be less than b_bufsize initially, to boundary align in file */ 304615Sbill char *b_ptr; /* Next place to stuff characters */ 30516068Sralph char *b_buf; /* Pointer to the buffer */ 30616068Sralph int b_bufsize; /* Size of the buffer */ 307615Sbill off_t b_off; /* Current file offset */ 308615Sbill struct biobuf *b_link; /* Link in chain for bflush() */ 309615Sbill } *biobufs; 310615Sbill #define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \ 311615Sbill : bflushc(b, c)) 312615Sbill int biofd; 313615Sbill off_t boffset; 314615Sbill struct biobuf *tout, *dout, *trout, *drout, *sout, *strout; 315615Sbill 316615Sbill /* 317615Sbill * Offset is the current offset in the string file. 318615Sbill * Its initial value reflects the fact that we will 319615Sbill * eventually stuff the size of the string table at the 320615Sbill * beginning of the string table (i.e. offset itself!). 321615Sbill */ 322615Sbill off_t offset = sizeof (off_t); 323615Sbill 324615Sbill int ofilfnd; /* -o given; otherwise move l.out to a.out */ 32544768Sbostic char *ofilename = "l.out"; 3263606Ssklower int ofilemode; /* respect umask even for unsucessful ld's */ 327615Sbill int infil; /* current input file descriptor */ 328615Sbill char *filname; /* and its name */ 329615Sbill 33017133Ssam #define NDIRS 25 33125533Sbloom #define NDEFDIRS 3 /* number of default directories in dirs[] */ 33217133Ssam char *dirs[NDIRS]; /* directories for library search */ 33317133Ssam int ndir; /* number of directories */ 33417133Ssam 335615Sbill /* 336615Sbill * Base of the string table of the current module (pass1 and pass2). 337615Sbill */ 338615Sbill char *curstr; 339615Sbill 34012671Ssam /* 34112671Ssam * System software page size, as returned by getpagesize. 34212671Ssam */ 34312671Ssam int pagesize; 34412671Ssam 345615Sbill char get(); 346615Sbill int delexit(); 347615Sbill char *savestr(); 34817133Ssam char *malloc(); 349615Sbill 350615Sbill main(argc, argv) 351615Sbill char **argv; 352615Sbill { 353615Sbill register int c, i; 354615Sbill int num; 355615Sbill register char *ap, **p; 356615Sbill char save; 357615Sbill 358650Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 359615Sbill signal(SIGINT, delexit); 360650Sbill signal(SIGTERM, delexit); 361650Sbill } 362615Sbill if (argc == 1) 363615Sbill exit(4); 36412671Ssam pagesize = getpagesize(); 365615Sbill 36617133Ssam /* 36717133Ssam * Pull out search directories. 36817133Ssam */ 36917133Ssam for (c = 1; c < argc; c++) { 37017133Ssam ap = argv[c]; 37117133Ssam if (ap[0] == '-' && ap[1] == 'L') { 37217133Ssam if (ap[2] == 0) 37317133Ssam error(1, "-L: pathname missing"); 37425533Sbloom if (ndir >= NDIRS - NDEFDIRS) 37517133Ssam error(1, "-L: too many directories"); 37617133Ssam dirs[ndir++] = &ap[2]; 37717133Ssam } 37817133Ssam } 37917133Ssam /* add default search directories */ 38037031Sbostic dirs[ndir++] = _PATH_USRLIB; 38137031Sbostic dirs[ndir++] = _PATH_LOCALLIB; 38217133Ssam 38317133Ssam p = argv+1; 384650Sbill /* 385650Sbill * Scan files once to find where symbols are defined. 386650Sbill */ 387615Sbill for (c=1; c<argc; c++) { 388615Sbill if (trace) 389615Sbill printf("%s:\n", *p); 390615Sbill filname = 0; 391615Sbill ap = *p++; 392615Sbill if (*ap != '-') { 393615Sbill load1arg(ap); 394615Sbill continue; 395615Sbill } 396615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 397615Sbill 398615Sbill case 'o': 399615Sbill if (++c >= argc) 400615Sbill error(1, "-o where?"); 40144768Sbostic ofilename = *p++; 402615Sbill ofilfnd++; 403615Sbill continue; 404615Sbill case 'u': 405615Sbill case 'e': 406615Sbill if (++c >= argc) 40733997Sbostic error(1, " -u or -e: arg missing"); 408615Sbill enter(slookup(*p++)); 409615Sbill if (ap[i]=='e') 410615Sbill entrypt = lastsym; 411615Sbill continue; 412615Sbill case 'H': 413615Sbill if (++c >= argc) 414615Sbill error(1, "-H: arg missing"); 415615Sbill if (tsize!=0) 416615Sbill error(1, "-H: too late, some text already loaded"); 417615Sbill hsize = atoi(*p++); 418615Sbill continue; 419615Sbill case 'A': 420615Sbill if (++c >= argc) 421615Sbill error(1, "-A: arg missing"); 422615Sbill if (Aflag) 423615Sbill error(1, "-A: only one base file allowed"); 424615Sbill Aflag = 1; 425615Sbill nflag = 0; 426615Sbill funding = 1; 427615Sbill load1arg(*p++); 428615Sbill trsize = drsize = tsize = dsize = bsize = 0; 429615Sbill ctrel = cdrel = cbrel = 0; 430615Sbill funding = 0; 431615Sbill addsym = nextsym; 432615Sbill continue; 433615Sbill case 'D': 434615Sbill if (++c >= argc) 435615Sbill error(1, "-D: arg missing"); 436615Sbill num = htoi(*p++); 437615Sbill if (dsize > num) 438615Sbill error(1, "-D: too small"); 439615Sbill dsize = num; 440615Sbill continue; 441615Sbill case 'T': 442615Sbill if (++c >= argc) 443615Sbill error(1, "-T: arg missing"); 444615Sbill if (tsize!=0) 445615Sbill error(1, "-T: too late, some text already loaded"); 446615Sbill textbase = htoi(*p++); 447615Sbill continue; 448615Sbill case 'l': 449615Sbill save = ap[--i]; 450615Sbill ap[i]='-'; 451615Sbill load1arg(&ap[i]); 452615Sbill ap[i]=save; 453615Sbill goto next; 454898Sbill case 'M': 455898Sbill Mflag++; 456898Sbill continue; 457615Sbill case 'x': 458615Sbill xflag++; 459615Sbill continue; 460615Sbill case 'X': 461615Sbill Xflag++; 462615Sbill continue; 463615Sbill case 'S': 464615Sbill Sflag++; 465615Sbill continue; 466615Sbill case 'r': 467615Sbill rflag++; 468615Sbill arflag++; 469615Sbill continue; 470615Sbill case 's': 471615Sbill sflag++; 472615Sbill xflag++; 473615Sbill continue; 474615Sbill case 'n': 475615Sbill nflag++; 476650Sbill Nflag = zflag = 0; 477615Sbill continue; 478615Sbill case 'N': 479650Sbill Nflag++; 480650Sbill nflag = zflag = 0; 481615Sbill continue; 482615Sbill case 'd': 483615Sbill dflag++; 484615Sbill continue; 485615Sbill case 'i': 486615Sbill printf("ld: -i ignored\n"); 487615Sbill continue; 488615Sbill case 't': 489615Sbill trace++; 490615Sbill continue; 491898Sbill case 'y': 492898Sbill if (ap[i+1] == 0) 493898Sbill error(1, "-y: symbol name missing"); 494898Sbill if (yflag == 0) { 495898Sbill ytab = (char **)calloc(argc, sizeof (char **)); 496898Sbill if (ytab == 0) 497898Sbill error(1, "ran out of memory (-y)"); 498898Sbill } 499898Sbill ytab[yflag++] = &ap[i+1]; 500898Sbill goto next; 501615Sbill case 'z': 502615Sbill zflag++; 503650Sbill Nflag = nflag = 0; 504615Sbill continue; 50517133Ssam case 'L': 50617133Ssam goto next; 507615Sbill default: 508615Sbill filname = savestr("-x"); /* kludge */ 509615Sbill filname[1] = ap[i]; /* kludge */ 510615Sbill archdr.ar_name[0] = 0; /* kludge */ 511615Sbill error(1, "bad flag"); 512615Sbill } 513615Sbill next: 514615Sbill ; 515615Sbill } 516650Sbill if (rflag == 0 && Nflag == 0 && nflag == 0) 517650Sbill zflag++; 518615Sbill endload(argc, argv); 519615Sbill exit(0); 520615Sbill } 521615Sbill 522615Sbill /* 523615Sbill * Convert a ascii string which is a hex number. 524615Sbill * Used by -T and -D options. 525615Sbill */ 526615Sbill htoi(p) 527615Sbill register char *p; 528615Sbill { 529615Sbill register int c, n; 530615Sbill 531615Sbill n = 0; 532615Sbill while (c = *p++) { 533615Sbill n <<= 4; 534615Sbill if (isdigit(c)) 535615Sbill n += c - '0'; 536615Sbill else if (c >= 'a' && c <= 'f') 537615Sbill n += 10 + (c - 'a'); 538615Sbill else if (c >= 'A' && c <= 'F') 539615Sbill n += 10 + (c - 'A'); 540615Sbill else 541615Sbill error(1, "badly formed hex number"); 542615Sbill } 543615Sbill return (n); 544615Sbill } 545615Sbill 546615Sbill delexit() 547615Sbill { 5489332Smckusick struct stat stbuf; 5499332Smckusick long size; 5509332Smckusick char c = 0; 551615Sbill 552615Sbill bflush(); 55344768Sbostic unlink("l.out"); 5549332Smckusick /* 5559332Smckusick * We have to insure that the last block of the data segment 55616068Sralph * is allocated a full pagesize block. If the underlying 55716068Sralph * file system allocates frags that are smaller than pagesize, 55816068Sralph * a full zero filled pagesize block needs to be allocated so 5599332Smckusick * that when it is demand paged, the paged in block will be 5609332Smckusick * appropriately filled with zeros. 5619332Smckusick */ 5629332Smckusick fstat(biofd, &stbuf); 56316068Sralph size = round(stbuf.st_size, pagesize); 56410640Smckusick if (!rflag && size > stbuf.st_size) { 5659332Smckusick lseek(biofd, size - 1, 0); 56625419Sbloom if (write(biofd, &c, 1) != 1) 56725419Sbloom delarg |= 4; 5689332Smckusick } 56925419Sbloom if (delarg==0 && Aflag==0) 57025419Sbloom (void) chmod(ofilename, ofilemode); 571615Sbill exit (delarg); 572615Sbill } 573615Sbill 574615Sbill endload(argc, argv) 575615Sbill int argc; 576615Sbill char **argv; 577615Sbill { 578615Sbill register int c, i; 579615Sbill long dnum; 580615Sbill register char *ap, **p; 581615Sbill 582615Sbill clibseg = libseg; 583615Sbill filname = 0; 584615Sbill middle(); 585615Sbill setupout(); 586615Sbill p = argv+1; 587615Sbill for (c=1; c<argc; c++) { 588615Sbill ap = *p++; 589615Sbill if (trace) 590615Sbill printf("%s:\n", ap); 591615Sbill if (*ap != '-') { 592615Sbill load2arg(ap); 593615Sbill continue; 594615Sbill } 595615Sbill for (i=1; ap[i]; i++) switch (ap[i]) { 596615Sbill 597615Sbill case 'D': 598615Sbill dnum = htoi(*p); 599615Sbill if (dorigin < dnum) 600615Sbill while (dorigin < dnum) 601615Sbill bputc(0, dout), dorigin++; 602615Sbill /* fall into ... */ 603615Sbill case 'T': 604615Sbill case 'u': 605615Sbill case 'e': 606615Sbill case 'o': 607615Sbill case 'H': 608615Sbill ++c; 609615Sbill ++p; 610615Sbill /* fall into ... */ 611615Sbill default: 612615Sbill continue; 613615Sbill case 'A': 614615Sbill funding = 1; 615615Sbill load2arg(*p++); 616615Sbill funding = 0; 617615Sbill c++; 618615Sbill continue; 619898Sbill case 'y': 62017133Ssam case 'L': 621898Sbill goto next; 622615Sbill case 'l': 623615Sbill ap[--i]='-'; 624615Sbill load2arg(&ap[i]); 625615Sbill goto next; 626615Sbill } 627615Sbill next: 628615Sbill ; 629615Sbill } 630615Sbill finishout(); 631615Sbill } 632615Sbill 633615Sbill /* 634615Sbill * Scan file to find defined symbols. 635615Sbill */ 636615Sbill load1arg(cp) 637615Sbill register char *cp; 638615Sbill { 639615Sbill register struct ranlib *tp; 640615Sbill off_t nloc; 641898Sbill int kind; 642615Sbill 643898Sbill kind = getfile(cp); 644898Sbill if (Mflag) 645898Sbill printf("%s\n", filname); 646898Sbill switch (kind) { 647615Sbill 648615Sbill /* 649615Sbill * Plain file. 650615Sbill */ 651615Sbill case 0: 652615Sbill load1(0, 0L); 653615Sbill break; 654615Sbill 655615Sbill /* 656615Sbill * Archive without table of contents. 657615Sbill * (Slowly) process each member. 658615Sbill */ 659615Sbill case 1: 660898Sbill error(-1, 661898Sbill "warning: archive has no table of contents; add one using ranlib(1)"); 662615Sbill nloc = SARMAG; 663615Sbill while (step(nloc)) 664615Sbill nloc += sizeof(archdr) + 665615Sbill round(atol(archdr.ar_size), sizeof (short)); 666615Sbill break; 667615Sbill 668615Sbill /* 669615Sbill * Archive with table of contents. 670615Sbill * Read the table of contents and its associated string table. 671615Sbill * Pass through the library resolving symbols until nothing changes 672615Sbill * for an entire pass (i.e. you can get away with backward references 673615Sbill * when there is a table of contents!) 674615Sbill */ 675615Sbill case 2: 676615Sbill nloc = SARMAG + sizeof (archdr); 677615Sbill dseek(&text, nloc, sizeof (tnum)); 678615Sbill mget((char *)&tnum, sizeof (tnum), &text); 679615Sbill nloc += sizeof (tnum); 680615Sbill tab = (struct ranlib *)malloc(tnum); 681615Sbill if (tab == 0) 682615Sbill error(1, "ran out of memory (toc)"); 683615Sbill dseek(&text, nloc, tnum); 684615Sbill mget((char *)tab, tnum, &text); 685615Sbill nloc += tnum; 686615Sbill tnum /= sizeof (struct ranlib); 687615Sbill dseek(&text, nloc, sizeof (ssiz)); 688615Sbill mget((char *)&ssiz, sizeof (ssiz), &text); 689615Sbill nloc += sizeof (ssiz); 690615Sbill tabstr = (char *)malloc(ssiz); 691615Sbill if (tabstr == 0) 692615Sbill error(1, "ran out of memory (tocstr)"); 693615Sbill dseek(&text, nloc, ssiz); 694615Sbill mget((char *)tabstr, ssiz, &text); 695615Sbill for (tp = &tab[tnum]; --tp >= tab;) { 696615Sbill if (tp->ran_un.ran_strx < 0 || 697615Sbill tp->ran_un.ran_strx >= ssiz) 698615Sbill error(1, "mangled archive table of contents"); 699615Sbill tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx; 700615Sbill } 701615Sbill while (ldrand()) 702615Sbill continue; 70325483Slepreau free((char *)tab); 70425483Slepreau free(tabstr); 705615Sbill nextlibp(-1); 706615Sbill break; 707615Sbill 708615Sbill /* 709615Sbill * Table of contents is out of date, so search 710615Sbill * as a normal library (but skip the __.SYMDEF file). 711615Sbill */ 712615Sbill case 3: 713898Sbill error(-1, 714898Sbill "warning: table of contents for archive is out of date; rerun ranlib(1)"); 715615Sbill nloc = SARMAG; 716615Sbill do 717615Sbill nloc += sizeof(archdr) + 718615Sbill round(atol(archdr.ar_size), sizeof(short)); 719615Sbill while (step(nloc)); 720615Sbill break; 721615Sbill } 722615Sbill close(infil); 723615Sbill } 724615Sbill 725615Sbill /* 726615Sbill * Advance to the next archive member, which 727615Sbill * is at offset nloc in the archive. If the member 728615Sbill * is useful, record its location in the liblist structure 729615Sbill * for use in pass2. Mark the end of the archive in libilst with a -1. 730615Sbill */ 731615Sbill step(nloc) 732615Sbill off_t nloc; 733615Sbill { 734615Sbill 735615Sbill dseek(&text, nloc, (long) sizeof archdr); 736615Sbill if (text.size <= 0) { 737615Sbill nextlibp(-1); 738615Sbill return (0); 739615Sbill } 740615Sbill getarhdr(); 741615Sbill if (load1(1, nloc + (sizeof archdr))) 742615Sbill nextlibp(nloc); 743615Sbill return (1); 744615Sbill } 745615Sbill 746615Sbill /* 747615Sbill * Record the location of a useful archive member. 748615Sbill * Recording -1 marks the end of files from an archive. 749615Sbill * The liblist data structure is dynamically extended here. 750615Sbill */ 751615Sbill nextlibp(val) 752615Sbill off_t val; 753615Sbill { 754615Sbill 755615Sbill if (clibseg->li_used == NROUT) { 756615Sbill if (++clibseg == &libseg[NSEG]) 757615Sbill error(1, "too many files loaded from libraries"); 758615Sbill clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t)); 759615Sbill if (clibseg->li_first == 0) 760615Sbill error(1, "ran out of memory (nextlibp)"); 761615Sbill } 762615Sbill clibseg->li_first[clibseg->li_used++] = val; 763898Sbill if (val != -1 && Mflag) 764898Sbill printf("\t%s\n", archdr.ar_name); 765615Sbill } 766615Sbill 767615Sbill /* 768615Sbill * One pass over an archive with a table of contents. 769615Sbill * Remember the number of symbols currently defined, 770615Sbill * then call step on members which look promising (i.e. 771615Sbill * that define a symbol which is currently externally undefined). 772615Sbill * Indicate to our caller whether this process netted any more symbols. 773615Sbill */ 774615Sbill ldrand() 775615Sbill { 776615Sbill register struct nlist *sp, **hp; 777615Sbill register struct ranlib *tp, *tplast; 778615Sbill off_t loc; 779615Sbill int nsymt = symx(nextsym); 780615Sbill 781615Sbill tplast = &tab[tnum-1]; 782615Sbill for (tp = tab; tp <= tplast; tp++) { 78325483Slepreau if ((hp = slookup(tp->ran_un.ran_name)) == 0 || *hp == 0) 784615Sbill continue; 785615Sbill sp = *hp; 786615Sbill if (sp->n_type != N_EXT+N_UNDF) 787615Sbill continue; 788615Sbill step(tp->ran_off); 789615Sbill loc = tp->ran_off; 790615Sbill while (tp < tplast && (tp+1)->ran_off == loc) 791615Sbill tp++; 792615Sbill } 793615Sbill return (symx(nextsym) != nsymt); 794615Sbill } 795615Sbill 796615Sbill /* 797615Sbill * Examine a single file or archive member on pass 1. 798615Sbill */ 799615Sbill load1(libflg, loc) 800615Sbill off_t loc; 801615Sbill { 802615Sbill register struct nlist *sp; 803615Sbill struct nlist *savnext; 804615Sbill int ndef, nlocal, type, size, nsymt; 805615Sbill register int i; 806615Sbill off_t maxoff; 807615Sbill struct stat stb; 808615Sbill 809615Sbill readhdr(loc); 810615Sbill if (filhdr.a_syms == 0) { 81129999Sbostic if (filhdr.a_text+filhdr.a_data == 0) { 81229999Sbostic /* load2() adds a symbol for the file name */ 81329999Sbostic if (!libflg) 81429999Sbostic ssize += sizeof (cursym); 815615Sbill return (0); 81629999Sbostic } 817615Sbill error(1, "no namelist"); 818615Sbill } 819615Sbill if (libflg) 820615Sbill maxoff = atol(archdr.ar_size); 821615Sbill else { 822615Sbill fstat(infil, &stb); 823615Sbill maxoff = stb.st_size; 824615Sbill } 825615Sbill if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff) 826615Sbill error(1, "too small (old format .o?)"); 827615Sbill ctrel = tsize; cdrel += dsize; cbrel += bsize; 828615Sbill ndef = 0; 829615Sbill nlocal = sizeof(cursym); 830615Sbill savnext = nextsym; 831615Sbill loc += N_SYMOFF(filhdr); 832615Sbill dseek(&text, loc, filhdr.a_syms); 833615Sbill dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t)); 834615Sbill mget(&size, sizeof (size), &reloc); 835615Sbill dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t)); 836615Sbill curstr = (char *)malloc(size); 837615Sbill if (curstr == NULL) 838615Sbill error(1, "no space for string table"); 839615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc); 840615Sbill while (text.size > 0) { 841615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 842615Sbill if (cursym.n_un.n_strx) { 843615Sbill if (cursym.n_un.n_strx<sizeof(size) || 844615Sbill cursym.n_un.n_strx>=size) 845615Sbill error(1, "bad string table index (pass 1)"); 846615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 847615Sbill } 848615Sbill type = cursym.n_type; 849615Sbill if ((type&N_EXT)==0) { 850615Sbill if (Xflag==0 || cursym.n_un.n_name[0]!='L' || 851615Sbill type & N_STAB) 852615Sbill nlocal += sizeof cursym; 853615Sbill continue; 854615Sbill } 855615Sbill symreloc(); 856615Sbill if (enter(lookup())) 857615Sbill continue; 858615Sbill if ((sp = lastsym)->n_type != N_EXT+N_UNDF) 859615Sbill continue; 860615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 861615Sbill if (cursym.n_value > sp->n_value) 862615Sbill sp->n_value = cursym.n_value; 863615Sbill continue; 864615Sbill } 865615Sbill if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT) 866615Sbill continue; 867615Sbill ndef++; 868615Sbill sp->n_type = cursym.n_type; 869615Sbill sp->n_value = cursym.n_value; 870615Sbill } 871615Sbill if (libflg==0 || ndef) { 872615Sbill tsize += filhdr.a_text; 873615Sbill dsize += round(filhdr.a_data, sizeof (long)); 874615Sbill bsize += round(filhdr.a_bss, sizeof (long)); 875615Sbill ssize += nlocal; 876615Sbill trsize += filhdr.a_trsize; 877615Sbill drsize += filhdr.a_drsize; 878615Sbill if (funding) 879615Sbill textbase = (*slookup("_end"))->n_value; 880615Sbill nsymt = symx(nextsym); 881615Sbill for (i = symx(savnext); i < nsymt; i++) { 882615Sbill sp = xsym(i); 883615Sbill sp->n_un.n_name = savestr(sp->n_un.n_name); 884615Sbill } 885615Sbill free(curstr); 886615Sbill return (1); 887615Sbill } 888615Sbill /* 889615Sbill * No symbols defined by this library member. 890615Sbill * Rip out the hash table entries and reset the symbol table. 891615Sbill */ 892615Sbill symfree(savnext); 893615Sbill free(curstr); 894615Sbill return(0); 895615Sbill } 896615Sbill 897615Sbill middle() 898615Sbill { 899615Sbill register struct nlist *sp; 900615Sbill long csize, t, corigin, ocsize; 901615Sbill int nund, rnd; 902615Sbill char s; 903615Sbill register int i; 904615Sbill int nsymt; 905615Sbill 906615Sbill torigin = 0; 907615Sbill dorigin = 0; 908615Sbill borigin = 0; 909615Sbill 910615Sbill p_etext = *slookup("_etext"); 911615Sbill p_edata = *slookup("_edata"); 912615Sbill p_end = *slookup("_end"); 913615Sbill /* 914615Sbill * If there are any undefined symbols, save the relocation bits. 915615Sbill */ 916615Sbill nsymt = symx(nextsym); 917615Sbill if (rflag==0) { 918615Sbill for (i = 0; i < nsymt; i++) { 919615Sbill sp = xsym(i); 920615Sbill if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 && 921650Sbill sp!=p_end && sp!=p_edata && sp!=p_etext) { 922615Sbill rflag++; 923615Sbill dflag = 0; 924615Sbill break; 925615Sbill } 926615Sbill } 927615Sbill } 928615Sbill if (rflag) 929615Sbill sflag = zflag = 0; 930615Sbill /* 931615Sbill * Assign common locations. 932615Sbill */ 933615Sbill csize = 0; 934615Sbill if (!Aflag) 935615Sbill addsym = symseg[0].sy_first; 936615Sbill database = round(tsize+textbase, 93712671Ssam (nflag||zflag? pagesize : sizeof (long))); 938615Sbill database += hsize; 939615Sbill if (dflag || rflag==0) { 940615Sbill ldrsym(p_etext, tsize, N_EXT+N_TEXT); 941615Sbill ldrsym(p_edata, dsize, N_EXT+N_DATA); 942615Sbill ldrsym(p_end, bsize, N_EXT+N_BSS); 943615Sbill for (i = symx(addsym); i < nsymt; i++) { 944615Sbill sp = xsym(i); 945615Sbill if ((s=sp->n_type)==N_EXT+N_UNDF && 946615Sbill (t = sp->n_value)!=0) { 947615Sbill if (t >= sizeof (double)) 948615Sbill rnd = sizeof (double); 949615Sbill else if (t >= sizeof (long)) 950615Sbill rnd = sizeof (long); 951615Sbill else 952615Sbill rnd = sizeof (short); 953615Sbill csize = round(csize, rnd); 954615Sbill sp->n_value = csize; 955615Sbill sp->n_type = N_EXT+N_COMM; 956615Sbill ocsize = csize; 957615Sbill csize += t; 958615Sbill } 959615Sbill if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) { 960615Sbill sp->n_value = ocsize; 961615Sbill sp->n_type = (s&N_STAB) | (N_EXT+N_COMM); 962615Sbill } 963615Sbill } 964615Sbill } 965615Sbill /* 966615Sbill * Now set symbols to their final value 967615Sbill */ 968615Sbill csize = round(csize, sizeof (long)); 969615Sbill torigin = textbase; 970615Sbill dorigin = database; 971615Sbill corigin = dorigin + dsize; 972615Sbill borigin = corigin + csize; 973615Sbill nund = 0; 974615Sbill nsymt = symx(nextsym); 975615Sbill for (i = symx(addsym); i<nsymt; i++) { 976615Sbill sp = xsym(i); 977615Sbill switch (sp->n_type & (N_TYPE+N_EXT)) { 978615Sbill 979615Sbill case N_EXT+N_UNDF: 9802369Skre if (arflag == 0) 9812369Skre errlev |= 01; 982615Sbill if ((arflag==0 || dflag) && sp->n_value==0) { 983650Sbill if (sp==p_end || sp==p_etext || sp==p_edata) 984650Sbill continue; 985615Sbill if (nund==0) 986615Sbill printf("Undefined:\n"); 987615Sbill nund++; 988615Sbill printf("%s\n", sp->n_un.n_name); 989615Sbill } 990615Sbill continue; 991615Sbill case N_EXT+N_ABS: 992615Sbill default: 993615Sbill continue; 994615Sbill case N_EXT+N_TEXT: 995615Sbill sp->n_value += torigin; 996615Sbill continue; 997615Sbill case N_EXT+N_DATA: 998615Sbill sp->n_value += dorigin; 999615Sbill continue; 1000615Sbill case N_EXT+N_BSS: 1001615Sbill sp->n_value += borigin; 1002615Sbill continue; 1003615Sbill case N_EXT+N_COMM: 1004615Sbill sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS); 1005615Sbill sp->n_value += corigin; 1006615Sbill continue; 1007615Sbill } 1008615Sbill } 1009615Sbill if (sflag || xflag) 1010615Sbill ssize = 0; 1011615Sbill bsize += csize; 1012615Sbill nsym = ssize / (sizeof cursym); 1013615Sbill if (Aflag) { 1014615Sbill fixspec(p_etext,torigin); 1015615Sbill fixspec(p_edata,dorigin); 1016615Sbill fixspec(p_end,borigin); 1017615Sbill } 1018615Sbill } 1019615Sbill 1020615Sbill fixspec(sym,offset) 1021615Sbill struct nlist *sym; 1022615Sbill long offset; 1023615Sbill { 1024615Sbill 1025615Sbill if(symx(sym) < symx(addsym) && sym!=0) 1026615Sbill sym->n_value += offset; 1027615Sbill } 1028615Sbill 1029615Sbill ldrsym(sp, val, type) 1030615Sbill register struct nlist *sp; 1031615Sbill long val; 1032615Sbill { 1033615Sbill 1034615Sbill if (sp == 0) 1035615Sbill return; 1036615Sbill if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) { 1037615Sbill printf("%s: ", sp->n_un.n_name); 1038615Sbill error(0, "user attempt to redfine loader-defined symbol"); 1039615Sbill return; 1040615Sbill } 1041615Sbill sp->n_type = type; 1042615Sbill sp->n_value = val; 1043615Sbill } 1044615Sbill 1045615Sbill off_t wroff; 1046615Sbill struct biobuf toutb; 1047615Sbill 1048615Sbill setupout() 1049615Sbill { 105042415Sbostic extern int errno; 1051615Sbill int bss; 105216068Sralph struct stat stbuf; 1053615Sbill 10543606Ssklower ofilemode = 0777 & ~umask(0); 10553606Ssklower biofd = creat(ofilename, 0666 & ofilemode); 1056898Sbill if (biofd < 0) { 1057898Sbill filname = ofilename; /* kludge */ 1058898Sbill archdr.ar_name[0] = 0; /* kludge */ 105942415Sbostic error(1, strerror(errno)); /* kludge */ 1060898Sbill } 106116068Sralph fstat(biofd, &stbuf); /* suppose file exists, wrong*/ 106216068Sralph if (stbuf.st_mode & 0111) { /* mode, ld fails? */ 106316068Sralph chmod(ofilename, stbuf.st_mode & 0666); 106416068Sralph ofilemode = stbuf.st_mode; 106516068Sralph } 106644293Sbostic #ifdef hp300 106744293Sbostic filhdr.a_mid = (rflag ? MID_ZERO : MID_HP300); 106844293Sbostic #endif 1069615Sbill filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC); 1070615Sbill filhdr.a_text = nflag ? tsize : 107112671Ssam round(tsize, zflag ? pagesize : sizeof (long)); 107212671Ssam filhdr.a_data = zflag ? round(dsize, pagesize) : dsize; 1073615Sbill bss = bsize - (filhdr.a_data - dsize); 1074615Sbill if (bss < 0) 1075615Sbill bss = 0; 1076615Sbill filhdr.a_bss = bss; 1077615Sbill filhdr.a_trsize = trsize; 1078615Sbill filhdr.a_drsize = drsize; 1079615Sbill filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym)); 1080615Sbill if (entrypt) { 1081615Sbill if (entrypt->n_type!=N_EXT+N_TEXT) 1082615Sbill error(0, "entry point not in text"); 1083615Sbill else 1084615Sbill filhdr.a_entry = entrypt->n_value; 1085615Sbill } else 1086615Sbill filhdr.a_entry = 0; 1087615Sbill filhdr.a_trsize = (rflag ? trsize:0); 1088615Sbill filhdr.a_drsize = (rflag ? drsize:0); 108916068Sralph tout = &toutb; 109016068Sralph bopen(tout, 0, stbuf.st_blksize); 1091615Sbill bwrite((char *)&filhdr, sizeof (filhdr), tout); 109216068Sralph if (zflag) 109316068Sralph bseek(tout, pagesize); 1094615Sbill wroff = N_TXTOFF(filhdr) + filhdr.a_text; 109516068Sralph outb(&dout, filhdr.a_data, stbuf.st_blksize); 1096615Sbill if (rflag) { 109716068Sralph outb(&trout, filhdr.a_trsize, stbuf.st_blksize); 109816068Sralph outb(&drout, filhdr.a_drsize, stbuf.st_blksize); 1099615Sbill } 1100615Sbill if (sflag==0 || xflag==0) { 110116068Sralph outb(&sout, filhdr.a_syms, stbuf.st_blksize); 1102615Sbill wroff += sizeof (offset); 110316068Sralph outb(&strout, 0, stbuf.st_blksize); 1104615Sbill } 1105615Sbill } 1106615Sbill 110716068Sralph outb(bp, inc, bufsize) 1108615Sbill register struct biobuf **bp; 1109615Sbill { 1110615Sbill 1111615Sbill *bp = (struct biobuf *)malloc(sizeof (struct biobuf)); 1112615Sbill if (*bp == 0) 1113615Sbill error(1, "ran out of memory (outb)"); 111416068Sralph bopen(*bp, wroff, bufsize); 1115615Sbill wroff += inc; 1116615Sbill } 1117615Sbill 1118615Sbill load2arg(acp) 1119615Sbill char *acp; 1120615Sbill { 1121615Sbill register char *cp; 1122615Sbill off_t loc; 1123615Sbill 1124615Sbill cp = acp; 1125615Sbill if (getfile(cp) == 0) { 1126615Sbill while (*cp) 1127615Sbill cp++; 1128615Sbill while (cp >= acp && *--cp != '/'); 1129615Sbill mkfsym(++cp); 1130615Sbill load2(0L); 1131615Sbill } else { /* scan archive members referenced */ 1132615Sbill for (;;) { 1133615Sbill if (clibseg->li_used2 == clibseg->li_used) { 1134615Sbill if (clibseg->li_used < NROUT) 1135615Sbill error(1, "libseg botch"); 1136615Sbill clibseg++; 1137615Sbill } 1138615Sbill loc = clibseg->li_first[clibseg->li_used2++]; 1139615Sbill if (loc == -1) 1140615Sbill break; 1141615Sbill dseek(&text, loc, (long)sizeof(archdr)); 1142615Sbill getarhdr(); 1143615Sbill mkfsym(archdr.ar_name); 1144615Sbill load2(loc + (long)sizeof(archdr)); 1145615Sbill } 1146615Sbill } 1147615Sbill close(infil); 1148615Sbill } 1149615Sbill 1150615Sbill load2(loc) 1151615Sbill long loc; 1152615Sbill { 1153615Sbill int size; 1154615Sbill register struct nlist *sp; 1155615Sbill register struct local *lp; 1156615Sbill register int symno, i; 1157615Sbill int type; 1158615Sbill 1159615Sbill readhdr(loc); 1160650Sbill if (!funding) { 1161615Sbill ctrel = torigin; 1162615Sbill cdrel += dorigin; 1163615Sbill cbrel += borigin; 1164615Sbill } 1165615Sbill /* 1166615Sbill * Reread the symbol table, recording the numbering 1167615Sbill * of symbols for fixing external references. 1168615Sbill */ 1169615Sbill for (i = 0; i < LHSIZ; i++) 1170615Sbill lochash[i] = 0; 1171615Sbill clocseg = locseg; 1172615Sbill clocseg->lo_used = 0; 1173615Sbill symno = -1; 1174615Sbill loc += N_TXTOFF(filhdr); 1175615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1176615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t)); 1177615Sbill mget(&size, sizeof(size), &text); 1178615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1179615Sbill filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t), 1180615Sbill size - sizeof(off_t)); 1181615Sbill curstr = (char *)malloc(size); 1182615Sbill if (curstr == NULL) 1183615Sbill error(1, "out of space reading string table (pass 2)"); 1184615Sbill mget(curstr+sizeof(off_t), size-sizeof(off_t), &text); 1185615Sbill dseek(&text, loc+filhdr.a_text+filhdr.a_data+ 1186615Sbill filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms); 1187615Sbill while (text.size > 0) { 1188615Sbill symno++; 1189615Sbill mget((char *)&cursym, sizeof(struct nlist), &text); 1190615Sbill if (cursym.n_un.n_strx) { 1191615Sbill if (cursym.n_un.n_strx<sizeof(size) || 1192615Sbill cursym.n_un.n_strx>=size) 1193615Sbill error(1, "bad string table index (pass 2)"); 1194615Sbill cursym.n_un.n_name = curstr + cursym.n_un.n_strx; 1195615Sbill } 1196615Sbill /* inline expansion of symreloc() */ 1197615Sbill switch (cursym.n_type & 017) { 1198615Sbill 1199615Sbill case N_TEXT: 1200615Sbill case N_EXT+N_TEXT: 1201615Sbill cursym.n_value += ctrel; 1202615Sbill break; 1203615Sbill case N_DATA: 1204615Sbill case N_EXT+N_DATA: 1205615Sbill cursym.n_value += cdrel; 1206615Sbill break; 1207615Sbill case N_BSS: 1208615Sbill case N_EXT+N_BSS: 1209615Sbill cursym.n_value += cbrel; 1210615Sbill break; 1211615Sbill case N_EXT+N_UNDF: 1212615Sbill break; 1213615Sbill default: 1214615Sbill if (cursym.n_type&N_EXT) 1215615Sbill cursym.n_type = N_EXT+N_ABS; 1216615Sbill } 1217615Sbill /* end inline expansion of symreloc() */ 1218615Sbill type = cursym.n_type; 1219898Sbill if (yflag && cursym.n_un.n_name) 1220898Sbill for (i = 0; i < yflag; i++) 1221898Sbill /* fast check for 2d character! */ 1222898Sbill if (ytab[i][1] == cursym.n_un.n_name[1] && 1223898Sbill !strcmp(ytab[i], cursym.n_un.n_name)) { 1224898Sbill tracesym(); 1225898Sbill break; 1226898Sbill } 1227615Sbill if ((type&N_EXT) == 0) { 1228615Sbill if (!sflag&&!xflag&& 1229615Sbill (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB)) 1230615Sbill symwrite(&cursym, sout); 1231615Sbill continue; 1232615Sbill } 1233615Sbill if (funding) 1234615Sbill continue; 1235615Sbill if ((sp = *lookup()) == 0) 1236615Sbill error(1, "internal error: symbol not found"); 1237615Sbill if (cursym.n_type == N_EXT+N_UNDF) { 1238615Sbill if (clocseg->lo_used == NSYMPR) { 1239615Sbill if (++clocseg == &locseg[NSEG]) 1240615Sbill error(1, "local symbol overflow"); 1241615Sbill clocseg->lo_used = 0; 1242615Sbill } 1243615Sbill if (clocseg->lo_first == 0) { 1244615Sbill clocseg->lo_first = (struct local *) 1245615Sbill malloc(NSYMPR * sizeof (struct local)); 1246615Sbill if (clocseg->lo_first == 0) 1247615Sbill error(1, "out of memory (clocseg)"); 1248615Sbill } 1249615Sbill lp = &clocseg->lo_first[clocseg->lo_used++]; 1250615Sbill lp->l_index = symno; 1251615Sbill lp->l_symbol = sp; 1252615Sbill lp->l_link = lochash[symno % LHSIZ]; 1253615Sbill lochash[symno % LHSIZ] = lp; 1254615Sbill continue; 1255615Sbill } 1256615Sbill if (cursym.n_type & N_STAB) 1257615Sbill continue; 1258615Sbill if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) { 1259615Sbill printf("%s: ", cursym.n_un.n_name); 1260615Sbill error(0, "multiply defined"); 1261615Sbill } 1262615Sbill } 1263615Sbill if (funding) 1264615Sbill return; 1265615Sbill dseek(&text, loc, filhdr.a_text); 1266615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize); 1267650Sbill load2td(ctrel, torigin - textbase, tout, trout); 1268615Sbill dseek(&text, loc+filhdr.a_text, filhdr.a_data); 1269615Sbill dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, 1270615Sbill filhdr.a_drsize); 1271650Sbill load2td(cdrel, dorigin - database, dout, drout); 1272615Sbill while (filhdr.a_data & (sizeof(long)-1)) { 1273615Sbill bputc(0, dout); 1274615Sbill filhdr.a_data++; 1275615Sbill } 1276615Sbill torigin += filhdr.a_text; 12771752Sbill dorigin += round(filhdr.a_data, sizeof (long)); 12781752Sbill borigin += round(filhdr.a_bss, sizeof (long)); 1279615Sbill free(curstr); 1280615Sbill } 1281615Sbill 1282898Sbill struct tynames { 1283898Sbill int ty_value; 1284898Sbill char *ty_name; 1285898Sbill } tynames[] = { 1286898Sbill N_UNDF, "undefined", 1287898Sbill N_ABS, "absolute", 1288898Sbill N_TEXT, "text", 1289898Sbill N_DATA, "data", 1290898Sbill N_BSS, "bss", 1291898Sbill N_COMM, "common", 1292898Sbill 0, 0, 1293898Sbill }; 1294898Sbill 1295898Sbill tracesym() 1296898Sbill { 1297898Sbill register struct tynames *tp; 1298898Sbill 1299898Sbill if (cursym.n_type & N_STAB) 1300898Sbill return; 1301898Sbill printf("%s", filname); 1302898Sbill if (archdr.ar_name[0]) 1303898Sbill printf("(%s)", archdr.ar_name); 1304898Sbill printf(": "); 1305898Sbill if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) { 1306898Sbill printf("definition of common %s size %d\n", 1307898Sbill cursym.n_un.n_name, cursym.n_value); 1308898Sbill return; 1309898Sbill } 1310898Sbill for (tp = tynames; tp->ty_name; tp++) 1311898Sbill if (tp->ty_value == (cursym.n_type&N_TYPE)) 1312898Sbill break; 1313898Sbill printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to"); 1314898Sbill if (cursym.n_type&N_EXT) 1315898Sbill printf(" external"); 1316898Sbill if (tp->ty_name) 1317898Sbill printf(" %s", tp->ty_name); 1318898Sbill printf(" %s\n", cursym.n_un.n_name); 1319898Sbill } 1320898Sbill 132129845Ssam #if !defined(tahoe) 132229845Ssam /* for machines which allow arbitrarily aligned word and longword accesses */ 1323*46419Sbostic #define getword(cp) (*(short *)(cp)) 132429845Ssam #define getl(cp) (*(long *)(cp)) 132529845Ssam #define putw(cp, w) (*(short *)(cp) = (w)) 132629845Ssam #define putl(cp, l) (*(long *)(cp) = (l)) 132729845Ssam #else 132829845Ssam short 1329*46419Sbostic getword(cp) 133029845Ssam char *cp; 133129845Ssam { 133229845Ssam union { 133329845Ssam short w; 133429845Ssam char c[2]; 133529845Ssam } w; 133629845Ssam 133729845Ssam w.c[0] = *cp++; 133829845Ssam w.c[1] = *cp++; 133929845Ssam return (w.w); 134029845Ssam } 134129845Ssam 134229845Ssam getl(cp) 134329845Ssam char *cp; 134429845Ssam { 134529845Ssam union { 134629845Ssam long l; 134729845Ssam char c[4]; 134829845Ssam } l; 134929845Ssam 135029845Ssam l.c[0] = *cp++; 135129845Ssam l.c[1] = *cp++; 135229845Ssam l.c[2] = *cp++; 135329845Ssam l.c[3] = *cp++; 135429845Ssam return (l.l); 135529845Ssam } 135629845Ssam 135729845Ssam putw(cp, v) 135829845Ssam char *cp; 135929845Ssam short v; 136029845Ssam { 136129845Ssam union { 136229845Ssam short w; 136329845Ssam char c[2]; 136429845Ssam } w; 136529845Ssam 136629845Ssam w.w = v; 136729845Ssam *cp++ = w.c[0]; 136829845Ssam *cp++ = w.c[1]; 136929845Ssam } 137029845Ssam 137129845Ssam putl(cp, v) 137229845Ssam char *cp; 137329845Ssam long v; 137429845Ssam { 137529845Ssam union { 137629845Ssam long l; 137729845Ssam char c[4]; 137829845Ssam } l; 137929845Ssam 138029845Ssam l.l = v; 138129845Ssam *cp++ = l.c[0]; 138229845Ssam *cp++ = l.c[1]; 138329845Ssam *cp++ = l.c[2]; 138429845Ssam *cp++ = l.c[3]; 138529845Ssam } 138629845Ssam #endif 138729845Ssam 1388650Sbill /* 1389650Sbill * This routine relocates the single text or data segment argument. 1390650Sbill * Offsets from external symbols are resolved by adding the value 1391650Sbill * of the external symbols. Non-external reference are updated to account 1392650Sbill * for the relative motion of the segments (ctrel, cdrel, ...). If 1393650Sbill * a relocation was pc-relative, then we update it to reflect the 1394650Sbill * change in the positioning of the segments by adding the displacement 1395650Sbill * of the referenced segment and subtracting the displacement of the 1396650Sbill * current segment (creloc). 1397650Sbill * 1398650Sbill * If we are saving the relocation information, then we increase 1399650Sbill * each relocation datum address by our base position in the new segment. 1400650Sbill */ 1401650Sbill load2td(creloc, position, b1, b2) 140230647Slepreau long creloc, position; 1403615Sbill struct biobuf *b1, *b2; 1404615Sbill { 1405615Sbill register struct nlist *sp; 1406615Sbill register struct local *lp; 1407615Sbill long tw; 1408615Sbill register struct relocation_info *rp, *rpend; 1409615Sbill struct relocation_info *relp; 1410615Sbill char *codep; 1411615Sbill register char *cp; 1412615Sbill int relsz, codesz; 1413615Sbill 1414615Sbill relsz = reloc.size; 1415615Sbill relp = (struct relocation_info *)malloc(relsz); 1416615Sbill codesz = text.size; 1417615Sbill codep = (char *)malloc(codesz); 1418615Sbill if (relp == 0 || codep == 0) 1419615Sbill error(1, "out of memory (load2td)"); 1420615Sbill mget((char *)relp, relsz, &reloc); 1421615Sbill rpend = &relp[relsz / sizeof (struct relocation_info)]; 1422615Sbill mget(codep, codesz, &text); 1423615Sbill for (rp = relp; rp < rpend; rp++) { 1424615Sbill cp = codep + rp->r_address; 1425650Sbill /* 1426650Sbill * Pick up previous value at location to be relocated. 1427650Sbill */ 1428615Sbill switch (rp->r_length) { 1429615Sbill 1430615Sbill case 0: /* byte */ 1431615Sbill tw = *cp; 1432615Sbill break; 1433615Sbill 1434615Sbill case 1: /* word */ 1435*46419Sbostic tw = getword(cp); 1436615Sbill break; 1437615Sbill 1438615Sbill case 2: /* long */ 143929845Ssam tw = getl(cp); 1440615Sbill break; 1441615Sbill 1442615Sbill default: 1443615Sbill error(1, "load2td botch: bad length"); 1444615Sbill } 1445650Sbill /* 1446650Sbill * If relative to an external which is defined, 1447650Sbill * resolve to a simpler kind of reference in the 1448650Sbill * result file. If the external is undefined, just 1449650Sbill * convert the symbol number to the number of the 1450650Sbill * symbol in the result file and leave it undefined. 1451650Sbill */ 1452615Sbill if (rp->r_extern) { 1453650Sbill /* 1454650Sbill * Search the hash table which maps local 1455650Sbill * symbol numbers to symbol tables entries 1456650Sbill * in the new a.out file. 1457650Sbill */ 1458615Sbill lp = lochash[rp->r_symbolnum % LHSIZ]; 1459615Sbill while (lp->l_index != rp->r_symbolnum) { 1460615Sbill lp = lp->l_link; 1461615Sbill if (lp == 0) 1462615Sbill error(1, "local symbol botch"); 1463615Sbill } 1464615Sbill sp = lp->l_symbol; 1465615Sbill if (sp->n_type == N_EXT+N_UNDF) 1466615Sbill rp->r_symbolnum = nsym+symx(sp); 1467615Sbill else { 1468615Sbill rp->r_symbolnum = sp->n_type & N_TYPE; 1469615Sbill tw += sp->n_value; 1470615Sbill rp->r_extern = 0; 1471615Sbill } 1472615Sbill } else switch (rp->r_symbolnum & N_TYPE) { 1473650Sbill /* 1474650Sbill * Relocation is relative to the loaded position 1475650Sbill * of another segment. Update by the change in position 1476650Sbill * of that segment. 1477650Sbill */ 1478615Sbill case N_TEXT: 1479615Sbill tw += ctrel; 1480615Sbill break; 1481615Sbill case N_DATA: 1482615Sbill tw += cdrel; 1483615Sbill break; 1484615Sbill case N_BSS: 1485615Sbill tw += cbrel; 1486615Sbill break; 1487615Sbill case N_ABS: 1488615Sbill break; 1489615Sbill default: 1490615Sbill error(1, "relocation format botch (symbol type))"); 1491615Sbill } 1492650Sbill /* 1493650Sbill * Relocation is pc relative, so decrease the relocation 1494650Sbill * by the amount the current segment is displaced. 1495650Sbill * (E.g if we are a relative reference to a text location 1496650Sbill * from data space, we added the increase in the text address 1497650Sbill * above, and subtract the increase in our (data) address 1498650Sbill * here, leaving the net change the relative change in the 1499650Sbill * positioning of our text and data segments.) 1500650Sbill */ 1501615Sbill if (rp->r_pcrel) 1502615Sbill tw -= creloc; 1503650Sbill /* 1504650Sbill * Put the value back in the segment, 1505650Sbill * while checking for overflow. 1506650Sbill */ 1507615Sbill switch (rp->r_length) { 1508615Sbill 1509615Sbill case 0: /* byte */ 1510615Sbill if (tw < -128 || tw > 127) 1511615Sbill error(0, "byte displacement overflow"); 1512615Sbill *cp = tw; 1513615Sbill break; 1514615Sbill case 1: /* word */ 1515615Sbill if (tw < -32768 || tw > 32767) 1516615Sbill error(0, "word displacement overflow"); 151729845Ssam putw(cp, tw); 1518615Sbill break; 1519615Sbill case 2: /* long */ 152029845Ssam putl(cp, tw); 1521615Sbill break; 1522615Sbill } 1523650Sbill /* 1524650Sbill * If we are saving relocation information, 1525650Sbill * we must convert the address in the segment from 1526650Sbill * the old .o file into an address in the segment in 1527650Sbill * the new a.out, by adding the position of our 1528650Sbill * segment in the new larger segment. 1529650Sbill */ 1530615Sbill if (rflag) 1531650Sbill rp->r_address += position; 1532615Sbill } 1533615Sbill bwrite(codep, codesz, b1); 1534615Sbill if (rflag) 1535615Sbill bwrite(relp, relsz, b2); 153625483Slepreau free((char *)relp); 153725483Slepreau free(codep); 1538615Sbill } 1539615Sbill 1540615Sbill finishout() 1541615Sbill { 1542615Sbill register int i; 1543615Sbill int nsymt; 1544615Sbill 1545615Sbill if (sflag==0) { 1546615Sbill nsymt = symx(nextsym); 1547615Sbill for (i = 0; i < nsymt; i++) 1548615Sbill symwrite(xsym(i), sout); 1549615Sbill bwrite(&offset, sizeof offset, sout); 1550615Sbill } 1551615Sbill if (!ofilfnd) { 155244768Sbostic unlink("a.out"); 155344768Sbostic if (link("l.out", "a.out") < 0) 1554898Sbill error(1, "cannot move l.out to a.out"); 155544768Sbostic ofilename = "a.out"; 1556615Sbill } 1557615Sbill delarg = errlev; 1558615Sbill delexit(); 1559615Sbill } 1560615Sbill 1561615Sbill mkfsym(s) 1562615Sbill char *s; 1563615Sbill { 1564615Sbill 1565615Sbill if (sflag || xflag) 1566615Sbill return; 1567615Sbill cursym.n_un.n_name = s; 156830836Sbostic cursym.n_type = N_EXT | N_FN; 1569615Sbill cursym.n_value = torigin; 1570615Sbill symwrite(&cursym, sout); 1571615Sbill } 1572615Sbill 1573615Sbill getarhdr() 1574615Sbill { 1575615Sbill register char *cp; 1576615Sbill 1577615Sbill mget((char *)&archdr, sizeof archdr, &text); 1578615Sbill for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];) 1579615Sbill if (*cp++ == ' ') { 1580615Sbill cp[-1] = 0; 1581615Sbill return; 1582615Sbill } 1583615Sbill } 1584615Sbill 1585615Sbill mget(loc, n, sp) 1586615Sbill register STREAM *sp; 1587615Sbill register char *loc; 1588615Sbill { 1589615Sbill register char *p; 1590615Sbill register int take; 1591615Sbill 1592615Sbill top: 1593615Sbill if (n == 0) 1594615Sbill return; 1595615Sbill if (sp->size && sp->nibuf) { 1596615Sbill p = sp->ptr; 1597615Sbill take = sp->size; 1598615Sbill if (take > sp->nibuf) 1599615Sbill take = sp->nibuf; 1600615Sbill if (take > n) 1601615Sbill take = n; 1602615Sbill n -= take; 1603615Sbill sp->size -= take; 1604615Sbill sp->nibuf -= take; 1605615Sbill sp->pos += take; 1606615Sbill do 1607615Sbill *loc++ = *p++; 1608615Sbill while (--take > 0); 1609615Sbill sp->ptr = p; 1610615Sbill goto top; 1611615Sbill } 161216068Sralph if (n > p_blksize) { 161316068Sralph take = n - n % p_blksize; 161416068Sralph lseek(infil, (sp->bno+1)<<p_blkshift, 0); 1615615Sbill if (take > sp->size || read(infil, loc, take) != take) 1616615Sbill error(1, "premature EOF"); 1617615Sbill loc += take; 1618615Sbill n -= take; 1619615Sbill sp->size -= take; 1620615Sbill sp->pos += take; 162116068Sralph dseek(sp, (sp->bno+1+(take>>p_blkshift))<<p_blkshift, -1); 1622615Sbill goto top; 1623615Sbill } 1624615Sbill *loc++ = get(sp); 1625615Sbill --n; 1626615Sbill goto top; 1627615Sbill } 1628615Sbill 1629615Sbill symwrite(sp, bp) 1630615Sbill struct nlist *sp; 1631615Sbill struct biobuf *bp; 1632615Sbill { 1633615Sbill register int len; 1634615Sbill register char *str; 1635615Sbill 1636615Sbill str = sp->n_un.n_name; 1637615Sbill if (str) { 1638615Sbill sp->n_un.n_strx = offset; 1639615Sbill len = strlen(str) + 1; 1640615Sbill bwrite(str, len, strout); 1641615Sbill offset += len; 1642615Sbill } 1643615Sbill bwrite(sp, sizeof (*sp), bp); 1644615Sbill sp->n_un.n_name = str; 1645615Sbill } 1646615Sbill 1647615Sbill dseek(sp, loc, s) 1648615Sbill register STREAM *sp; 1649615Sbill long loc, s; 1650615Sbill { 1651615Sbill register PAGE *p; 1652615Sbill register b, o; 1653615Sbill int n; 1654615Sbill 165516068Sralph b = loc>>p_blkshift; 165616068Sralph o = loc&p_blkmask; 1657615Sbill if (o&01) 1658615Sbill error(1, "loader error; odd offset"); 1659615Sbill --sp->pno->nuser; 1660615Sbill if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b) 1661615Sbill if (p->nuser==0 || (p = &page[0])->nuser==0) { 1662615Sbill if (page[0].nuser==0 && page[1].nuser==0) 1663615Sbill if (page[0].bno < page[1].bno) 1664615Sbill p = &page[0]; 1665615Sbill p->bno = b; 166616068Sralph lseek(infil, loc & ~(long)p_blkmask, 0); 166716068Sralph if ((n = read(infil, p->buff, p_blksize)) < 0) 1668615Sbill n = 0; 1669615Sbill p->nibuf = n; 167016068Sralph } else 167116068Sralph error(1, "botch: no pages"); 1672615Sbill ++p->nuser; 1673615Sbill sp->bno = b; 1674615Sbill sp->pno = p; 1675615Sbill if (s != -1) {sp->size = s; sp->pos = 0;} 1676615Sbill sp->ptr = (char *)(p->buff + o); 1677615Sbill if ((sp->nibuf = p->nibuf-o) <= 0) 1678615Sbill sp->size = 0; 1679615Sbill } 1680615Sbill 1681615Sbill char 1682615Sbill get(asp) 1683615Sbill STREAM *asp; 1684615Sbill { 1685615Sbill register STREAM *sp; 1686615Sbill 1687615Sbill sp = asp; 1688615Sbill if ((sp->nibuf -= sizeof(char)) < 0) { 168916068Sralph dseek(sp, ((long)(sp->bno+1)<<p_blkshift), (long)-1); 1690615Sbill sp->nibuf -= sizeof(char); 1691615Sbill } 1692615Sbill if ((sp->size -= sizeof(char)) <= 0) { 1693615Sbill if (sp->size < 0) 1694615Sbill error(1, "premature EOF"); 1695615Sbill ++fpage.nuser; 1696615Sbill --sp->pno->nuser; 1697615Sbill sp->pno = (PAGE *) &fpage; 1698615Sbill } 1699615Sbill sp->pos += sizeof(char); 1700615Sbill return(*sp->ptr++); 1701615Sbill } 1702615Sbill 1703615Sbill getfile(acp) 1704615Sbill char *acp; 1705615Sbill { 1706615Sbill register int c; 1707615Sbill char arcmag[SARMAG+1]; 1708615Sbill struct stat stb; 1709615Sbill 1710615Sbill archdr.ar_name[0] = '\0'; 171117133Ssam filname = acp; 171217133Ssam if (filname[0] == '-' && filname[1] == 'l') 171317133Ssam infil = libopen(filname + 2, O_RDONLY); 171417133Ssam else 171544768Sbostic infil = open(filname, O_RDONLY); 171617133Ssam if (infil < 0) 1717615Sbill error(1, "cannot open"); 171816068Sralph fstat(infil, &stb); 1719615Sbill page[0].bno = page[1].bno = -1; 1720615Sbill page[0].nuser = page[1].nuser = 0; 172116068Sralph c = stb.st_blksize; 172216068Sralph if (c == 0 || (c & (c - 1)) != 0) { 172316068Sralph /* use default size if not a power of two */ 172416068Sralph c = BLKSIZE; 172516068Sralph } 172616068Sralph if (p_blksize != c) { 172716068Sralph p_blksize = c; 172816068Sralph p_blkmask = c - 1; 172916068Sralph for (p_blkshift = 0; c > 1 ; p_blkshift++) 173016068Sralph c >>= 1; 173116068Sralph if (page[0].buff != NULL) 173216068Sralph free(page[0].buff); 173316068Sralph page[0].buff = (char *)malloc(p_blksize); 173416068Sralph if (page[0].buff == NULL) 173516068Sralph error(1, "ran out of memory (getfile)"); 173616068Sralph if (page[1].buff != NULL) 173716068Sralph free(page[1].buff); 173816068Sralph page[1].buff = (char *)malloc(p_blksize); 173916068Sralph if (page[1].buff == NULL) 174016068Sralph error(1, "ran out of memory (getfile)"); 174116068Sralph } 1742615Sbill text.pno = reloc.pno = (PAGE *) &fpage; 1743615Sbill fpage.nuser = 2; 1744615Sbill dseek(&text, 0L, SARMAG); 1745615Sbill if (text.size <= 0) 1746615Sbill error(1, "premature EOF"); 1747615Sbill mget((char *)arcmag, SARMAG, &text); 1748615Sbill arcmag[SARMAG] = 0; 1749615Sbill if (strcmp(arcmag, ARMAG)) 1750615Sbill return (0); 1751615Sbill dseek(&text, SARMAG, sizeof archdr); 175217133Ssam if (text.size <= 0) 1753615Sbill return (1); 1754615Sbill getarhdr(); 175530828Sbostic if (strncmp(archdr.ar_name, RANLIBMAG, sizeof(archdr.ar_name)) != 0) 1756615Sbill return (1); 1757615Sbill return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2); 1758615Sbill } 1759615Sbill 176017133Ssam /* 176117133Ssam * Search for a library with given name 176217133Ssam * using the directory search array. 176317133Ssam */ 176417133Ssam libopen(name, oflags) 176517133Ssam char *name; 176617133Ssam int oflags; 176717133Ssam { 176817133Ssam register char *p, *cp; 176917133Ssam register int i; 177017133Ssam static char buf[MAXPATHLEN+1]; 177117133Ssam int fd = -1; 177217133Ssam 177317133Ssam if (*name == '\0') /* backwards compat */ 177417133Ssam name = "a"; 177517133Ssam for (i = 0; i < ndir && fd == -1; i++) { 177617133Ssam p = buf; 177717133Ssam for (cp = dirs[i]; *cp; *p++ = *cp++) 177817133Ssam ; 177917133Ssam *p++ = '/'; 178017133Ssam for (cp = "lib"; *cp; *p++ = *cp++) 178117133Ssam ; 178217133Ssam for (cp = name; *cp; *p++ = *cp++) 178317133Ssam ; 178417133Ssam cp = ".a"; 178517133Ssam while (*p++ = *cp++) 178617133Ssam ; 178717133Ssam fd = open(buf, oflags); 178817133Ssam } 178917133Ssam if (fd != -1) 179017133Ssam filname = buf; 179117133Ssam return (fd); 179217133Ssam } 179317133Ssam 1794615Sbill struct nlist ** 1795615Sbill lookup() 1796615Sbill { 1797615Sbill register int sh; 1798615Sbill register struct nlist **hp; 1799615Sbill register char *cp, *cp1; 1800615Sbill register struct symseg *gp; 1801615Sbill register int i; 1802615Sbill 1803615Sbill sh = 0; 1804615Sbill for (cp = cursym.n_un.n_name; *cp;) 1805615Sbill sh = (sh<<1) + *cp++; 1806615Sbill sh = (sh & 0x7fffffff) % HSIZE; 1807615Sbill for (gp = symseg; gp < &symseg[NSEG]; gp++) { 1808615Sbill if (gp->sy_first == 0) { 1809615Sbill gp->sy_first = (struct nlist *) 1810615Sbill calloc(NSYM, sizeof (struct nlist)); 1811615Sbill gp->sy_hfirst = (struct nlist **) 1812615Sbill calloc(HSIZE, sizeof (struct nlist *)); 1813615Sbill if (gp->sy_first == 0 || gp->sy_hfirst == 0) 1814615Sbill error(1, "ran out of space for symbol table"); 1815615Sbill gp->sy_last = gp->sy_first + NSYM; 1816615Sbill gp->sy_hlast = gp->sy_hfirst + HSIZE; 1817615Sbill } 1818615Sbill if (gp > csymseg) 1819615Sbill csymseg = gp; 1820615Sbill hp = gp->sy_hfirst + sh; 1821615Sbill i = 1; 1822615Sbill do { 1823615Sbill if (*hp == 0) { 1824615Sbill if (gp->sy_used == NSYM) 1825615Sbill break; 1826615Sbill return (hp); 1827615Sbill } 1828615Sbill cp1 = (*hp)->n_un.n_name; 1829615Sbill for (cp = cursym.n_un.n_name; *cp == *cp1++;) 1830615Sbill if (*cp++ == 0) 1831615Sbill return (hp); 1832615Sbill hp += i; 1833615Sbill i += 2; 1834615Sbill if (hp >= gp->sy_hlast) 1835615Sbill hp -= HSIZE; 1836615Sbill } while (i < HSIZE); 1837615Sbill if (i > HSIZE) 1838615Sbill error(1, "hash table botch"); 1839615Sbill } 1840615Sbill error(1, "symbol table overflow"); 1841615Sbill /*NOTREACHED*/ 1842615Sbill } 1843615Sbill 1844615Sbill symfree(saved) 1845615Sbill struct nlist *saved; 1846615Sbill { 1847615Sbill register struct symseg *gp; 1848615Sbill register struct nlist *sp; 1849615Sbill 1850615Sbill for (gp = csymseg; gp >= symseg; gp--, csymseg--) { 1851615Sbill sp = gp->sy_first + gp->sy_used; 1852615Sbill if (sp == saved) { 1853615Sbill nextsym = sp; 1854615Sbill return; 1855615Sbill } 1856615Sbill for (sp--; sp >= gp->sy_first; sp--) { 1857615Sbill gp->sy_hfirst[sp->n_hash] = 0; 1858615Sbill gp->sy_used--; 1859615Sbill if (sp == saved) { 1860615Sbill nextsym = sp; 1861615Sbill return; 1862615Sbill } 1863615Sbill } 1864615Sbill } 1865615Sbill if (saved == 0) 1866615Sbill return; 1867615Sbill error(1, "symfree botch"); 1868615Sbill } 1869615Sbill 1870615Sbill struct nlist ** 1871615Sbill slookup(s) 1872615Sbill char *s; 1873615Sbill { 1874615Sbill 1875615Sbill cursym.n_un.n_name = s; 1876615Sbill cursym.n_type = N_EXT+N_UNDF; 1877615Sbill cursym.n_value = 0; 1878615Sbill return (lookup()); 1879615Sbill } 1880615Sbill 1881615Sbill enter(hp) 1882615Sbill register struct nlist **hp; 1883615Sbill { 1884615Sbill register struct nlist *sp; 1885615Sbill 1886615Sbill if (*hp==0) { 1887615Sbill if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast) 1888615Sbill error(1, "enter botch"); 1889615Sbill *hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used; 1890615Sbill csymseg->sy_used++; 1891615Sbill sp->n_un.n_name = cursym.n_un.n_name; 1892615Sbill sp->n_type = cursym.n_type; 1893615Sbill sp->n_hash = hp - csymseg->sy_hfirst; 1894615Sbill sp->n_value = cursym.n_value; 1895615Sbill nextsym = lastsym + 1; 1896615Sbill return(1); 1897615Sbill } else { 1898615Sbill lastsym = *hp; 1899615Sbill return(0); 1900615Sbill } 1901615Sbill } 1902615Sbill 1903615Sbill symx(sp) 1904615Sbill struct nlist *sp; 1905615Sbill { 1906615Sbill register struct symseg *gp; 1907615Sbill 1908615Sbill if (sp == 0) 1909615Sbill return (0); 1910615Sbill for (gp = csymseg; gp >= symseg; gp--) 1911615Sbill /* <= is sloppy so nextsym will always work */ 1912615Sbill if (sp >= gp->sy_first && sp <= gp->sy_last) 1913615Sbill return ((gp - symseg) * NSYM + sp - gp->sy_first); 1914615Sbill error(1, "symx botch"); 1915615Sbill /*NOTREACHED*/ 1916615Sbill } 1917615Sbill 1918615Sbill symreloc() 1919615Sbill { 1920615Sbill if(funding) return; 1921615Sbill switch (cursym.n_type & 017) { 1922615Sbill 1923615Sbill case N_TEXT: 1924615Sbill case N_EXT+N_TEXT: 1925615Sbill cursym.n_value += ctrel; 1926615Sbill return; 1927615Sbill 1928615Sbill case N_DATA: 1929615Sbill case N_EXT+N_DATA: 1930615Sbill cursym.n_value += cdrel; 1931615Sbill return; 1932615Sbill 1933615Sbill case N_BSS: 1934615Sbill case N_EXT+N_BSS: 1935615Sbill cursym.n_value += cbrel; 1936615Sbill return; 1937615Sbill 1938615Sbill case N_EXT+N_UNDF: 1939615Sbill return; 1940615Sbill 1941615Sbill default: 1942615Sbill if (cursym.n_type&N_EXT) 1943615Sbill cursym.n_type = N_EXT+N_ABS; 1944615Sbill return; 1945615Sbill } 1946615Sbill } 1947615Sbill 1948615Sbill error(n, s) 1949615Sbill char *s; 1950615Sbill { 1951898Sbill 1952615Sbill if (errlev==0) 1953615Sbill printf("ld:"); 1954615Sbill if (filname) { 1955615Sbill printf("%s", filname); 1956615Sbill if (n != -1 && archdr.ar_name[0]) 1957615Sbill printf("(%s)", archdr.ar_name); 1958615Sbill printf(": "); 1959615Sbill } 1960615Sbill printf("%s\n", s); 1961615Sbill if (n == -1) 1962615Sbill return; 1963615Sbill if (n) 1964615Sbill delexit(); 1965615Sbill errlev = 2; 1966615Sbill } 1967615Sbill 1968615Sbill readhdr(loc) 1969615Sbill off_t loc; 1970615Sbill { 1971615Sbill 1972615Sbill dseek(&text, loc, (long)sizeof(filhdr)); 1973615Sbill mget((short *)&filhdr, sizeof(filhdr), &text); 1974615Sbill if (N_BADMAG(filhdr)) { 1975615Sbill if (filhdr.a_magic == OARMAG) 1976615Sbill error(1, "old archive"); 1977615Sbill error(1, "bad magic number"); 1978615Sbill } 1979615Sbill if (filhdr.a_text&01 || filhdr.a_data&01) 1980615Sbill error(1, "text/data size odd"); 1981615Sbill if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) { 198212671Ssam cdrel = -round(filhdr.a_text, pagesize); 1983615Sbill cbrel = cdrel - filhdr.a_data; 1984615Sbill } else if (filhdr.a_magic == OMAGIC) { 1985615Sbill cdrel = -filhdr.a_text; 1986615Sbill cbrel = cdrel - filhdr.a_data; 1987615Sbill } else 1988615Sbill error(1, "bad format"); 1989615Sbill } 1990615Sbill 1991615Sbill round(v, r) 1992615Sbill int v; 1993615Sbill u_long r; 1994615Sbill { 1995615Sbill 1996615Sbill r--; 1997615Sbill v += r; 1998615Sbill v &= ~(long)r; 1999615Sbill return(v); 2000615Sbill } 2001615Sbill 2002615Sbill #define NSAVETAB 8192 2003615Sbill char *savetab; 2004615Sbill int saveleft; 2005615Sbill 2006615Sbill char * 2007615Sbill savestr(cp) 2008615Sbill register char *cp; 2009615Sbill { 2010615Sbill register int len; 2011615Sbill 2012615Sbill len = strlen(cp) + 1; 2013615Sbill if (len > saveleft) { 2014615Sbill saveleft = NSAVETAB; 2015615Sbill if (len > saveleft) 2016615Sbill saveleft = len; 201717133Ssam savetab = malloc(saveleft); 2018615Sbill if (savetab == 0) 2019615Sbill error(1, "ran out of memory (savestr)"); 2020615Sbill } 2021615Sbill strncpy(savetab, cp, len); 2022615Sbill cp = savetab; 2023615Sbill savetab += len; 2024615Sbill saveleft -= len; 2025615Sbill return (cp); 2026615Sbill } 2027615Sbill 202816068Sralph bopen(bp, off, bufsize) 202916068Sralph register struct biobuf *bp; 2030615Sbill { 2031615Sbill 203217133Ssam bp->b_ptr = bp->b_buf = malloc(bufsize); 203316068Sralph if (bp->b_ptr == (char *)0) 203416068Sralph error(1, "ran out of memory (bopen)"); 203516068Sralph bp->b_bufsize = bufsize; 203616068Sralph bp->b_nleft = bufsize - (off % bufsize); 2037615Sbill bp->b_off = off; 2038615Sbill bp->b_link = biobufs; 2039615Sbill biobufs = bp; 2040615Sbill } 2041615Sbill 2042615Sbill int bwrerror; 2043615Sbill 2044615Sbill bwrite(p, cnt, bp) 2045615Sbill register char *p; 2046615Sbill register int cnt; 2047615Sbill register struct biobuf *bp; 2048615Sbill { 2049615Sbill register int put; 2050615Sbill register char *to; 2051615Sbill 2052615Sbill top: 2053615Sbill if (cnt == 0) 2054615Sbill return; 2055615Sbill if (bp->b_nleft) { 2056615Sbill put = bp->b_nleft; 2057615Sbill if (put > cnt) 2058615Sbill put = cnt; 2059615Sbill bp->b_nleft -= put; 2060615Sbill to = bp->b_ptr; 206125419Sbloom bcopy(p, to, put); 2062615Sbill bp->b_ptr += put; 2063615Sbill p += put; 2064615Sbill cnt -= put; 2065615Sbill goto top; 2066615Sbill } 206716068Sralph if (cnt >= bp->b_bufsize) { 2068615Sbill if (bp->b_ptr != bp->b_buf) 2069615Sbill bflush1(bp); 207016068Sralph put = cnt - cnt % bp->b_bufsize; 2071615Sbill if (boffset != bp->b_off) 2072615Sbill lseek(biofd, bp->b_off, 0); 2073615Sbill if (write(biofd, p, put) != put) { 2074615Sbill bwrerror = 1; 2075615Sbill error(1, "output write error"); 2076615Sbill } 2077615Sbill bp->b_off += put; 2078615Sbill boffset = bp->b_off; 2079615Sbill p += put; 2080615Sbill cnt -= put; 2081615Sbill goto top; 2082615Sbill } 2083615Sbill bflush1(bp); 2084615Sbill goto top; 2085615Sbill } 2086615Sbill 2087615Sbill bflush() 2088615Sbill { 2089615Sbill register struct biobuf *bp; 2090615Sbill 2091615Sbill if (bwrerror) 2092615Sbill return; 2093615Sbill for (bp = biobufs; bp; bp = bp->b_link) 2094615Sbill bflush1(bp); 2095615Sbill } 2096615Sbill 2097615Sbill bflush1(bp) 2098615Sbill register struct biobuf *bp; 2099615Sbill { 2100615Sbill register int cnt = bp->b_ptr - bp->b_buf; 2101615Sbill 2102615Sbill if (cnt == 0) 2103615Sbill return; 2104615Sbill if (boffset != bp->b_off) 2105615Sbill lseek(biofd, bp->b_off, 0); 2106615Sbill if (write(biofd, bp->b_buf, cnt) != cnt) { 2107615Sbill bwrerror = 1; 2108615Sbill error(1, "output write error"); 2109615Sbill } 2110615Sbill bp->b_off += cnt; 2111615Sbill boffset = bp->b_off; 2112615Sbill bp->b_ptr = bp->b_buf; 211316068Sralph bp->b_nleft = bp->b_bufsize; 2114615Sbill } 2115615Sbill 2116615Sbill bflushc(bp, c) 2117615Sbill register struct biobuf *bp; 2118615Sbill { 2119615Sbill 2120615Sbill bflush1(bp); 2121615Sbill bputc(c, bp); 2122615Sbill } 212316068Sralph 212416068Sralph bseek(bp, off) 212516068Sralph register struct biobuf *bp; 212616068Sralph register off_t off; 212716068Sralph { 212816068Sralph bflush1(bp); 212916068Sralph 213016068Sralph bp->b_nleft = bp->b_bufsize - (off % bp->b_bufsize); 213116068Sralph bp->b_off = off; 213216068Sralph } 2133