Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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(const void *a1, const 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
}