Readable version of argument access types and mask
[unix-history] / usr / src / old / ld / ld.c
CommitLineData
537f7e17 1static char sccsid[] = "@(#)ld.c 3.2 %G%";
c4e4978a
BJ
2/*
3 * VAX VM/UNIX ld - string table version
4 */
5
6#include <sys/types.h>
7#include <signal.h>
8#include <stdio.h>
9#include <ctype.h>
537f7e17
BJ
10#include <ar.h>
11#include <a.out.h>
c4e4978a
BJ
12#include <ranlib.h>
13#include <stat.h>
14#include <pagsiz.h>
15
16/*
17 * Basic strategy:
18 *
19 * The loader takes a number of files and libraries as arguments.
20 * A first pass examines each file in turn. Normal files are
21 * unconditionally loaded, and the (external) symbols they define and require
22 * are noted in the symbol table. Libraries are searched, and the
23 * library members which define needed symbols are remembered
24 * in a special data structure so they can be selected on the second
25 * pass. Symbols defined and required by library members are also
26 * recorded.
27 *
28 * After the first pass, the loader knows the size of the basic text
29 * data, and bss segments from the sum of the sizes of the modules which
30 * were required. It has computed, for each ``common'' symbol, the
31 * maximum size of any reference to it, and these symbols are then assigned
32 * storage locations after their sizes are appropriately rounded.
33 * The loader now knows all sizes for the eventual output file, and
34 * can determine the final locations of external symbols before it
35 * begins a second pass.
36 *
37 * On the second pass each normal file and required library member
38 * is processed again. The symbol table for each such file is
39 * reread and relevant parts of it are placed in the output. The offsets
40 * in the local symbol table for externally defined symbols are recorded
41 * since relocation information refers to symbols in this way.
42 * Armed with all necessary information, the text and data segments
43 * are relocated and the result is placed in the output file, which
44 * is pasted together, ``in place'', by writing to it in several
45 * different places concurrently.
46 */
47
48/*
49 * Internal data structures
50 *
51 * All internal data structures are segmented and dynamically extended.
52 * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT)
53 * referenced library members, and 100 (NSYMPR) private (local) symbols
54 * per object module. For large programs and/or modules, these structures
55 * expand to be up to 40 (NSEG) times as large as this as necessary.
56 */
57#define NSEG 40 /* Number of segments, each data structure */
58#define NSYM 1103 /* Number of symbols per segment */
59#define NROUT 250 /* Number of library references per segment */
60#define NSYMPR 100 /* Number of private symbols per segment */
61
62/*
63 * Structure describing each symbol table segment.
64 * Each segment has its own hash table. We record the first
65 * address in and first address beyond both the symbol and hash
66 * tables, for use in the routine symx and the lookup routine respectively.
67 * The symfree routine also understands this structure well as it used
68 * to back out symbols from modules we decide that we don't need in pass 1.
69 *
70 * Csymseg points to the current symbol table segment;
71 * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated,
72 * (unless csymseg->sy_used == NSYM in which case we will allocate another
73 * symbol table segment first.)
74 */
75struct symseg {
76 struct nlist *sy_first; /* base of this alloc'ed segment */
77 struct nlist *sy_last; /* end of this segment, for n_strx */
78 int sy_used; /* symbols used in this seg */
79 struct nlist **sy_hfirst; /* base of hash table, this seg */
80 struct nlist **sy_hlast; /* end of hash table, this seg */
81} symseg[NSEG], *csymseg;
82
83/*
84 * The lookup routine uses quadratic rehash. Since a quadratic rehash
85 * only probes 1/2 of the buckets in the table, and since the hash
86 * table is segmented the same way the symbol table is, we make the
87 * hash table have twice as many buckets as there are symbol table slots
88 * in the segment. This guarantees that the quadratic rehash will never
89 * fail to find an empty bucket if the segment is not full and the
90 * symbol is not there.
91 */
92#define HSIZE (NSYM*2)
93
94/*
95 * Xsym converts symbol table indices (ala x) into symbol table pointers.
96 * Symx (harder, but never used in loops) inverts pointers into the symbol
97 * table into indices using the symseg[] structure.
98 */
99#define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM))
100/* symx() is a function, defined below */
101
102struct nlist cursym; /* current symbol */
103struct nlist *lastsym; /* last symbol entered */
104struct nlist *nextsym; /* next available symbol table entry */
105struct nlist *addsym; /* first sym defined during incr load */
106int nsym; /* pass2: number of local symbols in a.out */
107/* nsym + symx(nextsym) is the symbol table size during pass2 */
108
109struct nlist **lookup(), **slookup();
537f7e17 110struct nlist *p_etext, *p_edata, *p_end, *entrypt;
c4e4978a
BJ
111
112/*
113 * Definitions of segmentation for library member table.
114 * For each library we encounter on pass 1 we record pointers to all
115 * members which we will load on pass 2. These are recorded as offsets
116 * into the archive in the library member table. Libraries are
117 * separated in the table by the special offset value -1.
118 */
119off_t li_init[NROUT];
120struct libseg {
121 off_t *li_first;
122 int li_used;
123 int li_used2;
124} libseg[NSEG] = {
125 li_init, 0, 0,
126}, *clibseg = libseg;
127
128/*
129 * In processing each module on pass 2 we must relocate references
130 * relative to external symbols. These references are recorded
131 * in the relocation information as relative to local symbol numbers
132 * assigned to the external symbols when the module was created.
133 * Thus before relocating the module in pass 2 we create a table
134 * which maps these internal numbers to symbol table entries.
135 * A hash table is constructed, based on the local symbol table indices,
136 * for quick lookup of these symbols.
c4e4978a
BJ
137 */
138#define LHSIZ 31
139struct local {
140 int l_index; /* index to symbol in file */
141 struct nlist *l_symbol; /* ptr to symbol table */
142 struct local *l_link; /* hash link */
143} *lochash[LHSIZ], lhinit[NSYMPR];
144struct locseg {
145 struct local *lo_first;
146 int lo_used;
147} locseg[NSEG] = {
148 lhinit, 0
149}, *clocseg;
150
151/*
152 * Libraries are typically built with a table of contents,
153 * which is the first member of a library with special file
154 * name __.SYMDEF and contains a list of symbol names
155 * and with each symbol the offset of the library member which defines
156 * it. The loader uses this table to quickly tell which library members
157 * are (potentially) useful. The alternative, examining the symbol
158 * table of each library member, is painfully slow for large archives.
159 *
160 * See <ranlib.h> for the definition of the ranlib structure and an
161 * explanation of the __.SYMDEF file format.
162 */
163int tnum; /* number of symbols in table of contents */
164int ssiz; /* size of string table for table of contents */
165struct ranlib *tab; /* the table of contents (dynamically allocated) */
166char *tabstr; /* string table for table of contents */
167
168/*
169 * We open each input file or library only once, but in pass2 we
170 * (historically) read from such a file at 2 different places at the
171 * same time. These structures are remnants from those days,
537f7e17 172 * and now serve only to catch ``Premature EOF''.
c4e4978a
BJ
173 */
174typedef struct {
175 short *fakeptr;
176 int bno;
177 int nibuf;
178 int nuser;
179 char buff[BSIZE];
180} PAGE;
181
182PAGE page[2];
183
184struct {
185 short *fakeptr;
186 int bno;
187 int nibuf;
188 int nuser;
189} fpage;
190
191typedef struct {
192 char *ptr;
193 int bno;
194 int nibuf;
195 long size;
196 long pos;
197 PAGE *pno;
198} STREAM;
199
200STREAM text;
201STREAM reloc;
202
203/*
204 * Header from the a.out and the archive it is from (if any).
205 */
206struct exec filhdr;
207struct ar_hdr archdr;
208#define OARMAG 0177545
209
210/*
211 * Options.
212 */
213int trace;
214int xflag; /* discard local symbols */
215int Xflag; /* discard locals starting with 'L' */
216int Sflag; /* discard all except locals and globals*/
217int rflag; /* preserve relocation bits, don't define common */
218int arflag; /* original copy of rflag */
219int sflag; /* discard all symbols */
220int nflag; /* pure procedure */
221int dflag; /* define common even with rflag */
537f7e17 222int zflag; /* demand paged */
c4e4978a
BJ
223long hsize; /* size of hole at beginning of data to be squashed */
224int Aflag; /* doing incremental load */
537f7e17 225int Nflag; /* want impure a.out */
c4e4978a
BJ
226int funding; /* reading fundamental file for incremental load */
227
228/*
229 * These are the cumulative sizes, set in pass 1, which
230 * appear in the a.out header when the loader is finished.
231 */
232off_t tsize, dsize, bsize, trsize, drsize, ssize;
233
234/*
235 * Symbol relocation: c?rel is a scale factor which is
236 * added to an old relocation to convert it to new units;
237 * i.e. it is the difference between segment origins.
537f7e17
BJ
238 * (Thus if we are loading from a data segment which began at location
239 * 4 in a .o file into an a.out where it will be loaded starting at
240 * 1024, cdrel will be 1020.)
c4e4978a
BJ
241 */
242long ctrel, cdrel, cbrel;
243
244/*
537f7e17 245 * Textbase is the start address of all text, 0 unless given by -T.
c4e4978a 246 * Database is the base of all data, computed before and used during pass2.
537f7e17
BJ
247 */
248long textbase, database;
249
250/*
c4e4978a
BJ
251 * The base addresses for the loaded text, data and bss from the
252 * current module during pass2 are given by torigin, dorigin and borigin.
253 */
c4e4978a
BJ
254long torigin, dorigin, borigin;
255
256/*
257 * Errlev is nonzero when errors have occured.
258 * Delarg is an implicit argument to the routine delexit
259 * which is called on error. We do ``delarg = errlev'' before normal
260 * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the
261 * result file executable.
262 */
263int errlev;
264int delarg = 4;
265
266/*
267 * The biobuf structure and associated routines are used to write
268 * into one file at several places concurrently. Calling bopen
269 * with a biobuf structure sets it up to write ``biofd'' starting
270 * at the specified offset. You can then use ``bwrite'' and/or ``bputc''
271 * to stuff characters in the stream, much like ``fwrite'' and ``fputc''.
272 * Calling bflush drains all the buffers and MUST be done before exit.
273 */
274struct biobuf {
275 short b_nleft; /* Number free spaces left in b_buf */
276/* Initialize to be less than BUFSIZ initially, to boundary align in file */
277 char *b_ptr; /* Next place to stuff characters */
278 char b_buf[BUFSIZ]; /* The buffer itself */
279 off_t b_off; /* Current file offset */
280 struct biobuf *b_link; /* Link in chain for bflush() */
281} *biobufs;
282#define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \
283 : bflushc(b, c))
284int biofd;
285off_t boffset;
286struct biobuf *tout, *dout, *trout, *drout, *sout, *strout;
287
288/*
289 * Offset is the current offset in the string file.
290 * Its initial value reflects the fact that we will
291 * eventually stuff the size of the string table at the
292 * beginning of the string table (i.e. offset itself!).
293 */
294off_t offset = sizeof (off_t);
295
296int ofilfnd; /* -o given; otherwise move l.out to a.out */
297char *ofilename = "l.out";
298int infil; /* current input file descriptor */
299char *filname; /* and its name */
300
301/*
302 * Base of the string table of the current module (pass1 and pass2).
303 */
304char *curstr;
305
306char get();
307int delexit();
308char *savestr();
309
310main(argc, argv)
311char **argv;
312{
313 register int c, i;
314 int num;
315 register char *ap, **p;
316 char save;
317
537f7e17 318 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
c4e4978a 319 signal(SIGINT, delexit);
537f7e17
BJ
320 signal(SIGTERM, delexit);
321 }
c4e4978a
BJ
322 if (argc == 1)
323 exit(4);
324 p = argv+1;
325
537f7e17
BJ
326 /*
327 * Scan files once to find where symbols are defined.
328 */
c4e4978a
BJ
329 for (c=1; c<argc; c++) {
330 if (trace)
331 printf("%s:\n", *p);
332 filname = 0;
333 ap = *p++;
334 if (*ap != '-') {
335 load1arg(ap);
336 continue;
337 }
338 for (i=1; ap[i]; i++) switch (ap[i]) {
339
340 case 'o':
341 if (++c >= argc)
342 error(1, "-o where?");
343 ofilename = *p++;
344 ofilfnd++;
345 continue;
346 case 'u':
347 case 'e':
348 if (++c >= argc)
349 error(1, "-u or -c: arg missing");
350 enter(slookup(*p++));
351 if (ap[i]=='e')
352 entrypt = lastsym;
353 continue;
354 case 'H':
355 if (++c >= argc)
356 error(1, "-H: arg missing");
357 if (tsize!=0)
358 error(1, "-H: too late, some text already loaded");
359 hsize = atoi(*p++);
360 continue;
361 case 'A':
362 if (++c >= argc)
363 error(1, "-A: arg missing");
364 if (Aflag)
365 error(1, "-A: only one base file allowed");
366 Aflag = 1;
367 nflag = 0;
368 funding = 1;
369 load1arg(*p++);
370 trsize = drsize = tsize = dsize = bsize = 0;
371 ctrel = cdrel = cbrel = 0;
372 funding = 0;
373 addsym = nextsym;
374 continue;
375 case 'D':
376 if (++c >= argc)
377 error(1, "-D: arg missing");
378 num = htoi(*p++);
379 if (dsize > num)
380 error(1, "-D: too small");
381 dsize = num;
382 continue;
383 case 'T':
384 if (++c >= argc)
385 error(1, "-T: arg missing");
386 if (tsize!=0)
387 error(1, "-T: too late, some text already loaded");
388 textbase = htoi(*p++);
389 continue;
390 case 'l':
391 save = ap[--i];
392 ap[i]='-';
393 load1arg(&ap[i]);
394 ap[i]=save;
395 goto next;
396 case 'x':
397 xflag++;
398 continue;
399 case 'X':
400 Xflag++;
401 continue;
402 case 'S':
403 Sflag++;
404 continue;
405 case 'r':
406 rflag++;
407 arflag++;
c4e4978a
BJ
408 continue;
409 case 's':
410 sflag++;
411 xflag++;
412 continue;
413 case 'n':
414 nflag++;
537f7e17 415 Nflag = zflag = 0;
c4e4978a
BJ
416 continue;
417 case 'N':
537f7e17
BJ
418 Nflag++;
419 nflag = zflag = 0;
c4e4978a
BJ
420 continue;
421 case 'd':
422 dflag++;
423 continue;
424 case 'i':
425 printf("ld: -i ignored\n");
426 continue;
427 case 't':
428 trace++;
429 continue;
430 case 'z':
431 zflag++;
537f7e17 432 Nflag = nflag = 0;
c4e4978a
BJ
433 continue;
434 default:
435 filname = savestr("-x"); /* kludge */
436 filname[1] = ap[i]; /* kludge */
437 archdr.ar_name[0] = 0; /* kludge */
438 error(1, "bad flag");
439 }
440next:
441 ;
442 }
537f7e17
BJ
443 if (rflag == 0 && Nflag == 0 && nflag == 0)
444 zflag++;
c4e4978a
BJ
445 endload(argc, argv);
446 exit(0);
447}
448
449/*
450 * Convert a ascii string which is a hex number.
451 * Used by -T and -D options.
452 */
453htoi(p)
454 register char *p;
455{
456 register int c, n;
457
458 n = 0;
459 while (c = *p++) {
460 n <<= 4;
461 if (isdigit(c))
462 n += c - '0';
463 else if (c >= 'a' && c <= 'f')
464 n += 10 + (c - 'a');
465 else if (c >= 'A' && c <= 'F')
466 n += 10 + (c - 'A');
467 else
468 error(1, "badly formed hex number");
469 }
470 return (n);
471}
472
473delexit()
474{
475
476 bflush();
477 unlink("l.out");
478 if (delarg==0 && Aflag==0)
479 chmod(ofilename, 0777 &~ umask(0));
480 exit (delarg);
481}
482
483endload(argc, argv)
484 int argc;
485 char **argv;
486{
487 register int c, i;
488 long dnum;
489 register char *ap, **p;
490
491 clibseg = libseg;
492 filname = 0;
493 middle();
494 setupout();
495 p = argv+1;
496 for (c=1; c<argc; c++) {
497 ap = *p++;
498 if (trace)
499 printf("%s:\n", ap);
500 if (*ap != '-') {
501 load2arg(ap);
502 continue;
503 }
504 for (i=1; ap[i]; i++) switch (ap[i]) {
505
506 case 'D':
507 dnum = htoi(*p);
508 if (dorigin < dnum)
509 while (dorigin < dnum)
510 bputc(0, dout), dorigin++;
511 /* fall into ... */
512 case 'T':
513 case 'u':
514 case 'e':
515 case 'o':
516 case 'H':
517 ++c;
518 ++p;
519 /* fall into ... */
520 default:
521 continue;
522 case 'A':
523 funding = 1;
524 load2arg(*p++);
525 funding = 0;
526 c++;
527 continue;
528 case 'l':
529 ap[--i]='-';
530 load2arg(&ap[i]);
531 goto next;
532 }
533next:
534 ;
535 }
536 finishout();
537}
538
539/*
540 * Scan file to find defined symbols.
541 */
542load1arg(cp)
543 register char *cp;
544{
545 register struct ranlib *tp;
546 off_t nloc;
547
548 switch (getfile(cp)) {
549
550 /*
551 * Plain file.
552 */
553 case 0:
554 load1(0, 0L);
555 break;
556
557 /*
558 * Archive without table of contents.
559 * (Slowly) process each member.
560 */
561 case 1:
562 error(-1, "warning: archive has no table of contents");
563 nloc = SARMAG;
564 while (step(nloc))
565 nloc += sizeof(archdr) +
566 round(atol(archdr.ar_size), sizeof (short));
567 break;
568
569 /*
570 * Archive with table of contents.
571 * Read the table of contents and its associated string table.
572 * Pass through the library resolving symbols until nothing changes
573 * for an entire pass (i.e. you can get away with backward references
574 * when there is a table of contents!)
575 */
576 case 2:
577 nloc = SARMAG + sizeof (archdr);
578 dseek(&text, nloc, sizeof (tnum));
579 mget((char *)&tnum, sizeof (tnum), &text);
580 nloc += sizeof (tnum);
581 tab = (struct ranlib *)malloc(tnum);
582 if (tab == 0)
583 error(1, "ran out of memory (toc)");
584 dseek(&text, nloc, tnum);
585 mget((char *)tab, tnum, &text);
586 nloc += tnum;
587 tnum /= sizeof (struct ranlib);
588 dseek(&text, nloc, sizeof (ssiz));
589 mget((char *)&ssiz, sizeof (ssiz), &text);
590 nloc += sizeof (ssiz);
591 tabstr = (char *)malloc(ssiz);
592 if (tabstr == 0)
593 error(1, "ran out of memory (tocstr)");
594 dseek(&text, nloc, ssiz);
595 mget((char *)tabstr, ssiz, &text);
596 for (tp = &tab[tnum]; --tp >= tab;) {
597 if (tp->ran_un.ran_strx < 0 ||
598 tp->ran_un.ran_strx >= ssiz)
599 error(1, "mangled archive table of contents");
600 tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx;
601 }
602 while (ldrand())
603 continue;
604 cfree((char *)tab);
605 cfree(tabstr);
606 nextlibp(-1);
607 break;
608
609 /*
610 * Table of contents is out of date, so search
611 * as a normal library (but skip the __.SYMDEF file).
612 */
613 case 3:
614 error(-1, "warning: table of contents is out of date");
615 nloc = SARMAG;
616 do
617 nloc += sizeof(archdr) +
618 round(atol(archdr.ar_size), sizeof(short));
619 while (step(nloc));
620 break;
621 }
622 close(infil);
623}
624
625/*
626 * Advance to the next archive member, which
627 * is at offset nloc in the archive. If the member
628 * is useful, record its location in the liblist structure
629 * for use in pass2. Mark the end of the archive in libilst with a -1.
630 */
631step(nloc)
632 off_t nloc;
633{
634
635 dseek(&text, nloc, (long) sizeof archdr);
636 if (text.size <= 0) {
637 nextlibp(-1);
638 return (0);
639 }
640 getarhdr();
641 if (load1(1, nloc + (sizeof archdr)))
642 nextlibp(nloc);
643 return (1);
644}
645
646/*
647 * Record the location of a useful archive member.
648 * Recording -1 marks the end of files from an archive.
649 * The liblist data structure is dynamically extended here.
650 */
651nextlibp(val)
652 off_t val;
653{
654
655 if (clibseg->li_used == NROUT) {
656 if (++clibseg == &libseg[NSEG])
657 error(1, "too many files loaded from libraries");
658 clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t));
659 if (clibseg->li_first == 0)
660 error(1, "ran out of memory (nextlibp)");
661 }
662 clibseg->li_first[clibseg->li_used++] = val;
663}
664
665/*
666 * One pass over an archive with a table of contents.
667 * Remember the number of symbols currently defined,
668 * then call step on members which look promising (i.e.
669 * that define a symbol which is currently externally undefined).
670 * Indicate to our caller whether this process netted any more symbols.
671 */
672ldrand()
673{
674 register struct nlist *sp, **hp;
675 register struct ranlib *tp, *tplast;
676 off_t loc;
677 int nsymt = symx(nextsym);
678
679 tplast = &tab[tnum-1];
680 for (tp = tab; tp <= tplast; tp++) {
681 if ((hp = slookup(tp->ran_un.ran_name)) == 0)
682 continue;
683 sp = *hp;
684 if (sp->n_type != N_EXT+N_UNDF)
685 continue;
686 step(tp->ran_off);
687 loc = tp->ran_off;
688 while (tp < tplast && (tp+1)->ran_off == loc)
689 tp++;
690 }
691 return (symx(nextsym) != nsymt);
692}
693
694/*
695 * Examine a single file or archive member on pass 1.
696 */
697load1(libflg, loc)
698 off_t loc;
699{
700 register struct nlist *sp;
701 struct nlist *savnext;
702 int ndef, nlocal, type, size, nsymt;
703 register int i;
704 off_t maxoff;
705 struct stat stb;
706
707 readhdr(loc);
708 if (filhdr.a_syms == 0) {
709 if (filhdr.a_text+filhdr.a_data == 0)
710 return (0);
711 error(1, "no namelist");
712 }
713 if (libflg)
714 maxoff = atol(archdr.ar_size);
715 else {
716 fstat(infil, &stb);
717 maxoff = stb.st_size;
718 }
719 if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff)
720 error(1, "too small (old format .o?)");
721 ctrel = tsize; cdrel += dsize; cbrel += bsize;
722 ndef = 0;
723 nlocal = sizeof(cursym);
724 savnext = nextsym;
725 loc += N_SYMOFF(filhdr);
726 dseek(&text, loc, filhdr.a_syms);
727 dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t));
728 mget(&size, sizeof (size), &reloc);
729 dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t));
730 curstr = (char *)malloc(size);
731 if (curstr == NULL)
732 error(1, "no space for string table");
733 mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc);
734 while (text.size > 0) {
735 mget((char *)&cursym, sizeof(struct nlist), &text);
736 if (cursym.n_un.n_strx) {
737 if (cursym.n_un.n_strx<sizeof(size) ||
738 cursym.n_un.n_strx>=size)
739 error(1, "bad string table index (pass 1)");
740 cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
741 }
742 type = cursym.n_type;
743 if ((type&N_EXT)==0) {
744 if (Xflag==0 || cursym.n_un.n_name[0]!='L' ||
745 type & N_STAB)
746 nlocal += sizeof cursym;
747 continue;
748 }
749 symreloc();
750 if (enter(lookup()))
751 continue;
752 if ((sp = lastsym)->n_type != N_EXT+N_UNDF)
753 continue;
754 if (cursym.n_type == N_EXT+N_UNDF) {
755 if (cursym.n_value > sp->n_value)
756 sp->n_value = cursym.n_value;
757 continue;
758 }
759 if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT)
760 continue;
761 ndef++;
762 sp->n_type = cursym.n_type;
763 sp->n_value = cursym.n_value;
764 }
765 if (libflg==0 || ndef) {
766 tsize += filhdr.a_text;
767 dsize += round(filhdr.a_data, sizeof (long));
768 bsize += round(filhdr.a_bss, sizeof (long));
769 ssize += nlocal;
770 trsize += filhdr.a_trsize;
771 drsize += filhdr.a_drsize;
772 if (funding)
773 textbase = (*slookup("_end"))->n_value;
774 nsymt = symx(nextsym);
775 for (i = symx(savnext); i < nsymt; i++) {
776 sp = xsym(i);
777 sp->n_un.n_name = savestr(sp->n_un.n_name);
778 }
779 free(curstr);
780 return (1);
781 }
782 /*
783 * No symbols defined by this library member.
784 * Rip out the hash table entries and reset the symbol table.
785 */
786 symfree(savnext);
787 free(curstr);
788 return(0);
789}
790
791middle()
792{
793 register struct nlist *sp;
794 long csize, t, corigin, ocsize;
795 int nund, rnd;
796 char s;
797 register int i;
798 int nsymt;
799
800 torigin = 0;
801 dorigin = 0;
802 borigin = 0;
803
c4e4978a
BJ
804 p_etext = *slookup("_etext");
805 p_edata = *slookup("_edata");
806 p_end = *slookup("_end");
807 /*
808 * If there are any undefined symbols, save the relocation bits.
809 */
810 nsymt = symx(nextsym);
811 if (rflag==0) {
812 for (i = 0; i < nsymt; i++) {
813 sp = xsym(i);
814 if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 &&
537f7e17 815 sp!=p_end && sp!=p_edata && sp!=p_etext) {
c4e4978a
BJ
816 rflag++;
817 dflag = 0;
818 break;
819 }
820 }
821 }
822 if (rflag)
823 sflag = zflag = 0;
824 /*
825 * Assign common locations.
826 */
827 csize = 0;
828 if (!Aflag)
829 addsym = symseg[0].sy_first;
830 database = round(tsize+textbase,
831 (nflag||zflag? PAGSIZ : sizeof (long)));
832 database += hsize;
833 if (dflag || rflag==0) {
c4e4978a
BJ
834 ldrsym(p_etext, tsize, N_EXT+N_TEXT);
835 ldrsym(p_edata, dsize, N_EXT+N_DATA);
836 ldrsym(p_end, bsize, N_EXT+N_BSS);
837 for (i = symx(addsym); i < nsymt; i++) {
838 sp = xsym(i);
839 if ((s=sp->n_type)==N_EXT+N_UNDF &&
840 (t = sp->n_value)!=0) {
841 if (t >= sizeof (double))
842 rnd = sizeof (double);
843 else if (t >= sizeof (long))
844 rnd = sizeof (long);
845 else
846 rnd = sizeof (short);
847 csize = round(csize, rnd);
848 sp->n_value = csize;
849 sp->n_type = N_EXT+N_COMM;
850 ocsize = csize;
851 csize += t;
852 }
853 if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) {
854 sp->n_value = ocsize;
855 sp->n_type = (s&N_STAB) | (N_EXT+N_COMM);
856 }
857 }
858 }
859 /*
860 * Now set symbols to their final value
861 */
862 csize = round(csize, sizeof (long));
863 torigin = textbase;
864 dorigin = database;
865 corigin = dorigin + dsize;
866 borigin = corigin + csize;
867 nund = 0;
868 nsymt = symx(nextsym);
869 for (i = symx(addsym); i<nsymt; i++) {
870 sp = xsym(i);
871 switch (sp->n_type & (N_TYPE+N_EXT)) {
872
873 case N_EXT+N_UNDF:
874 errlev |= 01;
875 if ((arflag==0 || dflag) && sp->n_value==0) {
537f7e17
BJ
876 if (sp==p_end || sp==p_etext || sp==p_edata)
877 continue;
c4e4978a
BJ
878 if (nund==0)
879 printf("Undefined:\n");
880 nund++;
881 printf("%s\n", sp->n_un.n_name);
882 }
883 continue;
884 case N_EXT+N_ABS:
885 default:
886 continue;
887 case N_EXT+N_TEXT:
888 sp->n_value += torigin;
889 continue;
890 case N_EXT+N_DATA:
891 sp->n_value += dorigin;
892 continue;
893 case N_EXT+N_BSS:
894 sp->n_value += borigin;
895 continue;
896 case N_EXT+N_COMM:
897 sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS);
898 sp->n_value += corigin;
899 continue;
900 }
901 }
902 if (sflag || xflag)
903 ssize = 0;
904 bsize += csize;
905 nsym = ssize / (sizeof cursym);
906 if (Aflag) {
c4e4978a
BJ
907 fixspec(p_etext,torigin);
908 fixspec(p_edata,dorigin);
909 fixspec(p_end,borigin);
910 }
911}
912
913fixspec(sym,offset)
914 struct nlist *sym;
915 long offset;
916{
917
918 if(symx(sym) < symx(addsym) && sym!=0)
919 sym->n_value += offset;
920}
921
922ldrsym(sp, val, type)
923 register struct nlist *sp;
924 long val;
925{
926
927 if (sp == 0)
928 return;
929 if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) {
930 printf("%s: ", sp->n_un.n_name);
931 error(0, "user attempt to redfine loader-defined symbol");
932 return;
933 }
934 sp->n_type = type;
935 sp->n_value = val;
936}
937
938off_t wroff;
939struct biobuf toutb;
940
941setupout()
942{
943 int bss;
944
945 biofd = creat(ofilename, 0666);
946 if (biofd < 0)
947 error(1, "cannot create output");
948 tout = &toutb;
949 bopen(tout, 0);
950 filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC);
951 filhdr.a_text = nflag ? tsize :
952 round(tsize, zflag ? PAGSIZ : sizeof (long));
953 filhdr.a_data = zflag ? round(dsize, PAGSIZ) : dsize;
954 bss = bsize - (filhdr.a_data - dsize);
955 if (bss < 0)
956 bss = 0;
957 filhdr.a_bss = bss;
958 filhdr.a_trsize = trsize;
959 filhdr.a_drsize = drsize;
960 filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym));
961 if (entrypt) {
962 if (entrypt->n_type!=N_EXT+N_TEXT)
963 error(0, "entry point not in text");
964 else
965 filhdr.a_entry = entrypt->n_value;
966 } else
967 filhdr.a_entry = 0;
968 filhdr.a_trsize = (rflag ? trsize:0);
969 filhdr.a_drsize = (rflag ? drsize:0);
970 bwrite((char *)&filhdr, sizeof (filhdr), tout);
971 if (zflag) {
972 bflush1(tout);
973 biobufs = 0;
974 bopen(tout, PAGSIZ);
975 }
976 wroff = N_TXTOFF(filhdr) + filhdr.a_text;
977 outb(&dout, filhdr.a_data);
978 if (rflag) {
979 outb(&trout, filhdr.a_trsize);
980 outb(&drout, filhdr.a_drsize);
981 }
982 if (sflag==0 || xflag==0) {
983 outb(&sout, filhdr.a_syms);
984 wroff += sizeof (offset);
985 outb(&strout, 0);
986 }
987}
988
989outb(bp, inc)
990 register struct biobuf **bp;
991{
992
993 *bp = (struct biobuf *)malloc(sizeof (struct biobuf));
994 if (*bp == 0)
995 error(1, "ran out of memory (outb)");
996 bopen(*bp, wroff);
997 wroff += inc;
998}
999
1000load2arg(acp)
1001char *acp;
1002{
1003 register char *cp;
1004 off_t loc;
1005
1006 cp = acp;
1007 if (getfile(cp) == 0) {
1008 while (*cp)
1009 cp++;
1010 while (cp >= acp && *--cp != '/');
1011 mkfsym(++cp);
1012 load2(0L);
1013 } else { /* scan archive members referenced */
1014 for (;;) {
1015 if (clibseg->li_used2 == clibseg->li_used) {
1016 if (clibseg->li_used < NROUT)
1017 error(1, "libseg botch");
1018 clibseg++;
1019 }
1020 loc = clibseg->li_first[clibseg->li_used2++];
1021 if (loc == -1)
1022 break;
1023 dseek(&text, loc, (long)sizeof(archdr));
1024 getarhdr();
1025 mkfsym(archdr.ar_name);
1026 load2(loc + (long)sizeof(archdr));
1027 }
1028 }
1029 close(infil);
1030}
1031
1032load2(loc)
1033long loc;
1034{
1035 int size;
1036 register struct nlist *sp;
1037 register struct local *lp;
1038 register int symno, i;
1039 int type;
1040
1041 readhdr(loc);
537f7e17 1042 if (!funding) {
c4e4978a
BJ
1043 ctrel = torigin;
1044 cdrel += dorigin;
1045 cbrel += borigin;
1046 }
1047 /*
1048 * Reread the symbol table, recording the numbering
1049 * of symbols for fixing external references.
1050 */
1051 for (i = 0; i < LHSIZ; i++)
1052 lochash[i] = 0;
1053 clocseg = locseg;
1054 clocseg->lo_used = 0;
1055 symno = -1;
1056 loc += N_TXTOFF(filhdr);
1057 dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1058 filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t));
1059 mget(&size, sizeof(size), &text);
1060 dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1061 filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t),
1062 size - sizeof(off_t));
1063 curstr = (char *)malloc(size);
1064 if (curstr == NULL)
1065 error(1, "out of space reading string table (pass 2)");
1066 mget(curstr+sizeof(off_t), size-sizeof(off_t), &text);
1067 dseek(&text, loc+filhdr.a_text+filhdr.a_data+
1068 filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms);
1069 while (text.size > 0) {
1070 symno++;
1071 mget((char *)&cursym, sizeof(struct nlist), &text);
1072 if (cursym.n_un.n_strx) {
1073 if (cursym.n_un.n_strx<sizeof(size) ||
1074 cursym.n_un.n_strx>=size)
1075 error(1, "bad string table index (pass 2)");
1076 cursym.n_un.n_name = curstr + cursym.n_un.n_strx;
1077 }
1078/* inline expansion of symreloc() */
1079 switch (cursym.n_type & 017) {
1080
1081 case N_TEXT:
1082 case N_EXT+N_TEXT:
1083 cursym.n_value += ctrel;
1084 break;
1085 case N_DATA:
1086 case N_EXT+N_DATA:
1087 cursym.n_value += cdrel;
1088 break;
1089 case N_BSS:
1090 case N_EXT+N_BSS:
1091 cursym.n_value += cbrel;
1092 break;
1093 case N_EXT+N_UNDF:
1094 break;
1095 default:
1096 if (cursym.n_type&N_EXT)
1097 cursym.n_type = N_EXT+N_ABS;
1098 }
1099/* end inline expansion of symreloc() */
1100 type = cursym.n_type;
1101 if ((type&N_EXT) == 0) {
1102 if (!sflag&&!xflag&&
1103 (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB))
1104 symwrite(&cursym, sout);
1105 continue;
1106 }
1107 if (funding)
1108 continue;
1109 if ((sp = *lookup()) == 0)
1110 error(1, "internal error: symbol not found");
1111 if (cursym.n_type == N_EXT+N_UNDF) {
1112 if (clocseg->lo_used == NSYMPR) {
1113 if (++clocseg == &locseg[NSEG])
1114 error(1, "local symbol overflow");
1115 clocseg->lo_used = 0;
1116 }
1117 if (clocseg->lo_first == 0) {
1118 clocseg->lo_first = (struct local *)
1119 malloc(NSYMPR * sizeof (struct local));
1120 if (clocseg->lo_first == 0)
1121 error(1, "out of memory (clocseg)");
1122 }
1123 lp = &clocseg->lo_first[clocseg->lo_used++];
1124 lp->l_index = symno;
1125 lp->l_symbol = sp;
1126 lp->l_link = lochash[symno % LHSIZ];
1127 lochash[symno % LHSIZ] = lp;
1128 continue;
1129 }
1130 if (cursym.n_type & N_STAB)
1131 continue;
1132 if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) {
1133 printf("%s: ", cursym.n_un.n_name);
1134 error(0, "multiply defined");
1135 }
1136 }
1137 if (funding)
1138 return;
1139 dseek(&text, loc, filhdr.a_text);
1140 dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
537f7e17 1141 load2td(ctrel, torigin - textbase, tout, trout);
c4e4978a
BJ
1142 dseek(&text, loc+filhdr.a_text, filhdr.a_data);
1143 dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize,
1144 filhdr.a_drsize);
537f7e17 1145 load2td(cdrel, dorigin - database, dout, drout);
c4e4978a
BJ
1146 while (filhdr.a_data & (sizeof(long)-1)) {
1147 bputc(0, dout);
1148 filhdr.a_data++;
1149 }
1150 torigin += filhdr.a_text;
1151 dorigin += filhdr.a_data;
1152 borigin += filhdr.a_bss;
1153 free(curstr);
1154}
1155
537f7e17
BJ
1156/*
1157 * This routine relocates the single text or data segment argument.
1158 * Offsets from external symbols are resolved by adding the value
1159 * of the external symbols. Non-external reference are updated to account
1160 * for the relative motion of the segments (ctrel, cdrel, ...). If
1161 * a relocation was pc-relative, then we update it to reflect the
1162 * change in the positioning of the segments by adding the displacement
1163 * of the referenced segment and subtracting the displacement of the
1164 * current segment (creloc).
1165 *
1166 * If we are saving the relocation information, then we increase
1167 * each relocation datum address by our base position in the new segment.
1168 */
1169load2td(creloc, position, b1, b2)
1170 long creloc, offset;
c4e4978a
BJ
1171 struct biobuf *b1, *b2;
1172{
1173 register struct nlist *sp;
1174 register struct local *lp;
1175 long tw;
1176 register struct relocation_info *rp, *rpend;
c4e4978a
BJ
1177 struct relocation_info *relp;
1178 char *codep;
1179 register char *cp;
1180 int relsz, codesz;
1181
1182 relsz = reloc.size;
1183 relp = (struct relocation_info *)malloc(relsz);
1184 codesz = text.size;
1185 codep = (char *)malloc(codesz);
1186 if (relp == 0 || codep == 0)
1187 error(1, "out of memory (load2td)");
1188 mget((char *)relp, relsz, &reloc);
1189 rpend = &relp[relsz / sizeof (struct relocation_info)];
1190 mget(codep, codesz, &text);
1191 for (rp = relp; rp < rpend; rp++) {
c4e4978a 1192 cp = codep + rp->r_address;
537f7e17
BJ
1193 /*
1194 * Pick up previous value at location to be relocated.
1195 */
c4e4978a
BJ
1196 switch (rp->r_length) {
1197
1198 case 0: /* byte */
1199 tw = *cp;
1200 break;
1201
1202 case 1: /* word */
1203 tw = *(short *)cp;
1204 break;
1205
1206 case 2: /* long */
1207 tw = *(long *)cp;
1208 break;
1209
1210 default:
1211 error(1, "load2td botch: bad length");
1212 }
537f7e17
BJ
1213 /*
1214 * If relative to an external which is defined,
1215 * resolve to a simpler kind of reference in the
1216 * result file. If the external is undefined, just
1217 * convert the symbol number to the number of the
1218 * symbol in the result file and leave it undefined.
1219 */
c4e4978a 1220 if (rp->r_extern) {
537f7e17
BJ
1221 /*
1222 * Search the hash table which maps local
1223 * symbol numbers to symbol tables entries
1224 * in the new a.out file.
1225 */
c4e4978a
BJ
1226 lp = lochash[rp->r_symbolnum % LHSIZ];
1227 while (lp->l_index != rp->r_symbolnum) {
1228 lp = lp->l_link;
1229 if (lp == 0)
1230 error(1, "local symbol botch");
1231 }
1232 sp = lp->l_symbol;
1233 if (sp->n_type == N_EXT+N_UNDF)
1234 rp->r_symbolnum = nsym+symx(sp);
1235 else {
1236 rp->r_symbolnum = sp->n_type & N_TYPE;
1237 tw += sp->n_value;
1238 rp->r_extern = 0;
1239 }
1240 } else switch (rp->r_symbolnum & N_TYPE) {
537f7e17
BJ
1241 /*
1242 * Relocation is relative to the loaded position
1243 * of another segment. Update by the change in position
1244 * of that segment.
1245 */
c4e4978a
BJ
1246 case N_TEXT:
1247 tw += ctrel;
1248 break;
1249 case N_DATA:
1250 tw += cdrel;
1251 break;
1252 case N_BSS:
1253 tw += cbrel;
1254 break;
1255 case N_ABS:
1256 break;
1257 default:
1258 error(1, "relocation format botch (symbol type))");
1259 }
537f7e17
BJ
1260 /*
1261 * Relocation is pc relative, so decrease the relocation
1262 * by the amount the current segment is displaced.
1263 * (E.g if we are a relative reference to a text location
1264 * from data space, we added the increase in the text address
1265 * above, and subtract the increase in our (data) address
1266 * here, leaving the net change the relative change in the
1267 * positioning of our text and data segments.)
1268 */
c4e4978a 1269 if (rp->r_pcrel)
c4e4978a 1270 tw -= creloc;
537f7e17
BJ
1271 /*
1272 * Put the value back in the segment,
1273 * while checking for overflow.
1274 */
c4e4978a
BJ
1275 switch (rp->r_length) {
1276
1277 case 0: /* byte */
1278 if (tw < -128 || tw > 127)
1279 error(0, "byte displacement overflow");
1280 *cp = tw;
1281 break;
1282 case 1: /* word */
1283 if (tw < -32768 || tw > 32767)
1284 error(0, "word displacement overflow");
1285 *(short *)cp = tw;
1286 break;
1287 case 2: /* long */
1288 *(long *)cp = tw;
1289 break;
1290 }
537f7e17
BJ
1291 /*
1292 * If we are saving relocation information,
1293 * we must convert the address in the segment from
1294 * the old .o file into an address in the segment in
1295 * the new a.out, by adding the position of our
1296 * segment in the new larger segment.
1297 */
c4e4978a 1298 if (rflag)
537f7e17 1299 rp->r_address += position;
c4e4978a
BJ
1300 }
1301 bwrite(codep, codesz, b1);
1302 if (rflag)
1303 bwrite(relp, relsz, b2);
1304 cfree((char *)relp);
1305 cfree(codep);
1306}
1307
1308finishout()
1309{
1310 register int i;
1311 int nsymt;
1312
1313 if (sflag==0) {
1314 nsymt = symx(nextsym);
1315 for (i = 0; i < nsymt; i++)
1316 symwrite(xsym(i), sout);
1317 bwrite(&offset, sizeof offset, sout);
1318 }
1319 if (!ofilfnd) {
1320 unlink("a.out");
1321 link("l.out", "a.out");
1322 ofilename = "a.out";
1323 }
1324 delarg = errlev;
1325 delexit();
1326}
1327
1328mkfsym(s)
1329char *s;
1330{
1331
1332 if (sflag || xflag)
1333 return;
1334 cursym.n_un.n_name = s;
1335 cursym.n_type = N_TEXT;
1336 cursym.n_value = torigin;
1337 symwrite(&cursym, sout);
1338}
1339
1340getarhdr()
1341{
1342 register char *cp;
1343
1344 mget((char *)&archdr, sizeof archdr, &text);
1345 for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];)
1346 if (*cp++ == ' ') {
1347 cp[-1] = 0;
1348 return;
1349 }
1350}
1351
1352mget(loc, n, sp)
1353register STREAM *sp;
1354register char *loc;
1355{
1356 register char *p;
1357 register int take;
1358
1359top:
1360 if (n == 0)
1361 return;
1362 if (sp->size && sp->nibuf) {
1363 p = sp->ptr;
1364 take = sp->size;
1365 if (take > sp->nibuf)
1366 take = sp->nibuf;
1367 if (take > n)
1368 take = n;
1369 n -= take;
1370 sp->size -= take;
1371 sp->nibuf -= take;
1372 sp->pos += take;
1373 do
1374 *loc++ = *p++;
1375 while (--take > 0);
1376 sp->ptr = p;
1377 goto top;
1378 }
1379 if (n > BUFSIZ) {
1380 take = n - n % BSIZE;
1381 lseek(infil, (sp->bno+1)*BSIZE, 0);
1382 if (take > sp->size || read(infil, loc, take) != take)
1383 error(1, "premature EOF");
1384 loc += take;
1385 n -= take;
1386 sp->size -= take;
1387 sp->pos += take;
1388 dseek(sp, (sp->bno+1+take/BSIZE)*BSIZE, -1);
1389 goto top;
1390 }
1391 *loc++ = get(sp);
1392 --n;
1393 goto top;
1394}
1395
1396symwrite(sp, bp)
1397 struct nlist *sp;
1398 struct biobuf *bp;
1399{
1400 register int len;
1401 register char *str;
1402
1403 str = sp->n_un.n_name;
1404 if (str) {
1405 sp->n_un.n_strx = offset;
1406 len = strlen(str) + 1;
1407 bwrite(str, len, strout);
1408 offset += len;
1409 }
1410 bwrite(sp, sizeof (*sp), bp);
1411 sp->n_un.n_name = str;
1412}
1413
1414dseek(sp, loc, s)
1415register STREAM *sp;
1416long loc, s;
1417{
1418 register PAGE *p;
1419 register b, o;
1420 int n;
1421
1422 b = loc>>BSHIFT;
1423 o = loc&BMASK;
1424 if (o&01)
1425 error(1, "loader error; odd offset");
1426 --sp->pno->nuser;
1427 if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b)
1428 if (p->nuser==0 || (p = &page[0])->nuser==0) {
1429 if (page[0].nuser==0 && page[1].nuser==0)
1430 if (page[0].bno < page[1].bno)
1431 p = &page[0];
1432 p->bno = b;
1433 lseek(infil, loc & ~(long)BMASK, 0);
1434 if ((n = read(infil, p->buff, sizeof(p->buff))) < 0)
1435 n = 0;
1436 p->nibuf = n;
1437 } else
1438 error(1, "botch: no pages");
1439 ++p->nuser;
1440 sp->bno = b;
1441 sp->pno = p;
1442 if (s != -1) {sp->size = s; sp->pos = 0;}
1443 sp->ptr = (char *)(p->buff + o);
1444 if ((sp->nibuf = p->nibuf-o) <= 0)
1445 sp->size = 0;
1446}
1447
1448char
1449get(asp)
1450STREAM *asp;
1451{
1452 register STREAM *sp;
1453
1454 sp = asp;
1455 if ((sp->nibuf -= sizeof(char)) < 0) {
1456 dseek(sp, ((long)(sp->bno+1)<<BSHIFT), (long)-1);
1457 sp->nibuf -= sizeof(char);
1458 }
1459 if ((sp->size -= sizeof(char)) <= 0) {
1460 if (sp->size < 0)
1461 error(1, "premature EOF");
1462 ++fpage.nuser;
1463 --sp->pno->nuser;
1464 sp->pno = (PAGE *) &fpage;
1465 }
1466 sp->pos += sizeof(char);
1467 return(*sp->ptr++);
1468}
1469
1470getfile(acp)
1471char *acp;
1472{
1473 register char *cp;
1474 register int c;
1475 char arcmag[SARMAG+1];
1476 struct stat stb;
1477
1478 cp = acp;
1479 infil = -1;
1480 archdr.ar_name[0] = '\0';
1481 filname = cp;
1482 if (cp[0]=='-' && cp[1]=='l') {
1483 char *locfilname = "/usr/local/new/libxxxxxxxxxxxxxxx";
1484 if(cp[2] == '\0')
1485 cp = "-la";
1486 filname = "/usr/new/libxxxxxxxxxxxxxxx";
1487 for(c=0; cp[c+2]; c++) {
1488 filname[c+12] = cp[c+2];
1489 locfilname[c+18] = cp[c+2];
1490 }
1491 filname[c+12] = locfilname[c+18] = '.';
1492 filname[c+13] = locfilname[c+19] = 'a';
1493 filname[c+14] = locfilname[c+20] = '\0';
1494 if ((infil = open(filname+4, 0)) >= 0) {
1495 filname += 4;
1496 } else if ((infil = open(filname, 0)) < 0) {
1497 filname = locfilname;
1498 }
1499 }
1500 if (infil == -1 && (infil = open(filname, 0)) < 0)
1501 error(1, "cannot open");
1502 page[0].bno = page[1].bno = -1;
1503 page[0].nuser = page[1].nuser = 0;
1504 text.pno = reloc.pno = (PAGE *) &fpage;
1505 fpage.nuser = 2;
1506 dseek(&text, 0L, SARMAG);
1507 if (text.size <= 0)
1508 error(1, "premature EOF");
1509 mget((char *)arcmag, SARMAG, &text);
1510 arcmag[SARMAG] = 0;
1511 if (strcmp(arcmag, ARMAG))
1512 return (0);
1513 dseek(&text, SARMAG, sizeof archdr);
1514 if(text.size <= 0)
1515 return (1);
1516 getarhdr();
1517 if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0)
1518 return (1);
1519 fstat(infil, &stb);
1520 return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2);
1521}
1522
1523struct nlist **
1524lookup()
1525{
1526 register int sh;
1527 register struct nlist **hp;
1528 register char *cp, *cp1;
1529 register struct symseg *gp;
1530 register int i;
1531
1532 sh = 0;
1533 for (cp = cursym.n_un.n_name; *cp;)
1534 sh = (sh<<1) + *cp++;
1535 sh = (sh & 0x7fffffff) % HSIZE;
1536 for (gp = symseg; gp < &symseg[NSEG]; gp++) {
1537 if (gp->sy_first == 0) {
1538 gp->sy_first = (struct nlist *)
1539 calloc(NSYM, sizeof (struct nlist));
1540 gp->sy_hfirst = (struct nlist **)
1541 calloc(HSIZE, sizeof (struct nlist *));
1542 if (gp->sy_first == 0 || gp->sy_hfirst == 0)
1543 error(1, "ran out of space for symbol table");
1544 gp->sy_last = gp->sy_first + NSYM;
1545 gp->sy_hlast = gp->sy_hfirst + HSIZE;
1546 }
1547 if (gp > csymseg)
1548 csymseg = gp;
1549 hp = gp->sy_hfirst + sh;
1550 i = 1;
1551 do {
1552 if (*hp == 0) {
1553 if (gp->sy_used == NSYM)
1554 break;
1555 return (hp);
1556 }
1557 cp1 = (*hp)->n_un.n_name;
1558 for (cp = cursym.n_un.n_name; *cp == *cp1++;)
1559 if (*cp++ == 0)
1560 return (hp);
1561 hp += i;
1562 i += 2;
1563 if (hp >= gp->sy_hlast)
1564 hp -= HSIZE;
1565 } while (i < HSIZE);
1566 if (i > HSIZE)
1567 error(1, "hash table botch");
1568 }
1569 error(1, "symbol table overflow");
1570 /*NOTREACHED*/
1571}
1572
1573symfree(saved)
1574 struct nlist *saved;
1575{
1576 register struct symseg *gp;
1577 register struct nlist *sp;
1578
1579 for (gp = csymseg; gp >= symseg; gp--, csymseg--) {
1580 sp = gp->sy_first + gp->sy_used;
1581 if (sp == saved) {
1582 nextsym = sp;
1583 return;
1584 }
1585 for (sp--; sp >= gp->sy_first; sp--) {
1586 gp->sy_hfirst[sp->n_hash] = 0;
1587 gp->sy_used--;
1588 if (sp == saved) {
1589 nextsym = sp;
1590 return;
1591 }
1592 }
1593 }
1594 if (saved == 0)
1595 return;
1596 error(1, "symfree botch");
1597}
1598
1599struct nlist **
1600slookup(s)
1601 char *s;
1602{
1603
1604 cursym.n_un.n_name = s;
1605 cursym.n_type = N_EXT+N_UNDF;
1606 cursym.n_value = 0;
1607 return (lookup());
1608}
1609
1610enter(hp)
1611register struct nlist **hp;
1612{
1613 register struct nlist *sp;
1614
1615 if (*hp==0) {
1616 if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast)
1617 error(1, "enter botch");
1618 *hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used;
1619 csymseg->sy_used++;
1620 sp->n_un.n_name = cursym.n_un.n_name;
1621 sp->n_type = cursym.n_type;
1622 sp->n_hash = hp - csymseg->sy_hfirst;
1623 sp->n_value = cursym.n_value;
1624 nextsym = lastsym + 1;
1625 return(1);
1626 } else {
1627 lastsym = *hp;
1628 return(0);
1629 }
1630}
1631
1632symx(sp)
1633 struct nlist *sp;
1634{
1635 register struct symseg *gp;
1636
1637 if (sp == 0)
1638 return (0);
1639 for (gp = csymseg; gp >= symseg; gp--)
1640 /* <= is sloppy so nextsym will always work */
1641 if (sp >= gp->sy_first && sp <= gp->sy_last)
1642 return ((gp - symseg) * NSYM + sp - gp->sy_first);
1643 error(1, "symx botch");
1644 /*NOTREACHED*/
1645}
1646
1647symreloc()
1648{
1649 if(funding) return;
1650 switch (cursym.n_type & 017) {
1651
1652 case N_TEXT:
1653 case N_EXT+N_TEXT:
1654 cursym.n_value += ctrel;
1655 return;
1656
1657 case N_DATA:
1658 case N_EXT+N_DATA:
1659 cursym.n_value += cdrel;
1660 return;
1661
1662 case N_BSS:
1663 case N_EXT+N_BSS:
1664 cursym.n_value += cbrel;
1665 return;
1666
1667 case N_EXT+N_UNDF:
1668 return;
1669
1670 default:
1671 if (cursym.n_type&N_EXT)
1672 cursym.n_type = N_EXT+N_ABS;
1673 return;
1674 }
1675}
1676
1677error(n, s)
1678char *s;
1679{
1680 if (errlev==0)
1681 printf("ld:");
1682 if (filname) {
1683 printf("%s", filname);
1684 if (n != -1 && archdr.ar_name[0])
1685 printf("(%s)", archdr.ar_name);
1686 printf(": ");
1687 }
1688 printf("%s\n", s);
1689 if (n == -1)
1690 return;
1691 if (n)
1692 delexit();
1693 errlev = 2;
1694}
1695
1696readhdr(loc)
1697off_t loc;
1698{
1699
1700 dseek(&text, loc, (long)sizeof(filhdr));
1701 mget((short *)&filhdr, sizeof(filhdr), &text);
1702 if (N_BADMAG(filhdr)) {
1703 if (filhdr.a_magic == OARMAG)
1704 error(1, "old archive");
1705 error(1, "bad magic number");
1706 }
1707 if (filhdr.a_text&01 || filhdr.a_data&01)
1708 error(1, "text/data size odd");
1709 if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) {
1710 cdrel = -round(filhdr.a_text, PAGSIZ);
1711 cbrel = cdrel - filhdr.a_data;
1712 } else if (filhdr.a_magic == OMAGIC) {
1713 cdrel = -filhdr.a_text;
1714 cbrel = cdrel - filhdr.a_data;
1715 } else
1716 error(1, "bad format");
1717}
1718
1719round(v, r)
1720 int v;
1721 u_long r;
1722{
1723
1724 r--;
1725 v += r;
1726 v &= ~(long)r;
1727 return(v);
1728}
1729
1730#define NSAVETAB 8192
1731char *savetab;
1732int saveleft;
1733
1734char *
1735savestr(cp)
1736 register char *cp;
1737{
1738 register int len;
1739
1740 len = strlen(cp) + 1;
1741 if (len > saveleft) {
1742 saveleft = NSAVETAB;
1743 if (len > saveleft)
1744 saveleft = len;
1745 savetab = (char *)malloc(saveleft);
1746 if (savetab == 0)
1747 error(1, "ran out of memory (savestr)");
1748 }
1749 strncpy(savetab, cp, len);
1750 cp = savetab;
1751 savetab += len;
1752 saveleft -= len;
1753 return (cp);
1754}
1755
1756bopen(bp, off)
1757 struct biobuf *bp;
1758{
1759
1760 bp->b_ptr = bp->b_buf;
1761 bp->b_nleft = BUFSIZ - off % BUFSIZ;
1762 bp->b_off = off;
1763 bp->b_link = biobufs;
1764 biobufs = bp;
1765}
1766
1767int bwrerror;
1768
1769bwrite(p, cnt, bp)
1770 register char *p;
1771 register int cnt;
1772 register struct biobuf *bp;
1773{
1774 register int put;
1775 register char *to;
1776
1777top:
1778 if (cnt == 0)
1779 return;
1780 if (bp->b_nleft) {
1781 put = bp->b_nleft;
1782 if (put > cnt)
1783 put = cnt;
1784 bp->b_nleft -= put;
1785 to = bp->b_ptr;
1786 asm("movc3 r8,(r11),(r7)");
1787 bp->b_ptr += put;
1788 p += put;
1789 cnt -= put;
1790 goto top;
1791 }
1792 if (cnt >= BUFSIZ) {
1793 if (bp->b_ptr != bp->b_buf)
1794 bflush1(bp);
1795 put = cnt - cnt % BUFSIZ;
1796 if (boffset != bp->b_off)
1797 lseek(biofd, bp->b_off, 0);
1798 if (write(biofd, p, put) != put) {
1799 bwrerror = 1;
1800 error(1, "output write error");
1801 }
1802 bp->b_off += put;
1803 boffset = bp->b_off;
1804 p += put;
1805 cnt -= put;
1806 goto top;
1807 }
1808 bflush1(bp);
1809 goto top;
1810}
1811
1812bflush()
1813{
1814 register struct biobuf *bp;
1815
1816 if (bwrerror)
1817 return;
1818 for (bp = biobufs; bp; bp = bp->b_link)
1819 bflush1(bp);
1820}
1821
1822bflush1(bp)
1823 register struct biobuf *bp;
1824{
1825 register int cnt = bp->b_ptr - bp->b_buf;
1826
1827 if (cnt == 0)
1828 return;
1829 if (boffset != bp->b_off)
1830 lseek(biofd, bp->b_off, 0);
1831 if (write(biofd, bp->b_buf, cnt) != cnt) {
1832 bwrerror = 1;
1833 error(1, "output write error");
1834 }
1835 bp->b_off += cnt;
1836 boffset = bp->b_off;
1837 bp->b_ptr = bp->b_buf;
1838 bp->b_nleft = BUFSIZ;
1839}
1840
1841bflushc(bp, c)
1842 register struct biobuf *bp;
1843{
1844
1845 bflush1(bp);
1846 bputc(c, bp);
1847}