|
|
1.1 root 1: /*
2: * One pass Coff Loader.
3: * Acts as ld and drvld. Will be mkshrlb when the specs are done.
4: *
5: * By Charles Fiterman for Mark Williams 3/30/92.
6: */
7: #include "ld.h"
8: #include <stdlib.h>
9: #include <signal.h>
10: #include <ctype.h>
11: #include <path.h>
12:
13: flag_t reloc, /* Combine input into a new .o not an executable */
14: nosym, /* No symbol table out. */
15: watch, /* Produce a trace */
16: noilcl, /* Discard C local symbols beginning .L */
17: nolcl, /* Discard all local symbols */
18: qflag, /* No warn on commons of different length */
19: Qflag, /* Absolute silence on everything */
20: debflg, /* Create debug data */
21: drvld, /* Called as drvld */
22: fource = -1; /* halt on error */
23:
24: int errCount;
25: int nundef;
26: mod_t *head, /* head of list of modules to load */
27: *tail, /* tail or list of modules */
28: *xhead, /* head of noload modules */
29: *xtail; /* tail of noload modules */
30: ren_t *rhead; /* rename list */
31:
32: char *ofname = "a.out"; /* output file name */
33: long comnb, comns, comnl; /* common lengths */
34: char *entrys; /* entry string */
35: sym_t *symtable[NHASH]; /* hashed symbol table */
36:
37: unsigned short osegs = NLSEG; /* the number of output segments */
38: unsigned short segMap[MAXSEG] = /* All segments map to the first four */
39: { S_TEXT, S_DATA, S_BSSD, S_COMM };
40:
41: FILEHDR fileh;
42: AOUTHDR aouth;
43: SCNHDR *secth; /* output segments */
44:
45: static long str_length;
46: static int ofd;
47: static long *file_value = NULL, file_first;
48: char *argv0;
49:
50: /*
51: * Write or die.
52: */
53: void
54: xwrite(loc, size)
55: char *loc;
56: unsigned int size;
57: {
58: if (size != write(ofd, loc, size))
59: fatal("write error"); /**/
60: }
61:
62: /*
63: * Init segment descriptors.
64: */
65: void
66: initSegs()
67: {
68: secth = alloc(sizeof(*secth) * MAXSEG);
69: strcpy(secth[S_TEXT].s_name, _TEXT);
70: secth[S_TEXT].s_flags = STYP_TEXT;
71: strcpy(secth[S_DATA].s_name, _DATA);
72: secth[S_DATA].s_flags = STYP_DATA;
73: strcpy(secth[S_BSSD].s_name, _BSS);
74: secth[S_BSSD].s_flags = STYP_BSS;
75: strcpy(secth[S_COMM].s_name, _COMMENT);
76: secth[S_COMM].s_flags = STYP_INFO;
77: }
78:
79: /*
80: * Come here on interrupt.
81: */
82: byebye()
83: {
84: driver_fail(&aouth);
85: exit(1);
86: }
87:
88: /*
89: * We are drvld not ld. Ask the system where to put the stuff.
90: */
91: getsys()
92: {
93: register int i;
94: long bsz, daddr;
95:
96: time(&fileh.f_timdat);
97: fileh.f_nscns = osegs = NLSEG;
98:
99: daddr = sizeof(fileh) + (sizeof(* secth) * osegs) +
100: (fileh.f_opthdr = sizeof(aouth));
101:
102: for (i = 0; i < S_BSSD; i++) {
103: secth[i].s_scnptr = daddr;
104: daddr += secth[i].s_size;
105: }
106: bsz = secth[S_BSSD].s_size;
107: aouth.tsize = secth[S_TEXT].s_size;
108: aouth.dsize = secth[S_DATA].s_size + bsz;
109: signal(SIGKILL, byebye);
110: if (!driver_alloc(&aouth))
111: fatal("kernel interface failed");
112: /* This will become more elaborite when the kernel is done */
113: secth[S_TEXT].s_vaddr = secth[S_TEXT].s_paddr = aouth.text_start;
114: secth[S_DATA].s_vaddr = secth[S_DATA].s_paddr = aouth.data_start;
115: secth[S_BSSD].s_vaddr = secth[S_BSSD].s_paddr = aouth.data_start + bsz;
116: aouth.dsize -= aouth.bsize = bsz;
117:
118: if (!nosym)
119: fileh.f_symptr = daddr;
120: }
121:
122: /*
123: * Set virtual bases in array of segments.
124: */
125: static
126: baseall()
127: {
128: register SCNHDR *sh;
129: int i;
130: unsigned long daddr, vaddr, size;
131:
132: time(&fileh.f_timdat);
133:
134: /* Add extra segments to real segments */
135: for (i = NLSEG; i < osegs; i++) {
136: SCNHDR *oh;
137:
138: oh = secth + i;
139: sh = secth + segMap[i];
140:
141: sh->s_size += oh->s_size;
142: sh->s_nreloc += oh->s_nreloc;
143: sh->s_nlnno += oh->s_nlnno;
144: }
145:
146: /* only output S_COMM if it has something */
147: fileh.f_nscns = secth[S_COMM].s_size ? NLSEG : S_COMM;
148:
149: size = 0;
150: daddr = sizeof(fileh) + (sizeof(* secth) * fileh.f_nscns);
151: if (reloc)
152: vaddr = 0;
153: else {
154: daddr += fileh.f_opthdr = sizeof(aouth);
155: if (fileh.f_flags & F_KER) /* kernel */
156: vaddr = KERBASE;
157: else /* executable */
158: vaddr = daddr;
159: }
160:
161: /* set s_vaddr, s_paddr, s_size, and s_scnptr for all segments */
162: for (i = 0; i < NLSEG; i++) {
163: sh = secth + i;
164: switch (i) {
165: case S_TEXT:
166: aouth.text_start = sh->s_vaddr = vaddr;
167: aouth.tsize = size = sh->s_size;
168: break;
169:
170: case S_DATA: /* data adjustment */
171: if (!reloc) {
172: if (fileh.f_flags & F_KER)
173: vaddr = (vaddr + 0x0fff) & ~0x0fffL;
174: else
175: vaddr = (vaddr & 0x0fff) + DATABASE;
176: }
177:
178: aouth.data_start = sh->s_vaddr = vaddr;
179: aouth.dsize = size = sh->s_size;
180: break;
181:
182: case S_BSSD:
183: sh->s_paddr = sh->s_vaddr = vaddr;
184: vaddr += aouth.bsize = sh->s_size;
185: sh->s_scnptr = 0;
186: continue;
187:
188: default:
189: sh->s_vaddr = vaddr;
190: size = sh->s_size;
191: }
192:
193: sh->s_paddr = sh->s_vaddr;
194: sh->s_scnptr = daddr;
195: daddr += size;
196: vaddr += size;
197: }
198:
199: /* fix new segments to point to right places */
200: for (i = 0; i < NLSEG; i++) {
201: int j;
202: long vaddr, daddr;
203:
204: sh = secth + i;
205: vaddr = sh->s_vaddr + sh->s_size; /* mark the end */
206: daddr = sh->s_scnptr + sh->s_size;
207:
208: for (j = osegs; --j >= NLSEG;) {
209: SCNHDR *oh;
210:
211: if (segMap[j] != i)
212: continue;
213:
214: oh = secth + j;
215: oh->s_vaddr = vaddr -= oh->s_size;
216: oh->s_scnptr = daddr -= oh->s_size;
217: w_message("set extra %.8s at %x %x",
218: oh->s_name, vaddr, daddr);
219: }
220: }
221:
222: /* set relocations for all segments */
223: for (i = 0; i < NLSEG; i++) {
224: sh = secth + i;
225: if (!reloc || (S_BSSD == i) || !sh->s_nreloc) {
226: sh->s_relptr = 0;
227: continue;
228: }
229: sh->s_relptr = daddr;
230: daddr += sh->s_nreloc * RELSZ;
231: }
232:
233: /* set line numbers for all segments */
234: for (i = 0; i < NLSEG; i++) {
235: sh = secth + i;
236: if (!debflg || !sh->s_nlnno) {
237: sh->s_nlnno = sh->s_lnnoptr = 0;
238: continue;
239: }
240: sh->s_lnnoptr = daddr;
241: daddr += sh->s_nlnno * LINESZ;
242: }
243:
244: if (!nosym)
245: fileh.f_symptr = daddr;
246: }
247:
248: /*
249: * return entry point
250: */
251: static long
252: lentry(str)
253: char *str;
254: {
255: if (NULL == str) /* not user specified */
256: return(aouth.text_start);
257:
258: /* If an octal number use that */
259: {
260: register unsigned char c, *s;
261: long oaddr = 0;
262:
263: /* Try to scan whole string as octal. */
264: for (s = str; c = *s++;) {
265: if (('0' > c) || (c > '7'))
266: break;
267: oaddr = (oaddr * 8) + (c - '0');
268: }
269:
270: if (!c)
271: return (oaddr);
272: }
273:
274: /* Search for string in symbol table. */
275: {
276: register sym_t *sp;
277: char work[SYMNMLEN + 1];
278:
279: for (sp = symtable[crc16(str) % NHASH];
280: sp != NULL;
281: sp = sp->next) {
282: if ((sp->sym.n_sclass == C_EXT) &&
283: !strcmp(symName(&(sp->sym), work), str)) {
284: if (sp->sym.n_scnum != (S_TEXT + 1))
285: message("entry point '%s' not in .text");
286: return(sp->sym.n_value);
287: }
288: }
289:
290: message("entry point '%s' undefined", str); /**/
291: return (aouth.text_start);
292: }
293: }
294:
295: /*
296: * Define referenced special symbols.
297: */
298: void
299: symBind(sn, ldrv, name, loc)
300: int sn, ldrv;
301: char *name;
302: long loc;
303: {
304: register SYMENT *sym;
305: register sym_t *sp;
306: char work[SYMNMLEN + 1];
307:
308: for (sp = symtable[crc16(name) % NHASH]; sp != NULL; sp = sp->next) {
309: sym = &(sp->sym);
310: if ((sym->n_sclass != C_EXT) ||
311: strcmp(symName(sym, work), name))
312: continue;
313:
314: if (undefined(sym)) {
315: nundef--;
316: sym->n_scnum = sn + 1;
317: sym->n_value = loc;
318: sp->mod = NULL; /* not defined in any mod */
319: return;
320: }
321:
322: if (ldrv)
323: return;
324: else
325: spwarn(sp, "redefines builtin symbol");
326: /* Some symbols such as __end and __end_text
327: * are special to the linker. In general symbols
328: * beginning __ are reserved to implementors and
329: * should be avoided by users.
330: * Your definition has been used. */
331: }
332: }
333:
334: /*
335: * Add reference to symbol table
336: */
337: void
338: undef(s)
339: char *s;
340: {
341: SYMENT lds;
342:
343: memset(&lds, '\0', sizeof(lds));
344: lds.n_offset = (long)s; /* point symbol at our stuff */
345: lds.n_sclass = C_EXTDEF; /* mark undefined */
346: addsym(&lds, NULL); /* connect to no module */
347: }
348:
349: /*
350: * Show undefined symbols.
351: */
352: void
353: showUndef(sp, sym)
354: register sym_t *sp;
355: register SYMENT *sym;
356: {
357: if (undefined(sym))
358: spmsg(sp, ""); /* NODOC */
359: }
360:
361: /*
362: * Pass all symbols through a function.
363: * In a really elaborite order.
364: */
365: void
366: allSym(fun)
367: int (*fun)();
368: {
369: register SYMENT *sym;
370: register sym_t *sp;
371: register mod_t *mp;
372: register i;
373: SYMENT *symEnd;
374:
375: if (reloc) { /* We are producing another .o */
376: /*
377: * Do symbols connected to modules in module order.
378: * Only process a global symbol for it's owner.
379: */
380: for (mp = head; mp != (mod_t *)NULL; mp = mp->next) {
381: sym = ((SYMENT *)(mp->f->f_symptr));
382: symEnd = sym + mp->f->f_nsyms;
383: for (; sym < symEnd; sym += sym->n_numaux + 1) {
384: if (1 == sym->n_zeroes) { /* pointer to original */
385: sp = (sym_t *)sym->n_offset;
386: if (sp->mod == mp)
387: (*fun)(sp, &(sp->sym), mp, sym);
388: }
389: else
390: (*fun)(NULL, sym, mp, sym);
391: }
392: }
393: }
394: else {
395: /*
396: * Producing an executable.
397: */
398: for (mp = head; mp != (mod_t *)NULL; mp = mp->next) {
399: char showSym;
400:
401: sym = ((SYMENT *)(mp->f->f_symptr));
402: symEnd = sym + mp->f->f_nsyms;
403:
404: /*
405: * If first entry is not C_FILE supress
406: * all non C_EXT entries for debug, they make
407: * Orignon barf. If not debug mode and the
408: * user wants a symbol table give him everything.
409: */
410: showSym = !debflg || C_FILE == sym->n_sclass;
411:
412: for (; sym < symEnd; sym += sym->n_numaux + 1) {
413: if ((C_EXT == sym->n_sclass) && !sym->n_numaux)
414: continue; /* do later */
415:
416: /* pointer to original */
417: if (1 == sym->n_zeroes) {
418: sp = (sym_t *)sym->n_offset;
419: if (sp->mod == mp)
420: (*fun)(showSym ? sp : NULL,
421: &(sp->sym), mp, sym);
422: }
423: else
424: (*fun)(NULL, sym, mp, sym);
425: }
426: }
427:
428: /* All C_EXT entries go at the end. */
429: for (mp = head; mp != (mod_t *)NULL; mp = mp->next) {
430: sym = ((SYMENT *)(mp->f->f_symptr));
431: symEnd = sym + mp->f->f_nsyms;
432: for (; sym < symEnd; sym += sym->n_numaux + 1) {
433: if (!((C_EXT == sym->n_sclass) &&
434: !sym->n_numaux))
435: continue;
436:
437: /* pointer to original */
438: if (1 == sym->n_zeroes) {
439: sp = (sym_t *)sym->n_offset;
440: if (sp->mod == mp)
441: (*fun)(sp, &(sp->sym), mp, sym);
442: }
443: else
444: (*fun)(NULL, sym, mp, sym);
445: }
446: }
447: }
448:
449: /*
450: * Do symbols not connected to a module.
451: * These are end symbols and symbols defined with -u option
452: */
453: for (i = 0; i < NHASH; i++)
454: for (sp = symtable[i]; NULL != sp; sp = sp->next)
455: if (NULL == sp->mod)
456: (*fun)(sp, &(sp->sym), sp->mod, NULL);
457: }
458:
459: /*
460: * Fixup a symbol between passes.
461: */
462: void
463: symFix(sp, sym, mp, auxp)
464: sym_t *sp;
465: register SYMENT *sym, *auxp;
466: mod_t *mp;
467: {
468: int segn, len;
469:
470: segn = sym->n_scnum;
471: if (debflg && NULL != auxp && C_FILE == sym->n_sclass) {
472: if (NULL != file_value) /* files point in a circle */
473: *file_value = fileh.f_nsyms;
474: else
475: file_first = fileh.f_nsyms;
476: file_value = &(sym->n_value);
477: fileh.f_nsyms += sym->n_numaux + 1;
478: return;
479: }
480: if (!reloc && common(sym)) {
481: switch ((len = sym->n_value) & 3) {
482: case 2: /* 2 byte aligned */
483: sym->n_value = comns;
484: comns += len;
485: break;
486: case 0: /* 4 byte aligned */
487: sym->n_value = comnl;
488: comnl += len;
489: break;
490: default: /* unaligned */
491: sym->n_value = comnb;
492: comnb += len;
493: }
494: sym->n_scnum = S_BSSD + 1;
495: }
496: else if (segn > 0)
497: /*
498: * Correct the value to the output sector header.
499: * If mp == NULL then segn this is a constructed symbol
500: * and segn is relative to the output sector headers.
501: * Otherwise it is relative to the input sector headers
502: * but the connection to the output sector headers was
503: * placed in s_paddr by pass1.c/object().
504: */
505: sym->n_value += secth[(NULL == mp) ? segn - 1 :
506: mp->s[segn - 1].s_paddr].s_vaddr;
507:
508: if (NULL != sp && !nosym) {
509: sp->symno = fileh.f_nsyms++;
510: if (debflg)
511: fileh.f_nsyms += sym->n_numaux;
512: }
513: }
514:
515: /*
516: * Do work between passes.
517: */
518: void
519: betweenPass()
520: {
521: if (reloc)
522: fileh.f_flags |= F_AR32WR;
523: else {
524: fileh.f_flags |= F_RELFLG | F_EXEC | F_AR32WR;
525: comnb += (4 - ((comnb + comns) & 3)) & 3;
526: secth[S_BSSD].s_size += comnb + comns + comnl;
527: }
528: if (nosym)
529: fileh.f_flags |= F_LSYMS;
530:
531: if (!debflg)
532: fileh.f_flags |= F_LNNO;
533:
534: if (drvld)
535: getsys(); /* get segment base information from system */
536: else
537: baseall(); /* compute segment base information */
538:
539: if (!reloc) {
540: int i;
541:
542: /* define referenced end of segment symbols */
543: for (i = 0; i < NLSEG; i++) {
544: char end_name[20], c, *p;
545:
546: sprintf(end_name, "__end%.8s", secth[i].s_name);
547: for (p = end_name; '\0' != (c = *p); p++)
548: if (!isalnum(c))
549: *p = '_';
550:
551: symBind(i, drvld, end_name, secth[i].s_size);
552: }
553: /* define absolute end symbol */
554: symBind(S_BSSD, drvld, "__end", secth[S_BSSD].s_size);
555:
556: /* get starting addresses for 1, 2 and 4 alligned commons */
557: comnb = secth[S_BSSD].s_vaddr + secth[S_BSSD].s_size - comnb;
558: comns = comnb - comns;
559: comnl = comns - comnl;
560: }
561:
562: if (nundef && !reloc) {
563: message("the following symbols are undefined");
564: errCount--;
565: allSym(showUndef);
566: }
567:
568: switch (errCount & fource) {
569: case 0:
570: break;
571: case 1:
572: fatal("pass 1, 1 error"); /* NODOC */
573: default:
574: fatal("pass 1, %d errors", errCount);
575: /* At the end of pass 1 there were \fIn\fB errors detected.
576: * The link stopped here. */
577: }
578:
579: /* Run through symbol table doing fixups */
580: fileh.f_nsyms = 0;
581: allSym(symFix);
582:
583: if (NULL != file_value)
584: *file_value = file_first;
585:
586: aouth.entry = lentry(entrys);
587: }
588:
589: /*
590: * output symbol table.
591: */
592: static void
593: outputSym(s, sm, mp, auxp)
594: register sym_t *s;
595: register SYMENT *sm;
596: mod_t *mp;
597: SYMENT *auxp;
598: {
599: int i;
600: char *name, work[SYMNMLEN + 1];
601: SCNHDR *scn;
602: SYMENT sym;
603:
604: if (NULL == (char *)s)
605: return;
606:
607: /* build writeable copy */
608: memcpy(&sym, sm, sizeof(sym));
609: name = symName(sm, work);
610:
611: if (SYMNMLEN < (i = strlen(name))) {
612: sym.n_offset = str_length;
613: str_length += i + 1;
614: }
615: else
616: memcpy(sym.n_name, name, SYMNMLEN);
617:
618: if (!debflg || NULL == auxp)
619: sym.n_numaux = 0;
620:
621: if ((sym.n_scnum > 0) && (NULL != mp))
622: sym.n_scnum = segMap[mp->s[sym.n_scnum - 1].s_paddr] + 1;
623:
624: xwrite(&sym, SYMESZ);
625:
626: if (sym.n_numaux) {
627: int aux = 1;
628: int has_fcn = 0;
629:
630: switch(sym.n_sclass) {
631: case C_STRTAG:
632: case C_UNTAG:
633: case C_ENTAG:
634: case C_BLOCK:
635: has_fcn = 1;
636: break;
637: case C_STAT:
638: case C_FILE:
639: aux = sym.n_numaux + 1; /* dont scan for ixs */
640: break;
641: default:
642: if (ISFCN(sym.n_type))
643: has_fcn = 1;
644: }
645:
646: for (; aux <= sym.n_numaux; aux++) {
647: SYMENT *s1, *s2, *s3;
648: AUXENT *a = auxp + aux;
649:
650: /*
651: * Fix indices to new value.
652: */
653: if (a->ae_tagndx) {
654: s1 = ((SYMENT *)(mp->f->f_symptr)) +
655: a->ae_tagndx;
656: s = (sym_t *)s1->n_offset;
657: a->ae_tagndx = s->symno;
658: }
659: /* ae_endndx points past an entry */
660: if (has_fcn && a->ae_endndx) {
661: s2 = ((SYMENT *)(mp->f->f_symptr));
662: /* find the entry it points past */
663: for (s1 = s2 + a->ae_endndx;
664: (s3 = (s2 + s2->n_numaux + 1)) < s1;
665: s2 = s3)
666: ;
667: s = (sym_t *)s2->n_offset;
668: a->ae_endndx = s->symno + s2->n_numaux + 1;
669: }
670: }
671: xwrite(auxp + 1, SYMESZ * sym.n_numaux);
672: }
673: }
674:
675: /*
676: * output long symbols.
677: */
678: static void
679: longSym(s, sm)
680: register sym_t *s;
681: register SYMENT *sm;
682: {
683: int i;
684: char *name, work[SYMNMLEN + 1];
685:
686: if (NULL == s)
687: return;
688:
689: name = symName(sm, work);
690: if (SYMNMLEN < (i = strlen(name)))
691: xwrite(name, i + 1);
692: }
693:
694:
695: /*
696: * Scan this modules sections for a name match.
697: */
698: SCNHDR *
699: findSeg(mp, segn)
700: register mod_t *mp;
701: {
702: int i;
703: register SCNHDR *orsp, *isgp;
704:
705: orsp = secth + segn;
706: for (i = 0; i < mp->f->f_nscns; i++) {
707: isgp = mp->s + i;
708: if (strncmp(isgp->s_name, orsp->s_name, 8))
709: isgp = NULL;
710: else
711: break;
712: }
713: return isgp;
714: }
715:
716: /*
717: * Do relocations
718: */
719: static void
720: relocations(mp, osegn, isegn)
721: mod_t * mp;
722: {
723: register RELOC *rel;
724: char *t; /* actual text */
725: SCNHDR *isgp, *orsp;
726: unsigned i;
727: long size, told, fixr;
728:
729: if ((NULL == (isgp = findSeg(mp, isegn))) || !(size = isgp->s_size))
730: return;
731:
732: orsp = secth + osegn;
733: fixr = isgp->s_vaddr - orsp->s_vaddr;
734: t = (char *)isgp->s_scnptr;
735:
736: if (watch) {
737: errCount--;
738: mpmsg(mp, "relocating seg#%.8s[%06lx]@%06lx to %06lx r %ld",
739: isgp->s_name,
740: size,
741: isgp->s_vaddr,
742: orsp->s_vaddr,
743: isgp->s_nreloc); /* NODOC */
744: told = lseek(ofd, 0, 2);
745: }
746:
747: for (i = 0; i < isgp->s_nreloc; i++) {
748: char *ptr;
749: char *mtype;
750: sym_t *sp;
751: SYMENT *s, *sym;
752: long relf, w, at;
753: int undef;
754: char work[SYMNMLEN + 1], *name;
755: static char *pcrel = "pcrel";
756:
757: /* get reloc record */
758: rel = ((RELOC *)isgp->s_relptr) + i;
759:
760: w = rel->r_vaddr - isgp->s_vaddr;
761: if ((w < 0) || (w > size))
762: corrupt(mp);
763: ptr = t + w;
764:
765: if ((rel->r_symndx < 0) || (rel->r_symndx > mp->f->f_nsyms))
766: corrupt(mp);
767:
768: s = (SYMENT *)mp->f->f_symptr + rel->r_symndx;
769: if (1 == s->n_zeroes) { /* fixed elsewhere */
770: sp = (sym_t *)s->n_offset;
771: sym = &(sp->sym);
772: } else {
773: sp = NULL;
774: sym = s;
775: }
776: relf = sym->n_value;
777: mtype = "rel";
778: undef = undefined(sym);
779:
780: if (watch) {
781: at = told + w;
782: name = symName(sym, work);
783: }
784: /*
785: * This wierdness is to deal with a coff wierdness.
786: * The address of a common is incremented by the
787: * length of the common as seen in that module.
788: */
789: if (common(s))
790: relf -= s->n_value;
791: /*
792: * If the symbol is native to this module
793: * the reference already has this modules
794: * segment address. Subtract it.
795: */
796: else if (!undef && ((NULL == sp) || (sp->mod == mp)))
797: relf -= mp->s[s->n_scnum - 1].s_vaddr;
798:
799: /* relocate what the pointer is aimed at and leave a record */
800: #define relocate(type) *(type *)ptr = (w = *(type *)ptr) + relf
801:
802: if (reloc) {
803: rel->r_vaddr = w + orsp->s_vaddr;
804: rel->r_symndx = sp->symno;
805:
806: switch (rel->r_type) {
807: case R_PCRBYTE:
808: mtype = pcrel;
809: relf = fixr;
810:
811: case R_DIR8:
812: case R_RELBYTE:
813: relocate(char);
814: break;
815:
816: case R_PCRWORD:
817: mtype = pcrel;
818: relf = fixr;
819:
820: case R_DIR16:
821: case R_RELWORD:
822: relocate(short);
823: break;
824:
825: case R_PCRLONG:
826: mtype = pcrel;
827: relf = fixr;
828:
829: case R_DIR32:
830: case R_RELLONG:
831: relocate(long);
832: break;
833:
834: case R_NONREL:
835: mtype = "nonrel";
836: w = *(long *)ptr;
837: relf = 0;
838: break;
839:
840: default:
841: mpmsg(mp, "unknown r_type %d in segment %.8s record %d",
842: rel->r_type, isgp->s_name, i);
843: /* Unknown type on COFF relocation record. */
844: }
845:
846: if ((sym->n_scnum > 0) && (mtype != pcrel))
847: rel->r_symndx = sym->n_scnum - 1;
848:
849: if (!undef && (sym->n_scnum < 0))
850: rel->r_type = R_NONREL;
851:
852: w_message("%lx '%s'(%d %lx %lx) %lx = '%s'(%lx) + %lx",
853: at,
854: mtype,
855: rel->r_type,
856: rel->r_vaddr,
857: rel->r_symndx,
858: relf + w,
859: name,
860: sym->n_value,
861: w);
862: }
863: else {
864: switch (rel->r_type) {
865: case R_PCRBYTE:
866: mtype = pcrel;
867: relf -= orsp->s_vaddr;
868: case R_DIR8:
869: case R_RELBYTE:
870: relocate(char);
871: break;
872: case R_PCRWORD:
873: mtype = pcrel;
874: relf -= orsp->s_vaddr;
875: case R_RELWORD:
876: case R_DIR16:
877: relocate(short);
878: break;
879: case R_PCRLONG:
880: mtype = pcrel;
881: relf -= orsp->s_vaddr;
882: case R_RELLONG:
883: case R_DIR32:
884: relocate(long);
885: break;
886: case R_NONREL:
887: mtype = "nonrel";
888: w = *(long *)ptr;
889: relf = 0;
890: break;
891: default:
892: mpmsg(mp, "unknown r_type %d in segment %.8s record %d",
893: rel->r_type, isgp->s_name, i);
894: /* NODOC */
895: }
896: w_message("%lx '%s'(%d) %lx = '%s'(%lx) + %lx",
897: at,
898: mtype,
899: rel->r_type,
900: relf + w,
901: name,
902: sym->n_value,
903: w);
904: }
905: }
906: #undef relocate
907:
908: orsp->s_vaddr += size;
909: xwrite(t, (int)size);
910: }
911:
912: /*
913: * Write line records for a segment.
914: */
915: writeLine(mp, segn)
916: mod_t *mp;
917: {
918: int j;
919: long fptr;
920: AUXENT *a;
921: SYMENT *sym;
922: LINENO *l;
923: SCNHDR *scn;
924:
925: if (NULL == (scn = findSeg(mp, segn)) || (!scn->s_nlnno))
926: return;
927:
928: /*
929: * set up n_lnnoptr in symbol table to point
930: * to line records
931: */
932: l = (LINENO *)scn->s_lnnoptr;
933: fptr = lseek(ofd, 0L, 1); /* where I am */
934: for (j = 0; j < scn->s_nlnno; j++, l++) {
935: if (!l->l_lnno) {
936: sym = ((SYMENT *)(mp->f->f_symptr)) +
937: l->l_addr.l_symndx;
938: if (sym->n_numaux) {
939: a = (AUXENT *)sym + 1;
940: a->ae_lnnoptr = fptr;
941: if (1 == sym->n_zeroes) {
942: sym_t *sp;
943: sp = (sym_t *)sym->n_offset;
944: l->l_addr.l_symndx = sp->symno;
945: }
946: }
947: }
948: fptr += LINESZ;
949: }
950: xwrite(scn->s_lnnoptr, LINESZ * scn->s_nlnno);
951: }
952:
953: /*
954: * Output all data.
955: */
956: outputAll()
957: {
958: register mod_t *mp;
959: register SCNHDR *scn;
960: int i, j;
961: struct stat statbuf;
962:
963: /* Open output file */
964: ofd = qopen(ofname, 1);
965:
966: /* write header */
967: xwrite(&fileh, sizeof(fileh));
968:
969: if (!reloc) { /* if executable set bits and write opt header */
970: stat(ofname, &statbuf);
971: chmod(ofname,
972: statbuf.st_mode | S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6));
973:
974: aouth.magic = Z_MAGIC;
975: xwrite(&aouth, sizeof(aouth));
976: }
977:
978: /* write sector headers */
979: xwrite(secth, sizeof(* secth) * fileh.f_nscns);
980:
981: /* write corrected text segments */
982: for (i = 0; i < NLSEG; i++) {
983: if (i == S_BSSD)
984: continue;
985: for (j = 0; j < osegs; j++) {
986: if (segMap[j] == i)
987: for (mp = head; mp != NULL; mp = mp->next)
988: relocations(mp, i, j);
989: }
990: }
991:
992: /* write relocation if required */
993: for (i = (reloc ? 0 : S_BSSD); i < S_BSSD; i++) {
994: for (j = 0; j < osegs; j++) {
995: if (segMap[j] != i)
996: continue;
997:
998: for (mp = head; mp != NULL; mp = mp->next) {
999: if ((NULL == (scn = findSeg(mp, j))) ||
1000: !scn->s_nreloc)
1001: continue;
1002: xwrite(scn->s_relptr,
1003: RELSZ * (int)scn->s_nreloc);
1004: }
1005: }
1006: }
1007:
1008: /* write lines if required */
1009: for (i = (debflg ? 0 : NLSEG); i < NLSEG; i++) {
1010: for (j = 0; j < osegs; j++) {
1011: if (segMap[j] != i)
1012: continue;
1013:
1014: for (mp = head; mp != NULL; mp = mp->next)
1015: writeLine(mp, j);
1016: }
1017: }
1018:
1019: if (!nosym) {
1020: str_length = 4;
1021:
1022: allSym(outputSym);
1023: if (4 != str_length) {
1024: xwrite(&str_length, sizeof(str_length));
1025: allSym(longSym);
1026: }
1027: }
1028:
1029: close(ofd);
1030: }
1031:
1032: /*
1033: * Process arguements, and call other work.
1034: */
1035: main(argc, argv)
1036: char *argv[];
1037: {
1038: int c;
1039: char *specialList = NULL;
1040: char *argString = "?ge:finKl:L:o:A:O:rsu:wXxZ:qQ";
1041: char *env;
1042:
1043: /* find program name */
1044: if (NULL == (argv0 = strrchr(argv[0], '/')))
1045: argv0 = argv[0];
1046: else
1047: argv0++;
1048:
1049: env = getenv("LIBPATH");
1050: /*
1051: * drvld is an alternative name for ld.
1052: * In this mode ld will load the kernel's symbol table, so
1053: * that the loadable driver can link directly to kernel services.
1054: * After pass1 we call driver_alloc() to tell the kernel the
1055: * sizes of the driver segments, the kernel replys with locations
1056: * for them. Then we output the driver to a tmp file and execl()
1057: */
1058: if (!strcmp(argv0, "drvld")) {
1059: #if 0
1060: ofname = tmpnam(NULL);
1061: #endif
1062: argString = "?ge:l:L:u:wdq";
1063: fileh.f_flags |= F_KER;
1064: drvld = 1;
1065: /* read kernel for symbol table but don't load */
1066: readFile(kernelName(), 0, NULL);
1067: _addargs("DRVLD", &argc, &argv);
1068: }
1069: else
1070: _addargs("LD", &argc, &argv);
1071:
1072: initSegs();
1073:
1074: while (EOF != (c = getargs(argc, argv, argString))) {
1075: switch (c) {
1076: case 0: /* Not an option, read a file for load */
1077: readFile(optarg, 1, NULL);
1078: continue;
1079:
1080: case 'A': /* Read a file as an archive regardless of name */
1081: readFile(optarg, 1, ".a");
1082: continue;
1083:
1084: case 'O': /* Read a file as an object regardless of name */
1085: readFile(optarg, 1, ".o");
1086: continue;
1087:
1088: case 'f': /* attempt link even if errors */
1089: fource = 0;
1090: continue;
1091:
1092: case 'g': /* save extra segments and aux symbols */
1093: debflg ^= 1;
1094: continue;
1095:
1096: case 'e':
1097: entrys = optarg;
1098:
1099: case 'Z': /* use and erase after */
1100: case 'i': /* obselete options */
1101: case 'n':
1102: continue;
1103:
1104: case 'K': /* recompile of Kernel */
1105: fileh.f_flags |= F_KER;
1106: continue;
1107:
1108: case 'L':
1109: /*
1110: * Special filelist for lookup.
1111: */
1112: {
1113: char *new;
1114:
1115: if (NULL == specialList) {
1116: new = alloc(strlen(optarg) + 2);
1117: sprintf(new, "%c%s", LISTSEP, optarg);
1118: }
1119: else {
1120: new = alloc(
1121: strlen(specialList)+strlen(optarg)+2);
1122: sprintf(new, "%s%c%s",
1123: specialList, LISTSEP, optarg);
1124: free(specialList);
1125: }
1126: specialList = new;
1127: continue;
1128: }
1129:
1130: case 'l':
1131: /* -l<lib>: use standard lib */
1132: {
1133: char *xp, *lp;
1134:
1135: xp = alloc(strlen(optarg) + 6);
1136: sprintf(xp, "lib%s.a", optarg);
1137: lp = NULL;
1138: if (NULL != specialList)
1139: lp = path(specialList, xp, AREAD);
1140: if (NULL == lp && NULL != env)
1141: lp = path(env, xp, AREAD);
1142: if (NULL == lp)
1143: lp = path(DEFLIBPATH, xp, AREAD);
1144: if (NULL == lp)
1145: fatal("can't find '%s'", xp);
1146: /* Can't locate requested library. */
1147:
1148: readFile(lp, 1, NULL);
1149: free(xp);
1150: continue;
1151: }
1152:
1153: case 'o':
1154: ofname = optarg;
1155: continue;
1156:
1157: case 'r':
1158: reloc ^= 1; /* retain relocation information */
1159: continue;
1160:
1161: case 's':
1162: nosym ^= 1;
1163: continue;
1164:
1165: case 'u':
1166: undef(optarg);
1167: continue;
1168:
1169: case 'Q':
1170: Qflag = 1;
1171:
1172: case 'q':
1173: qflag = 1;
1174: continue;
1175:
1176: case 'w':
1177: watch ^= 1;
1178: continue;
1179:
1180: case 'X':
1181: noilcl ^= 1;
1182: continue;
1183:
1184: case 'x':
1185: nolcl ^= 1;
1186: continue;
1187:
1188: case '?':
1189: help(); /* non returning */
1190:
1191: default:
1192: usage(); /* non returning */
1193: }
1194: }
1195: if (nosym)
1196: nolcl = 1;
1197:
1198: if (reloc || debflg)
1199: nosym = nolcl = noilcl = 0;
1200:
1201: if (!fileh.f_magic)
1202: fatal("No work");
1203: /* There were no object files loaded. */
1204:
1205: betweenPass(); /* between passes */
1206: outputAll(); /* output all data */
1207:
1208: /* repass argument list to erase any -Z files */
1209: for (optix = 1; EOF != (c = getargs(argc, argv, argString));)
1210: if ('Z' == c)
1211: unlink(optarg);
1212:
1213: #if 0
1214: if (drvld) {
1215: execl(ofname, ofname, NULL); /* should never return */
1216: fatal("Cannot execute loadable driver '%s'.", ofname); /**/
1217: }
1218: #endif
1219: return (0);
1220: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.