]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/5l/span.c
cwfs: fix listen filedescriptor leaks
[plan9front.git] / sys / src / cmd / 5l / span.c
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                         oprange[AROR] = oprange[r];
730                         break;
731                 case AMUL:
732                         oprange[AMULU] = oprange[r];
733                         break;
734                 case ADIV:
735                         oprange[AMOD] = oprange[r];
736                         oprange[AMODU] = oprange[r];
737                         oprange[ADIVU] = oprange[r];
738                         break;
739                 case AMOVW:
740                 case AMOVB:
741                 case AMOVBU:
742                 case AMOVH:
743                 case AMOVHU:
744                         break;
745                 case ASWPW:
746                         oprange[ASWPBU] = oprange[r];
747                         oprange[ALDREX] = oprange[r];
748                         oprange[ASTREX] = oprange[r];
749                         break;
750                 case ALDREX:
751                 case ASTREX:
752                 case AB:
753                 case ABL:
754                 case ABX:
755                 case ABXRET:
756                 case ASWI:
757                 case AWORD:
758                 case AMOVM:
759                 case ARFE:
760                 case ACLREX:
761                 case ATEXT:
762                 case ACASE:
763                 case ABCASE:
764                         break;
765                 case AADDF:
766                         oprange[AADDD] = oprange[r];
767                         oprange[ASUBF] = oprange[r];
768                         oprange[ASUBD] = oprange[r];
769                         oprange[AMULF] = oprange[r];
770                         oprange[AMULD] = oprange[r];
771                         oprange[ADIVF] = oprange[r];
772                         oprange[ADIVD] = oprange[r];
773                         oprange[AMOVFD] = oprange[r];
774                         oprange[AMOVDF] = oprange[r];
775                         break;
776                         
777                 case ACMPF:
778                         oprange[ACMPD] = oprange[r];
779                         break;
780
781                 case AMOVF:
782                         oprange[AMOVD] = oprange[r];
783                         break;
784
785                 case AMOVFW:
786                         oprange[AMOVWF] = oprange[r];
787                         oprange[AMOVWD] = oprange[r];
788                         oprange[AMOVDW] = oprange[r];
789                         break;
790
791                 case AMULL:
792                         oprange[AMULA] = oprange[r];
793                         oprange[AMULAL] = oprange[r];
794                         oprange[AMULLU] = oprange[r];
795                         oprange[AMULALU] = oprange[r];
796                         break;
797                 }
798         }
799 }
800
801 /*
802 void
803 buildrep(int x, int as)
804 {
805         Opcross *p;
806         Optab *e, *s, *o;
807         int a1, a2, a3, n;
808
809         if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) {
810                 diag("assumptions fail in buildrep");
811                 errorexit();
812         }
813         repop[as] = x;
814         p = (opcross + x);
815         s = oprange[as].start;
816         e = oprange[as].stop;
817         for(o=e-1; o>=s; o--) {
818                 n = o-optab;
819                 for(a2=0; a2<2; a2++) {
820                         if(a2) {
821                                 if(o->a2 == C_NONE)
822                                         continue;
823                         } else
824                                 if(o->a2 != C_NONE)
825                                         continue;
826                         for(a1=0; a1<32; a1++) {
827                                 if(!xcmp[a1][o->a1])
828                                         continue;
829                                 for(a3=0; a3<32; a3++)
830                                         if(xcmp[a3][o->a3])
831                                                 (*p)[a1][a2][a3] = n;
832                         }
833                 }
834         }
835         oprange[as].start = 0;
836 }
837 */
838
839 enum{
840         ABSD = 0,
841         ABSU = 1,
842         RELD = 2,
843         RELU = 3,
844 };
845
846 int modemap[4] = { 0, 1, -1, 2, };
847
848 typedef struct Reloc Reloc;
849
850 struct Reloc
851 {
852         int n;
853         int t;
854         uchar *m;
855         ulong *a;
856 };
857
858 Reloc rels;
859
860 static void
861 grow(Reloc *r)
862 {
863         int t;
864         uchar *m, *nm;
865         ulong *a, *na;
866
867         t = r->t;
868         r->t += 64;
869         m = r->m;
870         a = r->a;
871         r->m = nm = malloc(r->t*sizeof(uchar));
872         r->a = na = malloc(r->t*sizeof(ulong));
873         memmove(nm, m, t*sizeof(uchar));
874         memmove(na, a, t*sizeof(ulong));
875         free(m);
876         free(a);
877 }
878
879 void
880 dynreloc(Sym *s, long v, int abs)
881 {
882         int i, k, n;
883         uchar *m;
884         ulong *a;
885         Reloc *r;
886
887         if(v&3)
888                 diag("bad relocation address");
889         v >>= 2;
890         if(s != S && s->type == SUNDEF)
891                 k = abs ? ABSU : RELU;
892         else
893                 k = abs ? ABSD : RELD;
894         /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */
895         k = modemap[k];
896         r = &rels;
897         n = r->n;
898         if(n >= r->t)
899                 grow(r);
900         m = r->m;
901         a = r->a;
902         for(i = n; i > 0; i--){
903                 if(v < a[i-1]){ /* happens occasionally for data */
904                         m[i] = m[i-1];
905                         a[i] = a[i-1];
906                 }
907                 else
908                         break;
909         }
910         m[i] = k;
911         a[i] = v;
912         r->n++;
913 }
914
915 static int
916 sput(char *s)
917 {
918         char *p;
919
920         p = s;
921         while(*s)
922                 cput(*s++);
923         cput(0);
924         return  s-p+1;
925 }
926
927 void
928 asmdyn()
929 {
930         int i, n, t, c;
931         Sym *s;
932         ulong la, ra, *a;
933         vlong off;
934         uchar *m;
935         Reloc *r;
936
937         cflush();
938         off = seek(cout, 0, 1);
939         lput(0);
940         t = 0;
941         lput(imports);
942         t += 4;
943         for(i = 0; i < NHASH; i++)
944                 for(s = hash[i]; s != S; s = s->link)
945                         if(s->type == SUNDEF){
946                                 lput(s->sig);
947                                 t += 4;
948                                 t += sput(s->name);
949                         }
950         
951         la = 0;
952         r = &rels;
953         n = r->n;
954         m = r->m;
955         a = r->a;
956         lput(n);
957         t += 4;
958         for(i = 0; i < n; i++){
959                 ra = *a-la;
960                 if(*a < la)
961                         diag("bad relocation order");
962                 if(ra < 256)
963                         c = 0;
964                 else if(ra < 65536)
965                         c = 1;
966                 else
967                         c = 2;
968                 cput((c<<6)|*m++);
969                 t++;
970                 if(c == 0){
971                         cput(ra);
972                         t++;
973                 }
974                 else if(c == 1){
975                         wput(ra);
976                         t += 2;
977                 }
978                 else{
979                         lput(ra);
980                         t += 4;
981                 }
982                 la = *a++;
983         }
984
985         cflush();
986         seek(cout, off, 0);
987         lput(t);
988
989         if(debug['v']){
990                 Bprint(&bso, "import table entries = %d\n", imports);
991                 Bprint(&bso, "export table entries = %d\n", exports);
992         }
993 }