BSD 3 development
[unix-history] / usr / src / cmd / ld.c
CommitLineData
4bd96c76
BJ
1char LD[] = "@(#)ld.c 1.10 78/12/07 15:34:58"; /* sccs ident */
2/*
3 * link editor for VAX
4 */
5
6/* layout of a.out file:
7 *
8 * header of 8 words magic number 0410:
9 data starts at 1st (PAGSIZ)
10 boundary above text
11 magic number 0407:
12 data starts immediately after
13 text
14 * text size )
15 * data size ) in bytes
16 * bss size )
17 * symbol table size
18 * entry point
19 * size of text relocation info
20 * size of data relocation info
21 *
22 * 'segment' origin comments
23 * header: 0
24 * text: 32 0 padded to multiple of 4 bytes
25 * data: 32+textsize 0 padded to multiple of 4 bytes
26 * text relocation: 32+textsize+datasize
27 * data relocation: 32+textsize+datasize+textrelocationsize
28 * symbol table: 32+textsize+datasize+textrelocationsize+datarelocationsize
29 *
30 */
31#include <signal.h>
32#include <stdio.h>
33#include <ar.h>
34#include <a.out.h>
35#include <pagsiz.h>
36
37struct {short hiword; short loword;}; /* stupid fp-11 */
38fixl(p) register long *p;{
39 register short t;
40 t=p->hiword; p->hiword=p->loword; p->loword=t;
41}
42
43writel(p,n,f) long *p; FILE *f; {
44#ifdef vax
45 fwrite(p,sizeof(*p),n,f);
46#else
47 while (n--) {
48 fwrite(&(*p).loword,2,1,f);
49 fwrite(&(*p).hiword,2,1,f);
50 p++;
51 }
52#endif
53}
54
55long htoi(p) register char *p; {/* hex to integer conversion */
56register long n = 0;
57while (*p) {
58 n <<= 4;
59 if (*p<='9' && *p>='0') n += *p - '0';
60 else if (*p<='f' && *p>='a') n += *p -'a' +10;
61 else if (*p<='F' && *p>='A') n += *p -'A' +10;
62 p++;
63}
64return(n);
65}
66
67typedef char *STRING;
68typedef int BOOL;
69#define TRUE 1
70#define FALSE 0
71
72#define OMAGIC 0407
73#define NMAGIC 0410
74
75/*
76 * Symbol types
77 */
78#define UNDEF 0x0
79#define ABS 0x2
80#define TEXT 0x4
81#define DATA 0x6
82#define BSS 0x8
83#define DATAO 0xA
84#define BSSO 0xC
85#define TEXTO 0xE
86#define ABSO 0x10
87
88#define COMM 0x12 /* for internal use only */
89
90#define EXTERN 0x1
91#define TYPE 0x1E
92#define STABTYPS 0xE0
93/*
94 * address reference types
95 */
96#define PCREL 1
97#define LEN1 0
98#define LEN2 2
99#define LEN4 4
100
101#define HW 01
102#define FW 03
103#define DW 07
104
105
106#define TYPMASK 0x1E
107#define TYMASK (0x1E)
108#define TMASK 0x1F
109
110#define RABS (ABS)
111#define RTEXT TEXT
112#define RDATA DATA
113#define RBSS BSS
114#define RDATAO DATAO
115#define RBSSO BSSO
116#define RTEXTO TEXTO
117#define RABSO ABSO
118#define REXT (01<<3)
119#define ROFF (02<<3)
120#define REFMASK 0x7
121
122#define NOVLY 1
123#define RELFLG 01
124#define NROUT 256
125#define NSYM 1103
126#define NSYMPR 500
127
128char premeof[] = "Premature EOF";
129
130typedef struct {
131 long loc;
132} LIBLIST;
133
134/* overlay management */
135int vindex;
136typedef struct {
137 int argsav;
138 int symsav;
139 LIBLIST *libsav;
140 STRING vname;
141 long ctsav, cdsav, cbsav;
142 long offt, offd, offb, offtr, offdr, offs;
143} OVERLAY;
144OVERLAY vnodes[NOVLY];
145
146/* input management */
147typedef struct {
148 short *fakeptr;
149 int bno;
150 int nibuf;
151 int nuser;
152 char buff[BSIZE];
153} PAGE;
154
155PAGE page[2];
156
157struct {
158 short *fakeptr;
159 int bno;
160 int nibuf;
161 int nuser;
162} fpage;
163
164typedef struct {
165 char *ptr;
166 int bno;
167 int nibuf;
168 long size;
169 long pos;
170 PAGE *pno;
171} STREAM;
172
173STREAM text;
174STREAM reloc;
175
176struct ar_hdr archdr;
177
178struct exec filhdr;
179
180/* one entry for each archive member referenced;
181 * set in first pass; needs restoring for overlays
182 */
183
184LIBLIST liblist[NROUT];
185LIBLIST *libp = liblist;
186
187
188/* symbol management */
189typedef struct {
190 char sname[8];
191 char stype;
192 char spare;
193 short symhash; /* index of hash table entry pointing to this symbol */
194 long svalue;
195} SYMBOL;
196
197typedef struct {
198 int locindex; /* index to symbol in file */
199 SYMBOL *locsymbol; /* ptr to symbol table */
200} LOCAL;
201
202SYMBOL cursym; /* current symbol */
203SYMBOL *symtab; /* actual symbols */
204SYMBOL *lastsym; /* last symbol entered */
205SYMBOL *nextsym; /* next available symbol table entry */
206int nsym; /* number of symbols allocated in symtab */
207SYMBOL *hshtab[NSYM+2]; /* hash table for symbols */
208LOCAL *local;
209
210/* internal symbols */
211SYMBOL *p_data;
212SYMBOL *p_etext;
213SYMBOL *p_edata;
214SYMBOL *p_end;
215SYMBOL *entrypt;
216
217int trace;
218/* flags */
219int xflag; /* discard local symbols */
220int Xflag; /* discard locals starting with 'L' */
221int Sflag; /* discard all except locals and globals*/
222int rflag; /* preserve relocation bits, don't define common */
223int arflag; /* original copy of rflag */
224int sflag; /* discard all symbols */
225int nflag = 1; /* pure procedure */
226int dflag; /* define common even with rflag */
227int iflag; /* I/D space separated */
228BOOL vflag; /* overlays used */
229int zflag;
230
231int ofilfnd;
232char *ofilename = "l.out";
233int infil;
234char *filname;
235
236long textbase;
237/* cumulative sizes set in pass 1 */
238long tsize;
239long dsize;
240long bsize;
241long trsize;
242long drsize;
243long ssize;
244
245/* symbol relocation; both passes */
246long ctrel;
247long cdrel;
248long cbrel;
249long ctorel;
250long cdorel;
251long cborel;
252
253int errlev;
254int delarg = 4;
255
256
257FILE *tout;
258FILE *dout;
259char *doutn = "";
260FILE *trout;
261char *troutn = "";
262FILE *drout;
263char *droutn = "";
264FILE *sout;
265char *soutn = "";
266
267char *mktemp();
268char get();
269char getb();
270short gets();
271long get3();
272long getl();
273SYMBOL **lookup();
274FILE *tcreat();
275long round();
276SYMBOL **slookup();
277SYMBOL *lookloc();
278
279symwrite(sp,n,f) SYMBOL *sp; FILE *f; {
280#ifdef vax
281 fwrite(sp,sizeof(*symtab),n,f);
282#else
283 while (n--) {
284 fwrite(sp,sizeof(*symtab)-sizeof(sp->svalue),1,f);
285 writel(&(sp->svalue),1,f); sp++;
286 }
287#endif
288}
289
290delexit()
291{
292 unlink("l.out");
293 unlink(doutn);
294 unlink(troutn);
295 unlink(droutn);
296 unlink(soutn);
297 if (delarg==0)
298 chmod(ofilename, 0777 &~ umask(0));
299 exit(delarg);
300}
301
302main(argc, argv)
303char **argv;
304{
305 register int c, i;
306 int num;
307 register char *ap, **p;
308 BOOL found;
309 int vscan;
310 char save;
311
312 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
313 signal(SIGINT, delexit);
314 if (argc == 1)
315 exit(4);
316 p = argv+1;
317
318 nextsym=symtab=sbrk(0); nsym=0;
319 /* scan files once to find symdefs */
320 for (c=1; c<argc; c++) {
321 if (trace) printf("%s:\n", *p);
322 filname = 0;
323 ap = *p++;
324
325 if (*ap == '-') {
326 for (i=1; ap[i]; i++) {
327 switch (ap[i]) {
328 case 'o':
329 if (++c >= argc)
330 error(1, "Bad output file");
331 ofilename = *p++;
332 ofilfnd++;
333 continue;
334
335 case 'u':
336 case 'e':
337 if (++c >= argc)
338 error(1, "Bad 'use' or 'entry'");
339 enter(slookup(*p++));
340 if (ap[i]=='e')
341 entrypt = lastsym;
342 continue;
343
344 case 'v':
345 if (++c >= argc)
346 error(1, "-v: arg missing");
347 vflag=TRUE;
348 vscan = vindex;
349 found=FALSE;
350 while (--vscan>=0 && found==FALSE)
351 found = eq(vnodes[vscan].vname, *p);
352 if (found) {
353 endload(c, argv);
354 restore(vscan);
355 } else
356 record(c, *p);
357 p++;
358 continue;
359
360 case 'D':
361 if (++c >= argc)
362 error(1, "-D: arg missing");
363 num = htoi(*p++);
364 if (dsize>num)
365 error(1, "-D: too small");
366 dsize = num;
367 continue;
368
369 case 'T':
370 if (++c >= argc)
371 error(1, "-T: arg missing");
372 if (tsize!=0)
373 error(1, "-T: too late, some text already loaded");
374 textbase = htoi(*p++);
375 continue;
376
377 case 'l':
378 save = ap[--i];
379 ap[i]='-';
380 load1arg(&ap[i]);
381 ap[i]=save;
382 break;
383
384 case 'x':
385 xflag++;
386 continue;
387
388 case 'X':
389 Xflag++;
390 continue;
391
392 case 'S':
393 Sflag++;
394 continue;
395
396 case 'r':
397 rflag++;
398 arflag++;
399 continue;
400
401 case 's':
402 sflag++;
403 xflag++;
404 continue;
405
406 case 'n':
407 nflag++;
408 continue;
409
410 case 'N':
411 nflag = 0;
412 continue;
413
414 case 'd':
415 dflag++;
416 continue;
417
418 case 'i':
419 iflag++;
420 continue;
421
422 case 't':
423 trace++;
424 continue;
425
426 case 'z':
427 zflag++;
428 continue;
429
430 default:
431 error(1, "bad flag");
432 } /*endsw*/
433 break;
434 } /*endfor*/
435 } else
436 load1arg(ap);
437 }
438 endload(argc, argv);
439 exit(0);
440}
441
442/* used after pass 1 */
443long torigin;
444long dorigin;
445long borigin;
446long database;
447
448endload(argc, argv)
449int argc;
450char **argv;
451{
452 register int c, i;
453 long dnum;
454 register char *ap, **p;
455
456 brk(nextsym);
457 filname = 0;
458 middle();
459 setupout();
460 if (-1==(local=sbrk(NSYMPR*sizeof(*local)))) error(1,"Memory overflow");
461 p = argv+1;
462 libp = liblist;
463 for (c=1; c<argc; c++) {
464 ap = *p++;
465 if (trace) printf("%s:\n", ap);
466 if (*ap == '-') {
467 for (i=1; ap[i]; i++) {
468 switch (ap[i]) {
469 case 'D':
470 for (dnum = htoi(*p); dorigin<dnum; dorigin++) putc(0, dout);
471 case 'T':
472 case 'u':
473 case 'e':
474 case 'o':
475 case 'v':
476 ++c;
477 ++p;
478
479 default:
480 continue;
481
482 case 'l':
483 ap[--i]='-';
484 load2arg(&ap[i]);
485 break;
486 } /*endsw*/
487 break;
488 } /*endfor*/
489 } else
490 load2arg(ap);
491 }
492 finishout();
493}
494
495record(c, nam)
496int c;
497STRING nam;
498{
499 register OVERLAY *v;
500
501 v = &vnodes[vindex++];
502 v->argsav = c;
503 v->symsav = nextsym-symtab;
504 v->libsav = libp;
505 v->vname = nam;
506 v->offt = tsize;
507 v->offd = dsize;
508 v->offb = bsize;
509 v->offtr = trsize;
510 v->offdr = drsize;
511 v->offs = ssize;
512 v->ctsav = ctrel;
513 v->cdsav = cdrel;
514 v->cbsav = cbrel;
515}
516
517restore(vscan)
518int vscan;
519{
520 register OVERLAY *v;
521 register SYMBOL *saved,*sp;
522
523 v = &vnodes[vscan];
524 vindex = vscan+1;
525 libp = v->libsav;
526 ctrel = v->ctsav;
527 cdrel = v->cdsav;
528 cbrel = v->cbsav;
529 tsize = v->offt;
530 dsize = v->offd;
531 bsize = v->offb;
532 trsize = v->offtr;
533 drsize = v->offdr;
534 ssize = v->offs;
535 saved = symtab + v->symsav;
536 sp = nextsym;
537 while (sp>saved)
538 hshtab[(--sp)->symhash]=0;
539 nextsym = saved;
540}
541
542/* scan file to find defined symbols */
543load1arg(cp)
544register char *cp;
545{
546 long loc;
547
548 if (getfile(cp)==0)
549 load1(0, 0L);
550 else {
551 loc = sizeof(int);
552 for (;;) {
553 dseek(&text, loc, (long)sizeof(archdr));
554 if (text.size <= 0) {
555 libp->loc = -1;
556 if( ++libp >= liblist + NROUT)
557 error(1,"liblist overflow");
558 /* thanks to Dennis Wasley */
559 return;
560 }
561 mget((short *)&archdr, sizeof archdr, &text);
562 if (load1(1, loc+sizeof(archdr))) {
563 libp->loc = loc;
564 libp++;
565 }
566#ifndef vax
567 if (archdr.ar_size.loword==0) fixl(&archdr.ar_size);
568#endif
569 loc += round(archdr.ar_size, 1) + sizeof(archdr);
570 }
571 }
572 close(infil);
573}
574
575/* single file or archive member */
576load1(libflg, loc)
577long loc;
578{
579 register SYMBOL *sp;
580 SYMBOL *savnext;
581 int ndef, nlocal, type;
582
583 readhdr(loc);
584 ctrel = tsize;
585 cdrel += dsize;
586 cbrel += bsize;
587 ndef = 0;
588 nlocal = sizeof(cursym);
589 savnext = nextsym;
590/* if (filhdr.a_trsize+filhdr.a_drsize==0) {
591/* error(0, "No relocation bits");
592/* return(0);
593/* }
594*/
595 loc += filhdr.a_text + filhdr.a_data +
596 filhdr.a_trsize + filhdr.a_drsize + sizeof(filhdr);
597 dseek(&text, loc, filhdr.a_syms);
598 while (text.size > 0) {
599 symget(&cursym, &text);
600 type = cursym.stype;
601 if ((type&EXTERN)==0) {
602 if (Xflag==0 || cursym.sname[0]!='L' || type & STABTYPS)
603 nlocal += sizeof cursym;
604 continue;
605 }
606 symreloc();
607 if (enter(lookup()))
608 continue;
609 if ((sp = lastsym)->stype != EXTERN+UNDEF)
610 continue;
611 if (cursym.stype == EXTERN+UNDEF) {
612 if (cursym.svalue > sp->svalue)
613 sp->svalue = cursym.svalue;
614 continue;
615 }
616 if (sp->svalue != 0 && cursym.stype == EXTERN+TEXT)
617 continue;
618 ndef++;
619 sp->stype = cursym.stype;
620 sp->svalue = cursym.svalue;
621 }
622 if (libflg==0 || ndef) {
623 tsize += filhdr.a_text;
624 dsize += round(filhdr.a_data, FW);
625 bsize += round(filhdr.a_bss, FW);
626 ssize += nlocal;
627 trsize += filhdr.a_trsize;
628 drsize += filhdr.a_drsize;
629 return(1);
630 }
631 /*
632 * No symbols defined by this library member.
633 * Rip out the hash table entries and reset the symbol table.
634 */
635 while (nextsym>savnext)
636 hshtab[(--nextsym)->symhash]=0;
637 return(0);
638}
639
640middle()
641{
642 register SYMBOL *sp, *symp;
643 long csize, t, corigin, ocsize;
644 int nund, rnd;
645 char s;
646
647 torigin = 0;
648 dorigin = 0;
649 borigin = 0;
650
651 p_data = *slookup("_data");
652 p_etext = *slookup("_etext");
653 p_edata = *slookup("_edata");
654 p_end = *slookup("_end");
655 /*
656 * If there are any undefined symbols, save the relocation bits.
657 */
658 symp = nextsym;
659 if (rflag==0) {
660 for (sp = symtab; sp<symp; sp++)
661 if (sp->stype==EXTERN+UNDEF && sp->svalue==0
662 && sp!=p_end && sp!=p_edata && sp!=p_etext
663 && sp!=p_data) {
664 rflag++;
665 dflag = 0;
666 break;
667 }
668 }
669 if (rflag)
670 sflag = iflag = 0;
671 /*
672 * Assign common locations.
673 */
674 csize = 0;
675 database = round(tsize+textbase, (nflag? PAGRND:FW));
676 if (dflag || rflag==0) {
677 ldrsym(p_data, (long)0 , EXTERN+DATA);
678 ldrsym(p_etext, tsize, EXTERN+TEXT);
679 ldrsym(p_edata, dsize, EXTERN+DATA);
680 ldrsym(p_end, bsize, EXTERN+BSS);
681 for (sp = symtab; sp<symp; sp++) {
682 if ((s=sp->stype)==EXTERN+UNDEF && (t = sp->svalue)!=0) {
683 if (t>DW)
684 rnd = DW;
685 else if (t>FW)
686 rnd = FW;
687 else
688 rnd = HW;
689 csize = round(csize, rnd);
690 sp->svalue = csize;
691 sp->stype = EXTERN+COMM;
692 ocsize = csize;
693 csize += t;
694 }
695 if (((s&TMASK) == EXTERN+UNDEF) && (s & STABTYPS)) {
696 sp->svalue = ocsize;
697 sp->stype = (s & STABTYPS) | (EXTERN+COMM);
698 }
699 }
700 }
701 /*
702 * Now set symbols to their final value
703 */
704 csize = round(csize, FW);
705 torigin = textbase;
706 dorigin = database;
707 corigin = dorigin + dsize;
708 borigin = corigin + csize;
709/*
710 if (zflag)
711 borigin = round(borigin, PAGRND);
712*/
713 cdorel = 0;
714 cborel = dsize+csize;
715 nund = 0;
716 for (sp = symtab; sp<symp; sp++) switch (sp->stype & TMASK) {
717 case EXTERN+UNDEF:
718 errlev |= 01;
719 if ((arflag==0 || dflag) && sp->svalue==0) {
720 if (nund==0)
721 printf("Undefined:\n");
722 nund++;
723 printf("%.8s\n", sp->sname);
724 }
725 continue;
726
727 case EXTERN+ABS:
728 default:
729 continue;
730
731 case EXTERN+TEXT:
732 sp->svalue += torigin;
733 continue;
734
735 case EXTERN+DATA:
736 sp->svalue += dorigin;
737 continue;
738
739 case EXTERN+BSS:
740 sp->svalue += borigin;
741 continue;
742
743 case EXTERN+COMM:
744 sp->stype = (sp->stype & STABTYPS) | (EXTERN+BSS);
745 sp->svalue += corigin;
746 continue;
747 }
748 if (sflag || xflag)
749 ssize = 0;
750 bsize += csize;
751 nsym = ssize / (sizeof cursym);
752}
753
754ldrsym(asp, val, type)
755long val;
756SYMBOL *asp;
757{
758 register SYMBOL *sp;
759
760 if ((sp = asp) == 0)
761 return;
762 if (sp->stype != EXTERN+UNDEF || sp->svalue) {
763 printf("%.8s: ", sp->sname);
764 error(0, "Multiply defined (internal)");
765 return;
766 }
767 sp->stype = type;
768 sp->svalue = val;
769}
770
771extern char _sibuf[BUFSIZ]; /* the space is forced upon us; might as well use it */
772
773setupout()
774{
775 int bss;
776 tout = fopen(ofilename, "w");
777 if (tout==NULL)
778 error(1, "cannot create output");
779 setbuf(tout,_sibuf);
780 dout = tcreat(&doutn, "/tmp/ldaaXXXXX");
781 if (sflag==0 || xflag==0)
782 sout = tcreat(&soutn, "/tmp/ldbaXXXXX");
783 if (rflag) {
784 trout = tcreat(&troutn, "/tmp/ldcaXXXXX");
785 drout = tcreat(&droutn, "/tmp/lddaXXXXX");
786 }
787 filhdr.a_magic = nflag? NMAGIC:OMAGIC;
788 if (zflag)
789 filhdr.a_magic = nflag?0413:0412;
790 filhdr.a_text = nflag? tsize:round(tsize, FW);
791 if (zflag)
792 filhdr.a_text = round(tsize, PAGRND);
793 filhdr.a_data = dsize;
794 if (zflag)
795 filhdr.a_data = round(dsize, PAGRND);
796 bss = bsize - (filhdr.a_data - dsize);
797 if (bss < 0)
798 bss = 0;
799 filhdr.a_bss = bss;
800 filhdr.a_trsize = trsize;
801 filhdr.a_drsize = drsize;
802 filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*(nextsym-symtab));
803 if (entrypt) {
804 if (entrypt->stype!=EXTERN+TEXT)
805 error(0, "Entry point not in text");
806 else
807 filhdr.a_entry = entrypt->svalue;
808 } else
809 filhdr.a_entry=0;
810 filhdr.a_trsize = (rflag ? trsize:0);
811 filhdr.a_drsize = (rflag ? drsize:0);
812 writel(&filhdr,8,tout);
813 if (zflag)
814 fseek(tout, PAGSIZ, 0);
815}
816
817FILE *
818tcreat(namep, name)
819char **namep, *name;
820{
821 register FILE *fp;
822 register char *tnm;
823
824 tnm = mktemp(name);
825 if ((fp = fopen(tnm, "w")) == NULL)
826 error(1, "Cannot create temp file");
827 chmod(tnm, 0600);
828 *namep = tnm;
829 return(fp);
830}
831
832load2arg(acp)
833char *acp;
834{
835 register char *cp;
836 register LIBLIST *lp;
837
838 cp = acp;
839 if (getfile(cp) == 0) {
840 while (*cp)
841 cp++;
842 while (cp >= acp && *--cp != '/');
843 mkfsym(++cp);
844 load2(0L);
845 } else { /* scan archive members referenced */
846 for (lp = libp; lp->loc != -1; lp++) {
847 dseek(&text, lp->loc, (long)sizeof(archdr));
848 mget((short *)&archdr, sizeof(archdr), &text);
849 mkfsym(archdr.ar_name);
850 load2(lp->loc + (long)sizeof(archdr));
851 }
852 libp = ++lp;
853 }
854 close(infil);
855}
856
857load2(loc)
858long loc;
859{
860 register SYMBOL *sp;
861 register LOCAL *lp;
862 register int symno;
863 int type;
864
865 readhdr(loc);
866 ctrel = torigin;
867 cdrel += dorigin;
868 cbrel += borigin;
869 /*
870 * Reread the symbol table, recording the numbering
871 * of symbols for fixing external references.
872 */
873 lp = local;
874 symno = -1;
875 loc += sizeof(filhdr);
876 dseek(&text, loc+filhdr.a_text+filhdr.a_data+
877 filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms);
878 while (text.size > 0) {
879 symno++;
880 symget(&cursym, &text);
881 symreloc();
882 type = cursym.stype;
883 if ((type&EXTERN) == 0) {
884 if (!sflag&&!xflag&&
885 (!Xflag||cursym.sname[0]!='L'||type&STABTYPS))
886 symwrite(&cursym, 1, sout);
887 continue;
888 }
889 if ((sp = *lookup()) == 0)
890 error(1, "internal error: symbol not found");
891 if (cursym.stype == EXTERN+UNDEF) {
892 if (lp >= local+NSYMPR)
893 error(1, "Local symbol overflow");
894 lp->locindex = symno;
895 lp++->locsymbol = sp;
896 continue;
897 }
898 if(cursym.stype & STABTYPS) continue;
899 if (cursym.stype!=sp->stype || cursym.svalue!=sp->svalue) {
900 printf("%.8s: ", cursym.sname);
901 error(0, "Multiply defined");
902 }
903 }
904 dseek(&text, loc, filhdr.a_text);
905 dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
906 load2td(lp, ctrel, tout, trout);
907 dseek(&text, loc+filhdr.a_text, filhdr.a_data);
908 dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, filhdr.a_drsize);
909 load2td(lp, cdrel, dout, drout);
910 while (filhdr.a_data&FW) {
911 putc(0, dout); filhdr.a_data++;
912 }
913 torigin += filhdr.a_text;
914 dorigin += filhdr.a_data;
915 borigin += filhdr.a_bss;
916 cdorel += filhdr.a_data;
917 cborel += filhdr.a_bss;
918}
919
920load2td(lp, creloc, b1, b2)
921LOCAL *lp;
922long creloc;
923FILE *b1, *b2;
924{
925 register r1;
926 register char r2;
927 register long t;
928 register SYMBOL *sp;
929 long tw,u,l;
930
931 for (;;) {
932 if (reloc.size==0) {while (text.size) putc(get(&text),b1); break;}
933 t=getl(&reloc); /* position of relocatable stuff */
934 if (rflag) putl(t+creloc,b2); /* remember for subsequent link editing */
935 while (text.pos<t) putc(get(&text),b1); /* advance to proper position */
936 r1=get3(&reloc); /* kind of relocation */
937 r2 = getb(&reloc);
938 switch (r2&06) {/* read raw datum according to its length */
939 case LEN1: tw=get(&text); break;
940 case LEN2: tw=gets(&text); break;
941 case LEN4: tw=getl(&text); break;
942 }
943 if (r2&REXT) {
944 sp=lookloc(lp,r1); /* find the symbol */
945 if (sp->stype==EXTERN+UNDEF) { /* still undefined */
946 r2=(r2&(REFMASK+REXT+ROFF));
947 r1 = nsym+(sp-symtab); /* new reloc */
948 }
949 else {
950 if (sp->stype==EXTERN+DATA && r2&ROFF) {
951 r1=RDATAO;
952 r2&=REFMASK;
953 }
954 else if (sp->stype==EXTERN+BSS && r2&ROFF) {
955 r1=RBSSO;
956 r2&=REFMASK;
957 }
958 else if (sp->stype==EXTERN+ABS && r2&ROFF) {
959 r1=RABSO;
960 r2&=REFMASK;
961 }
962 else if (sp->stype==EXTERN+TEXT && r2&ROFF) {
963 r1=RTEXTO;
964 r2&=REFMASK;
965 }
966 else {if (r2&ROFF) {if (rflag) {error(0,"!-r; see JFR"); rflag=0;}}
967 else tw += database;
968 r1=sp->stype&TYPE;
969 r2&=REFMASK;
970 }
971 tw += sp->svalue - database;
972 }
973 } else switch (r1&TYMASK) {
974 case RTEXT: tw += ctrel; break;
975 case RTEXTO:tw += round(filhdr.a_text,PAGRND)+ctrel-database; break;
976 case RDATA: tw += cdrel; break;
977 case RDATAO:tw += cdorel; break;
978 case RBSS: tw += cbrel; break;
979 case RBSSO: tw += cborel-filhdr.a_data; break;
980 case RABSO: tw += round(filhdr.a_text,PAGRND)-database; break;
981 }
982 if (rflag) { /* remember for subsequent link editing */
983 put3(r1,b2);
984 putb(r2,b2);
985 }
986 if (r2&PCREL) tw -= creloc; /* assembler already subtracted text.pos */
987 switch (r2&06) {/* output relocated datum according to its length */
988 case LEN1: l= -128; u=127; putc((char)tw,b1); break;
989 case LEN2: l= -32768; u=32767; puts((short)tw,b1); break;
990 case LEN4: l=0x80000000; u=0x7FFFFFFF; putl(tw,b1); break;
991 }
992 if (tw<l || u<tw) error(0,"Displacement overflow");
993 }
994}
995
996finishout()
997{
998
999 if (!nflag)
1000 while (tsize&FW) {
1001 putc(0, tout); tsize++;
1002 }
1003 if (zflag) {
1004 while (tsize&PAGRND) {
1005 putc(0, tout); tsize++;
1006 }
1007 while (dsize&PAGRND) {
1008 putc(0, dout); dsize++;
1009 }
1010 }
1011 fclose(dout);
1012 copy(doutn);
1013 if (rflag) {
1014 fclose(trout);
1015 copy(troutn);
1016 fclose(drout);
1017 copy(droutn);
1018 }
1019 if (sflag==0) {
1020 if (xflag==0) {
1021 fclose(sout);
1022 copy(soutn);
1023 }
1024 symwrite(symtab, nextsym-symtab, tout);
1025 }
1026 fclose(tout);
1027 if (!ofilfnd) {
1028 unlink("a.out");
1029 link("l.out", "a.out");
1030 ofilename = "a.out";
1031 }
1032 delarg = errlev;
1033 delexit();
1034}
1035
1036copy(np)
1037char *np;
1038{
1039 register c;
1040 register FILE *fp;
1041
1042 if ((fp = fopen(np, "r")) == NULL)
1043 error(1, "cannot recopy output");
1044 while ((c = getc(fp)) != EOF)
1045 putc(c, tout);
1046 fclose(fp);
1047}
1048
1049mkfsym(s)
1050char *s;
1051{
1052
1053 if (sflag || xflag)
1054 return;
1055 cp8c(s, cursym.sname);
1056 cursym.stype = TEXT;
1057 cursym.svalue = torigin;
1058 symwrite(&cursym, 1, sout);
1059}
1060
1061mget(loc, n, sp)
1062register STREAM *sp;
1063register char *loc;
1064{
1065 register char *p;
1066
1067 if ((sp->nibuf -= n) >= 0) {
1068 if ((sp->size -= n) > 0) {
1069 p = sp->ptr;
1070 sp->pos += n;
1071 do
1072 *loc++ = *p++;
1073 while (--n);
1074 sp->ptr = p;
1075 return;
1076 } else
1077 sp->size += n;
1078 }
1079 sp->nibuf += n;
1080 do {
1081 *loc++ = get(sp);
1082 } while (--n);
1083}
1084
1085short
1086gets(sp) STREAM *sp; {
1087short t; mget(&t,2,sp); return(t);
1088}
1089
1090char
1091getb(sp) STREAM *sp; {
1092char t; mget(&t,1,sp); return(t);
1093}
1094
1095long
1096get3(sp) STREAM *sp; {
1097long t; t=0; mget(&t,3,sp); return(t);
1098}
1099
1100long
1101getl(sp) STREAM *sp; {
1102 long t; mget(&t,4,sp);
1103#ifndef vax
1104 fixl(&t);
1105#endif
1106 return(t);
1107}
1108
1109symget(sp,f) SYMBOL *sp; STREAM *f; {
1110 mget(sp,sizeof(*sp),f);
1111#ifndef vax
1112 fixl(&sp->svalue);
1113#endif
1114}
1115
1116dseek(sp, loc, s)
1117register STREAM *sp;
1118long loc, s;
1119{
1120 register PAGE *p;
1121 register b, o;
1122 int n;
1123
1124 b = loc>>BSHIFT;
1125 o = loc&BMASK;
1126 if (o&01)
1127 error(1, "loader error; odd offset");
1128 --sp->pno->nuser;
1129 if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b)
1130 if (p->nuser==0 || (p = &page[0])->nuser==0) {
1131 if (page[0].nuser==0 && page[1].nuser==0)
1132 if (page[0].bno < page[1].bno)
1133 p = &page[0];
1134 p->bno = b;
1135 lseek(infil, loc & ~(long)BMASK, 0);
1136 if ((n = read(infil, p->buff, sizeof(p->buff))) < 0)
1137 n = 0;
1138 p->nibuf = n;
1139 } else
1140 error(1, "No pages");
1141 ++p->nuser;
1142 sp->bno = b;
1143 sp->pno = p;
1144 if (s != -1) {sp->size = s; sp->pos = 0;}
1145 sp->ptr = (short *)(p->buff + o);
1146 if ((sp->nibuf = p->nibuf-o) <= 0)
1147 sp->size = 0;
1148}
1149
1150char
1151get(asp)
1152STREAM *asp;
1153{
1154 register STREAM *sp;
1155
1156 sp = asp;
1157 if ((sp->nibuf -= sizeof(char)) < 0) {
1158 dseek(sp, ((long)(sp->bno+1)<<BSHIFT), (long)-1);
1159 sp->nibuf -= sizeof(char);
1160 }
1161 if ((sp->size -= sizeof(char)) <= 0) {
1162 if (sp->size < 0)
1163 error(1, premeof);
1164 ++fpage.nuser;
1165 --sp->pno->nuser;
1166 sp->pno = &fpage;
1167 }
1168 sp->pos += sizeof(char);
1169 return(*sp->ptr++);
1170}
1171
1172getfile(acp)
1173STRING acp;
1174{
1175 register STRING cp;
1176 register int c;
1177 int arcmag;
1178
1179 cp = acp;
1180 infil = -1;
1181 archdr.ar_name[0] = '\0';
1182 filname = cp;
1183 if (cp[0]=='-' && cp[1]=='l') {
1184 char *locfilname = "/usr/local/lib/libxxxxxxxxxxxxxxx";
1185 if(cp[2] == '\0')
1186 cp = "-la";
1187 filname = "/usr/lib/libxxxxxxxxxxxxxxx";
1188 for(c=0; cp[c+2]; c++) {
1189 filname[c+12] = cp[c+2];
1190 locfilname[c+18] = cp[c+2];
1191 }
1192 filname[c+12] = locfilname[c+18] = '.';
1193 filname[c+13] = locfilname[c+19] = 'a';
1194 filname[c+14] = locfilname[c+20] = '\0';
1195 if ((infil = open(filname+4, 0)) >= 0) {
1196 filname += 4;
1197 } else if ((infil = open(filname, 0)) < 0) {
1198 filname = locfilname;
1199 }
1200 }
1201 if (infil == -1 && (infil = open(filname, 0)) < 0)
1202 error(1, "cannot open");
1203 page[0].bno = page[1].bno = -1;
1204 page[0].nuser = page[1].nuser = 0;
1205 text.pno = reloc.pno = &fpage;
1206 fpage.nuser = 2;
1207 dseek(&text, 0L, (long)sizeof(int));
1208 if (text.size <= 0)
1209 error(1, premeof);
1210 mget(&arcmag, sizeof(arcmag), &text);
1211 return(arcmag==ARMAG);
1212}
1213
1214SYMBOL **lookup()
1215{
1216 int i;
1217 BOOL clash;
1218 register SYMBOL **hp;
1219 register char *cp, *cp1;
1220
1221 i = 0;
1222 for (cp = cursym.sname; cp < &cursym.sname[8];)
1223 i = (i<<1) + *cp++;
1224 for (hp = &hshtab[(i&077777)%NSYM+2]; *hp!=0;) {
1225 cp1 = (*hp)->sname;
1226 clash=FALSE;
1227 for (cp = cursym.sname; cp < &cursym.sname[8];)
1228 if (*cp++ != *cp1++) {
1229 clash=TRUE;
1230 break;
1231 }
1232 if (clash) {
1233 if (++hp >= &hshtab[NSYM+2])
1234 hp = hshtab;
1235 } else
1236 break;
1237 }
1238 return(hp);
1239}
1240
1241SYMBOL **slookup(s)
1242char *s;
1243{
1244 cp8c(s, cursym.sname);
1245 cursym.stype = EXTERN+UNDEF;
1246 cursym.svalue = 0;
1247 return(lookup());
1248}
1249
1250enter(hp)
1251register SYMBOL **hp;
1252{
1253 register SYMBOL *sp;
1254
1255 if (*hp==0) {
1256 if ((nextsym-symtab)>=NSYM)
1257 error(1, "Symbol table overflow");
1258 if ((nextsym-symtab)>=nsym) {
1259 if (-1==sbrk(NSYM/5 * sizeof(*symtab))) error(1,"Memory overflow");
1260 nsym += NSYM/5;
1261 }
1262 *hp = lastsym = sp = nextsym++;
1263 cp8c(cursym.sname, sp->sname);
1264 sp->stype = cursym.stype;
1265 sp->symhash = hp-hshtab;
1266 sp->svalue = cursym.svalue;
1267 return(1);
1268 } else {
1269 lastsym = *hp;
1270 return(0);
1271 }
1272}
1273
1274symreloc()
1275{
1276 switch (cursym.stype & 017) {
1277
1278 case TEXT:
1279 case EXTERN+TEXT:
1280 cursym.svalue += ctrel;
1281 return;
1282
1283 case DATA:
1284 case EXTERN+DATA:
1285 cursym.svalue += cdrel;
1286 return;
1287
1288 case BSS:
1289 case EXTERN+BSS:
1290 cursym.svalue += cbrel;
1291 return;
1292
1293 case EXTERN+UNDEF:
1294 return;
1295 }
1296 if (cursym.stype&EXTERN)
1297 cursym.stype = EXTERN+ABS;
1298}
1299
1300error(n, s)
1301char *s;
1302{
1303 if (errlev==0)
1304 printf("ld:");
1305 if (filname) {
1306 printf("%s", filname);
1307 if (archdr.ar_name[0])
1308 printf("(%.14s)", archdr.ar_name);
1309 printf(": ");
1310 }
1311 printf("%s\n", s);
1312 if (n)
1313 delexit();
1314 errlev = 2;
1315}
1316
1317SYMBOL *
1318lookloc(lp, r)
1319register LOCAL *lp;
1320{
1321 register LOCAL *clp;
1322 register sn;
1323
1324 sn = r;
1325 for (clp = local; clp<lp; clp++)
1326 if (clp->locindex == sn)
1327 return(clp->locsymbol);
1328 error(1, "Local symbol botch");
1329}
1330
1331readhdr(loc)
1332long loc;
1333{
1334 long *p; int i;
1335 dseek(&text, loc, (long)sizeof(filhdr));
1336 mget((short *)&filhdr, sizeof(filhdr), &text);
1337#ifndef vax
1338 for (p= &filhdr,i=8;--i>=0;) fixl(p++);
1339#endif
1340 if (filhdr.a_magic!=A_MAGIC1 && filhdr.a_magic!=A_MAGIC2 &&
1341 filhdr.a_magic!=A_MAGIC3 && filhdr.a_magic!=A_MAGIC4)
1342 error(1,"Bad magic number");
1343 if (filhdr.a_text&01 || filhdr.a_data&01) {
1344 printf("tsize=%X dsize=%X\n",filhdr.a_text,filhdr.a_data);
1345 error(1, "Text/data size odd");
1346 }
1347 filhdr.a_bss = round(filhdr.a_bss, FW);
1348 if (filhdr.a_magic == NMAGIC) {
1349 cdrel = -round(filhdr.a_text, PAGRND);
1350 cbrel = cdrel - filhdr.a_data;
1351 } else if (filhdr.a_magic == OMAGIC) {
1352 cdrel = -filhdr.a_text;
1353 cbrel = cdrel - filhdr.a_data;
1354 } else
1355 error(1, "Bad format");
1356}
1357
1358cp8c(from, to)
1359char *from, *to;
1360{
1361 register char *f, *t, *te;
1362
1363 f = from;
1364 t = to;
1365 te = t+8;
1366 while ((*t++ = *f++) && t<te);
1367 while (t<te)
1368 *t++ = 0;
1369}
1370
1371eq(s1, s2)
1372STRING s1;
1373STRING s2;
1374{
1375 while (*s1==*s2++)
1376 if ((*s1++)==0)
1377 return(TRUE);
1378 return(FALSE);
1379}
1380
1381long
1382round(v, r)
1383long v;
1384unsigned r;
1385{
1386 v += r;
1387 v &= ~(long)r;
1388 return(v);
1389}
1390
1391puts(w, f)
1392FILE *f; short w; {
1393fwrite(&w,sizeof(short),1,f);
1394}
1395
1396putb(w, f)
1397FILE *f; char w; {
1398fwrite(&w,sizeof(char),1,f);
1399}
1400
1401put3(w, f)
1402FILE *f; long w; {
1403fwrite(&w,3,1,f);
1404}
1405
1406putl(w, f)
1407FILE *f; long w; {
1408#ifndef vax
1409 fixl(&w);
1410#endif
1411 fwrite(&w,sizeof(long),1,f);
1412}