xref: /inferno-os/utils/5l/span.c (revision 50b0dbb170df61467e42c7ea4deb0b5692d15f4c)
1 #include	"l.h"
2 
3 static struct {
4 	ulong	start;
5 	ulong	size;
6 } pool;
7 
8 void	checkpool(Prog*);
9 void 	flushpool(Prog*, int);
10 
11 void
12 span(void)
13 {
14 	Prog *p;
15 	Sym *setext, *s;
16 	Optab *o;
17 	int m, bflag, i;
18 	long c, otxt, v;
19 
20 	if(debug['v'])
21 		Bprint(&bso, "%5.2f span\n", cputime());
22 	Bflush(&bso);
23 
24 	bflag = 0;
25 	c = INITTEXT;
26 	otxt = c;
27 	for(p = firstp; p != P; p = p->link) {
28 		p->pc = c;
29 		o = oplook(p);
30 		m = o->size;
31 		if(m == 0) {
32 			if(p->as == ATEXT) {
33 				curtext = p;
34 				autosize = p->to.offset + 4;
35 				if(p->from.sym != S)
36 					p->from.sym->value = c;
37 				/* need passes to resolve branches */
38 				if(c-otxt >= 1L<<17)
39 					bflag = 1;
40 				otxt = c;
41 				continue;
42 			}
43 			diag("zero-width instruction\n%P", p);
44 			continue;
45 		}
46 		switch(o->flag & (LFROM|LTO|LPOOL)) {
47 		case LFROM:
48 			addpool(p, &p->from);
49 			break;
50 		case LTO:
51 			addpool(p, &p->to);
52 			break;
53 		case LPOOL:
54 			if ((p->scond&C_SCOND) == 14)
55 				flushpool(p, 0);
56 			break;
57 		}
58 		if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
59 			flushpool(p, 0);
60 		c += m;
61 		if(blitrl)
62 			checkpool(p);
63 	}
64 
65 	/*
66 	 * if any procedure is large enough to
67 	 * generate a large SBRA branch, then
68 	 * generate extra passes putting branches
69 	 * around jmps to fix. this is rare.
70 	 */
71 	while(bflag) {
72 		if(debug['v'])
73 			Bprint(&bso, "%5.2f span1\n", cputime());
74 		bflag = 0;
75 		c = INITTEXT;
76 		for(p = firstp; p != P; p = p->link) {
77 			p->pc = c;
78 			o = oplook(p);
79 /* very larg branches
80 			if(o->type == 6 && p->cond) {
81 				otxt = p->cond->pc - c;
82 				if(otxt < 0)
83 					otxt = -otxt;
84 				if(otxt >= (1L<<17) - 10) {
85 					q = prg();
86 					q->link = p->link;
87 					p->link = q;
88 					q->as = AB;
89 					q->to.type = D_BRANCH;
90 					q->cond = p->cond;
91 					p->cond = q;
92 					q = prg();
93 					q->link = p->link;
94 					p->link = q;
95 					q->as = AB;
96 					q->to.type = D_BRANCH;
97 					q->cond = q->link->link;
98 					bflag = 1;
99 				}
100 			}
101  */
102 			m = o->size;
103 			if(m == 0) {
104 				if(p->as == ATEXT) {
105 					curtext = p;
106 					autosize = p->to.offset + 4;
107 					if(p->from.sym != S)
108 						p->from.sym->value = c;
109 					continue;
110 				}
111 				diag("zero-width instruction\n%P", p);
112 				continue;
113 			}
114 			c += m;
115 		}
116 	}
117 
118 	if(debug['t']) {
119 		/*
120 		 * add strings to text segment
121 		 */
122 		c = rnd(c, 8);
123 		for(i=0; i<NHASH; i++)
124 		for(s = hash[i]; s != S; s = s->link) {
125 			if(s->type != SSTRING)
126 				continue;
127 			v = s->value;
128 			while(v & 3)
129 				v++;
130 			s->value = c;
131 			c += v;
132 		}
133 	}
134 
135 	c = rnd(c, 8);
136 
137 	setext = lookup("etext", 0);
138 	if(setext != S) {
139 		setext->value = c;
140 		textsize = c - INITTEXT;
141 	}
142 	if(INITRND)
143 		INITDAT = rnd(c, INITRND);
144 	if(debug['v'])
145 		Bprint(&bso, "tsize = %lux\n", textsize);
146 	Bflush(&bso);
147 }
148 
149 /*
150  * when the first reference to the literal pool threatens
151  * to go out of range of a 12-bit PC-relative offset,
152  * drop the pool now, and branch round it.
153  * this happens only in extended basic blocks that exceed 4k.
154  */
155 void
156 checkpool(Prog *p)
157 {
158 	if(pool.size >= 0xffc || immaddr((p->pc+4)+4+pool.size - pool.start+8) == 0)
159 		flushpool(p, 1);
160 	else if(p->link == P)
161 		flushpool(p, 2);
162 }
163 
164 void
165 flushpool(Prog *p, int skip)
166 {
167 	Prog *q;
168 
169 	if(blitrl) {
170 		if(skip){
171 			if(debug['v'] && skip == 1)
172 				print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start);
173 			q = prg();
174 			q->as = AB;
175 			q->to.type = D_BRANCH;
176 			q->cond = p->link;
177 			q->link = blitrl;
178 			blitrl = q;
179 		}
180 		else if(p->pc+pool.size-pool.start < 2048)
181 			return;
182 		elitrl->link = p->link;
183 		p->link = blitrl;
184 		blitrl = 0;	/* BUG: should refer back to values until out-of-range */
185 		elitrl = 0;
186 		pool.size = 0;
187 		pool.start = 0;
188 	}
189 }
190 
191 void
192 addpool(Prog *p, Adr *a)
193 {
194 	Prog *q, t;
195 	int c;
196 
197 	c = aclass(a);
198 
199 	t = zprg;
200 	t.as = AWORD;
201 
202 	switch(c) {
203 	default:
204 		t.to = *a;
205 		break;
206 
207 	case C_SROREG:
208 	case C_LOREG:
209 	case C_ROREG:
210 	case C_FOREG:
211 	case C_SOREG:
212 	case C_FAUTO:
213 	case C_SAUTO:
214 	case C_LAUTO:
215 	case C_LACON:
216 		t.to.type = D_CONST;
217 		t.to.offset = instoffset;
218 		break;
219 	}
220 
221 	for(q = blitrl; q != P; q = q->link)	/* could hash on t.t0.offset */
222 		if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
223 			p->cond = q;
224 			return;
225 		}
226 
227 	q = prg();
228 	*q = t;
229 	q->pc = pool.size;
230 
231 	if(blitrl == P) {
232 		blitrl = q;
233 		pool.start = p->pc;
234 	} else
235 		elitrl->link = q;
236 	elitrl = q;
237 	pool.size += 4;
238 
239 	p->cond = q;
240 }
241 
242 void
243 xdefine(char *p, int t, long v)
244 {
245 	Sym *s;
246 
247 	s = lookup(p, 0);
248 	if(s->type == 0 || s->type == SXREF) {
249 		s->type = t;
250 		s->value = v;
251 	}
252 }
253 
254 long
255 regoff(Adr *a)
256 {
257 
258 	instoffset = 0;
259 	aclass(a);
260 	return instoffset;
261 }
262 
263 long
264 immrot(ulong v)
265 {
266 	int i;
267 
268 	for(i=0; i<16; i++) {
269 		if((v & ~0xff) == 0)
270 			return (i<<8) | v | (1<<25);
271 		v = (v<<2) | (v>>30);
272 	}
273 	return 0;
274 }
275 
276 long
277 immaddr(long v)
278 {
279 	if(v >= 0 && v <= 0xfff)
280 		return (v & 0xfff) |
281 			(1<<24) |	/* pre indexing */
282 			(1<<23);	/* pre indexing, up */
283 	if(v >= -0xfff && v < 0)
284 		return (-v & 0xfff) |
285 			(1<<24);	/* pre indexing */
286 	return 0;
287 }
288 
289 int
290 immfloat(long v)
291 {
292 	return (v & 0xC03) == 0;	/* offset will fit in floating-point load/store */
293 }
294 
295 int
296 immhalf(long v)
297 {
298 	if(v >= 0 && v <= 0xff)
299 		return v|
300 			(1<<24)|	/* pre indexing */
301 			(1<<23);	/* pre indexing, up */
302 	if(v >= -0xff && v < 0)
303 		return (-v & 0xff)|
304 			(1<<24);	/* pre indexing */
305 	return 0;
306 }
307 
308 int
309 aclass(Adr *a)
310 {
311 	Sym *s;
312 	int t;
313 
314 	switch(a->type) {
315 	case D_NONE:
316 		return C_NONE;
317 
318 	case D_REG:
319 		return C_REG;
320 
321 	case D_REGREG:
322 		return C_REGREG;
323 
324 	case D_SHIFT:
325 		return C_SHIFT;
326 
327 	case D_FREG:
328 		return C_FREG;
329 
330 	case D_FPCR:
331 		return C_FCR;
332 
333 	case D_OREG:
334 		switch(a->name) {
335 		case D_EXTERN:
336 		case D_STATIC:
337 			if(a->sym == 0 || a->sym->name == 0) {
338 				print("null sym external\n");
339 				print("%D\n", a);
340 				return C_GOK;
341 			}
342 			s = a->sym;
343 			t = s->type;
344 			if(t == 0 || t == SXREF) {
345 				diag("undefined external: %s in %s",
346 					s->name, TNAME);
347 				s->type = SDATA;
348 			}
349 			if(dlm) {
350 				switch(t) {
351 				default:
352 					instoffset = s->value + a->offset + INITDAT;
353 					break;
354 				case SUNDEF:
355 				case STEXT:
356 				case SCONST:
357 				case SLEAF:
358 				case SSTRING:
359 					instoffset = s->value + a->offset;
360 					break;
361 				}
362 				return C_ADDR;
363 			}
364 			instoffset = s->value + a->offset - BIG;
365 			t = immaddr(instoffset);
366 			if(t) {
367 				if(immhalf(instoffset))
368 					return immfloat(t) ? C_HFEXT : C_HEXT;
369 				if(immfloat(t))
370 					return C_FEXT;
371 				return C_SEXT;
372 			}
373 			return C_LEXT;
374 		case D_AUTO:
375 			instoffset = autosize + a->offset;
376 			t = immaddr(instoffset);
377 			if(t){
378 				if(immhalf(instoffset))
379 					return immfloat(t) ? C_HFAUTO : C_HAUTO;
380 				if(immfloat(t))
381 					return C_FAUTO;
382 				return C_SAUTO;
383 			}
384 			return C_LAUTO;
385 
386 		case D_PARAM:
387 			instoffset = autosize + a->offset + 4L;
388 			t = immaddr(instoffset);
389 			if(t){
390 				if(immhalf(instoffset))
391 					return immfloat(t) ? C_HFAUTO : C_HAUTO;
392 				if(immfloat(t))
393 					return C_FAUTO;
394 				return C_SAUTO;
395 			}
396 			return C_LAUTO;
397 		case D_NONE:
398 			instoffset = a->offset;
399 			t = immaddr(instoffset);
400 			if(t) {
401 				if(immhalf(instoffset))		 /* n.b. that it will also satisfy immrot */
402 					return immfloat(t) ? C_HFOREG : C_HOREG;
403 				if(immfloat(t))
404 					return C_FOREG; /* n.b. that it will also satisfy immrot */
405 				t = immrot(instoffset);
406 				if(t)
407 					return C_SROREG;
408 				if(immhalf(instoffset))
409 					return C_HOREG;
410 				return C_SOREG;
411 			}
412 			t = immrot(instoffset);
413 			if(t)
414 				return C_ROREG;
415 			return C_LOREG;
416 		}
417 		return C_GOK;
418 
419 	case D_PSR:
420 		return C_PSR;
421 
422 	case D_OCONST:
423 		switch(a->name) {
424 		case D_EXTERN:
425 		case D_STATIC:
426 			s = a->sym;
427 			t = s->type;
428 			if(t == 0 || t == SXREF) {
429 				diag("undefined external: %s in %s",
430 					s->name, TNAME);
431 				s->type = SDATA;
432 			}
433 			instoffset = s->value + a->offset + INITDAT;
434 			if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF)
435 				instoffset = s->value + a->offset;
436 			return C_LCON;
437 		}
438 		return C_GOK;
439 
440 	case D_FCONST:
441 		return C_FCON;
442 
443 	case D_CONST:
444 		switch(a->name) {
445 
446 		case D_NONE:
447 			instoffset = a->offset;
448 			if(a->reg != NREG)
449 				goto aconsize;
450 
451 			t = immrot(instoffset);
452 			if(t)
453 				return C_RCON;
454 			t = immrot(~instoffset);
455 			if(t)
456 				return C_NCON;
457 			return C_LCON;
458 
459 		case D_EXTERN:
460 		case D_STATIC:
461 			s = a->sym;
462 			if(s == S)
463 				break;
464 			t = s->type;
465 			switch(t) {
466 			case 0:
467 			case SXREF:
468 				diag("undefined external: %s in %s",
469 					s->name, TNAME);
470 				s->type = SDATA;
471 				break;
472 			case SUNDEF:
473 			case STEXT:
474 			case SSTRING:
475 			case SCONST:
476 			case SLEAF:
477 				instoffset = s->value + a->offset;
478 				return C_LCON;
479 			}
480 			if(!dlm) {
481 				instoffset = s->value + a->offset - BIG;
482 				t = immrot(instoffset);
483 				if(t && instoffset != 0)
484 					return C_RECON;
485 			}
486 			instoffset = s->value + a->offset + INITDAT;
487 			return C_LCON;
488 
489 		case D_AUTO:
490 			instoffset = autosize + a->offset;
491 			goto aconsize;
492 
493 		case D_PARAM:
494 			instoffset = autosize + a->offset + 4L;
495 		aconsize:
496 			t = immrot(instoffset);
497 			if(t)
498 				return C_RACON;
499 			return C_LACON;
500 		}
501 		return C_GOK;
502 
503 	case D_BRANCH:
504 		return C_SBRA;
505 	}
506 	return C_GOK;
507 }
508 
509 Optab*
510 oplook(Prog *p)
511 {
512 	int a1, a2, a3, r;
513 	char *c1, *c3;
514 	Optab *o, *e;
515 
516 	a1 = p->optab;
517 	if(a1)
518 		return optab+(a1-1);
519 	a1 = p->from.class;
520 	if(a1 == 0) {
521 		a1 = aclass(&p->from) + 1;
522 		p->from.class = a1;
523 	}
524 	a1--;
525 	a3 = p->to.class;
526 	if(a3 == 0) {
527 		a3 = aclass(&p->to) + 1;
528 		p->to.class = a3;
529 	}
530 	a3--;
531 	a2 = C_NONE;
532 	if(p->reg != NREG)
533 		a2 = C_REG;
534 	r = p->as;
535 	o = oprange[r].start;
536 	if(o == 0) {
537 		a1 = opcross[repop[r]][a1][a2][a3];
538 		if(a1) {
539 			p->optab = a1+1;
540 			return optab+a1;
541 		}
542 		o = oprange[r].stop; /* just generate an error */
543 	}
544 	if(0) {
545 		print("oplook %A %d %d %d\n",
546 			(int)p->as, a1, a2, a3);
547 		print("		%d %d\n", p->from.type, p->to.type);
548 	}
549 	e = oprange[r].stop;
550 	c1 = xcmp[a1];
551 	c3 = xcmp[a3];
552 	for(; o<e; o++)
553 		if(o->a2 == a2)
554 		if(c1[o->a1])
555 		if(c3[o->a3]) {
556 			p->optab = (o-optab)+1;
557 			return o;
558 		}
559 	diag("illegal combination %A %d %d %d",
560 		p->as, a1, a2, a3);
561 	prasm(p);
562 	if(o == 0)
563 		o = optab;
564 	return o;
565 }
566 
567 int
568 cmp(int a, int b)
569 {
570 
571 	if(a == b)
572 		return 1;
573 	switch(a) {
574 	case C_LCON:
575 		if(b == C_RCON || b == C_NCON)
576 			return 1;
577 		break;
578 	case C_LACON:
579 		if(b == C_RACON)
580 			return 1;
581 		break;
582 	case C_LECON:
583 		if(b == C_RECON)
584 			return 1;
585 		break;
586 
587 	case C_HFEXT:
588 		return b == C_HEXT || b == C_FEXT;
589 	case C_FEXT:
590 	case C_HEXT:
591 		return b == C_HFEXT;
592 	case C_SEXT:
593 		return cmp(C_HFEXT, b);
594 	case C_LEXT:
595 		return cmp(C_SEXT, b);
596 
597 	case C_HFAUTO:
598 		return b == C_HAUTO || b == C_FAUTO;
599 	case C_FAUTO:
600 	case C_HAUTO:
601 		return b == C_HFAUTO;
602 	case C_SAUTO:
603 		return cmp(C_HFAUTO, b);
604 	case C_LAUTO:
605 		return cmp(C_SAUTO, b);
606 
607 	case C_HFOREG:
608 		return b == C_HOREG || b == C_FOREG;
609 	case C_FOREG:
610 	case C_HOREG:
611 		return b == C_HFOREG;
612 	case C_SROREG:
613 		return cmp(C_SOREG, b) || cmp(C_ROREG, b);
614 	case C_SOREG:
615 	case C_ROREG:
616 		return b == C_SROREG || cmp(C_HFOREG, b);
617 	case C_LOREG:
618 		return cmp(C_SROREG, b);
619 
620 	case C_LBRA:
621 		if(b == C_SBRA)
622 			return 1;
623 		break;
624 	}
625 	return 0;
626 }
627 
628 int
629 ocmp(void *a1, void *a2)
630 {
631 	Optab *p1, *p2;
632 	int n;
633 
634 	p1 = (Optab*)a1;
635 	p2 = (Optab*)a2;
636 	n = p1->as - p2->as;
637 	if(n)
638 		return n;
639 	n = (p2->flag&V4) - (p1->flag&V4);	/* architecture version */
640 	if(n)
641 		return n;
642 	n = (p2->flag&VFP) - (p1->flag&VFP);	/* floating point arch */
643 	if(n)
644 		return n;
645 	n = p1->a1 - p2->a1;
646 	if(n)
647 		return n;
648 	n = p1->a2 - p2->a2;
649 	if(n)
650 		return n;
651 	n = p1->a3 - p2->a3;
652 	if(n)
653 		return n;
654 	return 0;
655 }
656 
657 void
658 buildop(void)
659 {
660 	int i, n, r;
661 
662 	armv4 = !debug['h'];
663 	vfp = debug['f'];
664 	for(i=0; i<C_GOK; i++)
665 		for(n=0; n<C_GOK; n++)
666 			xcmp[i][n] = cmp(n, i);
667 	for(n=0; optab[n].as != AXXX; n++) {
668 		if((optab[n].flag & VFP) && !vfp)
669 			optab[n].as = AXXX;
670 		if((optab[n].flag & V4) && !armv4) {
671 			optab[n].as = AXXX;
672 			break;
673 		}
674 	}
675 	qsort(optab, n, sizeof(optab[0]), ocmp);
676 	for(i=0; i<n; i++) {
677 		r = optab[i].as;
678 		oprange[r].start = optab+i;
679 		while(optab[i].as == r)
680 			i++;
681 		oprange[r].stop = optab+i;
682 		i--;
683 
684 		switch(r)
685 		{
686 		default:
687 			diag("unknown op in build: %A", r);
688 			errorexit();
689 		case AXXX:
690 			break;
691 		case AADD:
692 			oprange[AAND] = oprange[r];
693 			oprange[AEOR] = oprange[r];
694 			oprange[ASUB] = oprange[r];
695 			oprange[ARSB] = oprange[r];
696 			oprange[AADC] = oprange[r];
697 			oprange[ASBC] = oprange[r];
698 			oprange[ARSC] = oprange[r];
699 			oprange[AORR] = oprange[r];
700 			oprange[ABIC] = oprange[r];
701 			break;
702 		case ACMP:
703 			oprange[ATST] = oprange[r];
704 			oprange[ATEQ] = oprange[r];
705 			oprange[ACMN] = oprange[r];
706 			break;
707 		case AMVN:
708 			break;
709 		case ABEQ:
710 			oprange[ABNE] = oprange[r];
711 			oprange[ABCS] = oprange[r];
712 			oprange[ABHS] = oprange[r];
713 			oprange[ABCC] = oprange[r];
714 			oprange[ABLO] = oprange[r];
715 			oprange[ABMI] = oprange[r];
716 			oprange[ABPL] = oprange[r];
717 			oprange[ABVS] = oprange[r];
718 			oprange[ABVC] = oprange[r];
719 			oprange[ABHI] = oprange[r];
720 			oprange[ABLS] = oprange[r];
721 			oprange[ABGE] = oprange[r];
722 			oprange[ABLT] = oprange[r];
723 			oprange[ABGT] = oprange[r];
724 			oprange[ABLE] = oprange[r];
725 			break;
726 		case ASLL:
727 			oprange[ASRL] = oprange[r];
728 			oprange[ASRA] = oprange[r];
729 			break;
730 		case AMUL:
731 			oprange[AMULU] = oprange[r];
732 			break;
733 		case ADIV:
734 			oprange[AMOD] = oprange[r];
735 			oprange[AMODU] = oprange[r];
736 			oprange[ADIVU] = oprange[r];
737 			break;
738 		case AMOVW:
739 		case AMOVB:
740 		case AMOVBU:
741 		case AMOVH:
742 		case AMOVHU:
743 			break;
744 		case ASWPW:
745 			oprange[ASWPBU] = oprange[r];
746 			break;
747 		case AB:
748 		case ABL:
749 		case ABX:
750 		case ABXRET:
751 		case ASWI:
752 		case AWORD:
753 		case AMOVM:
754 		case ARFE:
755 		case ATEXT:
756 		case ACASE:
757 		case ABCASE:
758 			break;
759 		case AADDF:
760 			oprange[AADDD] = oprange[r];
761 			oprange[ASUBF] = oprange[r];
762 			oprange[ASUBD] = oprange[r];
763 			oprange[AMULF] = oprange[r];
764 			oprange[AMULD] = oprange[r];
765 			oprange[ADIVF] = oprange[r];
766 			oprange[ADIVD] = oprange[r];
767 			oprange[AMOVFD] = oprange[r];
768 			oprange[AMOVDF] = oprange[r];
769 			break;
770 
771 		case ACMPF:
772 			oprange[ACMPD] = oprange[r];
773 			break;
774 
775 		case AMOVF:
776 			oprange[AMOVD] = oprange[r];
777 			break;
778 
779 		case AMOVFW:
780 			oprange[AMOVWF] = oprange[r];
781 			oprange[AMOVWD] = oprange[r];
782 			oprange[AMOVDW] = oprange[r];
783 			break;
784 
785 		case AMULL:
786 			oprange[AMULA] = oprange[r];
787 			oprange[AMULAL] = oprange[r];
788 			oprange[AMULLU] = oprange[r];
789 			oprange[AMULALU] = oprange[r];
790 			break;
791 		}
792 	}
793 }
794 
795 /*
796 void
797 buildrep(int x, int as)
798 {
799 	Opcross *p;
800 	Optab *e, *s, *o;
801 	int a1, a2, a3, n;
802 
803 	if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
804 		diag("assumptions fail in buildrep");
805 		errorexit();
806 	}
807 	repop[as] = x;
808 	p = (opcross + x);
809 	s = oprange[as].start;
810 	e = oprange[as].stop;
811 	for(o=e-1; o>=s; o--) {
812 		n = o-optab;
813 		for(a2=0; a2<2; a2++) {
814 			if(a2) {
815 				if(o->a2 == C_NONE)
816 					continue;
817 			} else
818 				if(o->a2 != C_NONE)
819 					continue;
820 			for(a1=0; a1<32; a1++) {
821 				if(!xcmp[a1][o->a1])
822 					continue;
823 				for(a3=0; a3<32; a3++)
824 					if(xcmp[a3][o->a3])
825 						(*p)[a1][a2][a3] = n;
826 			}
827 		}
828 	}
829 	oprange[as].start = 0;
830 }
831 */
832 
833 enum{
834 	ABSD = 0,
835 	ABSU = 1,
836 	RELD = 2,
837 	RELU = 3,
838 };
839 
840 int modemap[4] = { 0, 1, -1, 2, };
841 
842 typedef struct Reloc Reloc;
843 
844 struct Reloc
845 {
846 	int n;
847 	int t;
848 	uchar *m;
849 	ulong *a;
850 };
851 
852 Reloc rels;
853 
854 static void
855 grow(Reloc *r)
856 {
857 	int t;
858 	uchar *m, *nm;
859 	ulong *a, *na;
860 
861 	t = r->t;
862 	r->t += 64;
863 	m = r->m;
864 	a = r->a;
865 	r->m = nm = malloc(r->t*sizeof(uchar));
866 	r->a = na = malloc(r->t*sizeof(ulong));
867 	memmove(nm, m, t*sizeof(uchar));
868 	memmove(na, a, t*sizeof(ulong));
869 	free(m);
870 	free(a);
871 }
872 
873 void
874 dynreloc(Sym *s, long v, int abs)
875 {
876 	int i, k, n;
877 	uchar *m;
878 	ulong *a;
879 	Reloc *r;
880 
881 	if(v&3)
882 		diag("bad relocation address");
883 	v >>= 2;
884 	if(s != S && s->type == SUNDEF)
885 		k = abs ? ABSU : RELU;
886 	else
887 		k = abs ? ABSD : RELD;
888 	/* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */
889 	k = modemap[k];
890 	r = &rels;
891 	n = r->n;
892 	if(n >= r->t)
893 		grow(r);
894 	m = r->m;
895 	a = r->a;
896 	for(i = n; i > 0; i--){
897 		if(v < a[i-1]){	/* happens occasionally for data */
898 			m[i] = m[i-1];
899 			a[i] = a[i-1];
900 		}
901 		else
902 			break;
903 	}
904 	m[i] = k;
905 	a[i] = v;
906 	r->n++;
907 }
908 
909 static int
910 sput(char *s)
911 {
912 	char *p;
913 
914 	p = s;
915 	while(*s)
916 		cput(*s++);
917 	cput(0);
918 	return  s-p+1;
919 }
920 
921 void
922 asmdyn()
923 {
924 	int i, n, t, c;
925 	Sym *s;
926 	ulong la, ra, *a;
927 	vlong off;
928 	uchar *m;
929 	Reloc *r;
930 
931 	cflush();
932 	off = seek(cout, 0, 1);
933 	lput(0);
934 	t = 0;
935 	lput(imports);
936 	t += 4;
937 	for(i = 0; i < NHASH; i++)
938 		for(s = hash[i]; s != S; s = s->link)
939 			if(s->type == SUNDEF){
940 				lput(s->sig);
941 				t += 4;
942 				t += sput(s->name);
943 			}
944 
945 	la = 0;
946 	r = &rels;
947 	n = r->n;
948 	m = r->m;
949 	a = r->a;
950 	lput(n);
951 	t += 4;
952 	for(i = 0; i < n; i++){
953 		ra = *a-la;
954 		if(*a < la)
955 			diag("bad relocation order");
956 		if(ra < 256)
957 			c = 0;
958 		else if(ra < 65536)
959 			c = 1;
960 		else
961 			c = 2;
962 		cput((c<<6)|*m++);
963 		t++;
964 		if(c == 0){
965 			cput(ra);
966 			t++;
967 		}
968 		else if(c == 1){
969 			wput(ra);
970 			t += 2;
971 		}
972 		else{
973 			lput(ra);
974 			t += 4;
975 		}
976 		la = *a++;
977 	}
978 
979 	cflush();
980 	seek(cout, off, 0);
981 	lput(t);
982 
983 	if(debug['v']){
984 		Bprint(&bso, "import table entries = %d\n", imports);
985 		Bprint(&bso, "export table entries = %d\n", exports);
986 	}
987 }
988