|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)sdi.c 1.1 86/02/03 Copyr 1985 Sun Micro";
3: #endif
4:
5: /*
6: * Copyright (c) 1985 by Sun Microsystems, Inc.
7: */
8:
9: #include "as.h"
10:
11: /*
12: * module to handle span-dependent instructions, e.g. jbr
13: * see CACM Vol 21 No 4 April 1978 for a description of the
14: * algorithm for resolving sdi's between the 1st and 2nd pass
15: */
16:
17: #define SQUID( x ) ( ((x)==C_TEXT)||(rflag && ((x) != C_BSS)) )
18: #define INFINITY 0x7fffffff /* larger than any address */
19:
20: struct sdi { /* information for span dependent instructions (sdi's) */
21: struct sdi *sdi_next; /* next sdi in list */
22: long int sdi_loc; /* location of the sdi */
23: union{
24: struct sym_bkt *sdi_Sym;/* symbol part of the sdi address */
25: int *sdi_Add;
26: }su;
27: #define sdi_sym su.sdi_Sym
28: #define sdi_address su.sdi_Add
29: long int sdi_off; /* offset part of the sdi address */
30: short sdi_leng; /* actual length of the sdi */
31: long int sdi_base; /* origin of the span of the sdi */
32: short sdi_flags; /* bits: is/was it a ddi? */
33: # if EBUG
34: unsigned sdi_lineno;
35: # endif EBUG
36: } *sdi_list; /* linked list of descriptors */
37:
38: struct sdi *ddi_list;
39:
40: /* sdi_flag bit */
41: #define SDI_TYPE 7 /* SDI4, SDI6, SDI8, SDIP */
42: #define SDI_DDI 010
43: #define SDI_EXTERN 020
44:
45: /* SDI4, SDI6, SDI8, SDIP, SDIX, SDIL */
46: static int glen[] = { 4, 6, 8, 4, 6, 4 };
47:
48:
49: /* grab a new sdi descriptor off of the free list; allocate space
50: * for a new free list if necessary
51: * stolen from the symbol-table manager
52: * We keep the sdi and ddi lists separate because:
53: * 1) we want to keep locality in the sdi list
54: * 2) we want to give back the ddi list
55: */
56:
57: #define SEGALLOC 100
58: static
59: struct seglist { int allocsize, nalloced; struct sdi *nextfree, *head; char *segname;}
60: sdilist = { SEGALLOC, 0, NULL, NULL, "sdi" },
61: ddilist = { SEGALLOC, 0, NULL, NULL, "ddi" };
62:
63: static long total_delta = 0;
64:
65: struct sdi *
66: sdi_alloc(s)
67: register struct seglist *s;
68: {
69: register struct sdi *sdp, *sdi_free;
70: register int i;
71:
72: if ((sdp = s->nextfree) != NULL)
73: s->nextfree = sdp->sdi_next;
74: else {
75: sdp = (struct sdi *)calloc(s->allocsize,sizeof(struct sdi));
76: if (sdp == NULL) sys_error("%s storage exceeded\n", s->segname);
77: sdp->sdi_next = s->head;
78: s->head = sdp++;
79: sdi_free = NULL;
80: for (i = s->allocsize-2; i--;) {
81: sdp->sdi_next = sdi_free;
82: sdi_free = sdp++;
83: }
84: s->nextfree = sdi_free;
85: s->allocsize *= 2;
86: }
87: s->nalloced++;
88: return(sdp);
89: }
90:
91: void
92: sdi_free(s)
93: register struct seglist *s;
94: {
95: register struct sdi *t, *u;
96: u = s->head;
97: while (u != NULL){
98: t = u->sdi_next;
99: free(u);
100: u = t;
101: }
102: s->head = NULL;
103: s->nextfree = NULL;
104: s->allocsize = SEGALLOC;
105: s->nalloced = 0;
106: }
107:
108: /*
109: * short-lived data structure
110: * used just for sorting the destination addresses, and keeping pointers
111: * to the corresponding sdi's.
112: */
113: struct sdi_destpair { struct sdi *user; int address; };
114:
115: int * destlist;
116: int destsize;
117:
118: sort_destpair( a, b )
119: struct sdi_destpair *a, *b;
120: {
121: return a->address - b->address;
122: }
123:
124: /*
125: * reformulate the base/span representation as follows:
126: * for each sdi, form a pair: a pointer to the sdi structure and
127: * the destination address (relative to the text base).
128: * Sort on destination address, then re-form as an integer array
129: * into which point the sdi structures. The array can be segmented
130: * to speed up processing it.
131: */
132: make_destlist()
133: {
134: struct sdi_destpair *darray;
135: register struct sdi_destpair *dp;
136: register struct sdi *s, *d;
137: register int *a;
138: register ndest = 0;
139: register lastaddr, newaddr;
140: int ddidelta;
141:
142: if ( sdilist.nalloced==0 ) return; /* empty list */
143: if ((darray = (struct sdi_destpair *)calloc( sdilist.nalloced , sizeof( struct sdi_destpair))) == NULL)
144: sys_error("cannot allocate intermediate structure");
145: for (s=sdi_list, dp = darray; s; s = s->sdi_next){
146: if (s->sdi_loc == -1 ) continue;
147: if (s->sdi_sym == NULL){
148: dp->address = s->sdi_off;
149: dp++ -> user = s;
150: ndest++;
151: }
152: }
153: if (destsize=ndest){
154: qsort( darray, ndest, sizeof (struct sdi_destpair), sort_destpair );
155: destlist = a = (int *)calloc( ndest, sizeof a[0] );
156: if (a==NULL)
157: sys_error("cannot allocate intermediate structure");
158: dp = darray;
159: *a = lastaddr = dp->address;
160: dp++ ->user->sdi_address = a++;
161: while (--ndest > 0){
162: if (lastaddr == (newaddr = dp->address)){
163: /* pick up the occasional duplicate destination address */
164: a--;
165: destsize--;
166: }else
167: *a = lastaddr = newaddr;
168: dp++ ->user->sdi_address = a++;
169: }
170: }
171: free( darray );
172: /*
173: * this is the part I hate.
174: * sweep through the sdi list and the dest list in parallel.
175: * for each sdi that was a ddi, subtract 2 from all destinations
176: * above the base address of the s(d)di. At the same time,
177: * sweep through the ddi list and subtract the shrinkage size
178: * from all destinations above the base address of the ddi.
179: * These are corrective factors we must apply because of initially
180: * assuming that all ddi's would be long. The base addresses of
181: * the sdi's have already been fixed by the routine resolve_ddi.
182: */
183: if (destsize){
184: a = destlist;
185: ndest = destsize;
186: s = sdi_list;
187: d = ddi_list;
188: ddidelta = 0;
189: while(ndest--){
190: newaddr = *a;
191: while( s != NULL && s->sdi_loc < newaddr ){
192: if (s->sdi_flags & SDI_DDI)
193: ddidelta += 2;
194: s = s->sdi_next;
195: }
196: while( d != NULL && d->sdi_loc < newaddr ){
197: ddidelta += d->sdi_flags;
198: d = d->sdi_next;
199: }
200: *a++ -= ddidelta;
201: }
202: }
203: }
204:
205: /*
206: * routine to create a sdi descriptor and insert it into the list
207: */
208: makesdi(op, base, flavor)
209: struct oper *op;/* the operand of the sdi */
210: long int base; /* origin of the the initial span of the sdi, to be */
211: /* corrected between pass1 and pass2 by subtracting */
212: /* from the value of the symbol of the operand */
213: /* i.e. 0 for resolving short absolute address modes */
214: /* Dot[+increment] for PC relative addresses */
215: {
216: register struct sdi *s, **p;
217: register int loc;
218: static long lastloc = INFINITY; /* you wanna see hackery? */
219: static struct sdi * lastsdi; /* we got hackery */
220:
221: if (!op ){ /* put the procedure boundary: .proc */
222: if (Oflag) return;
223: s = sdi_alloc(&sdilist);
224: s->sdi_loc = -1;
225: for ( p = lastsdi ? &(lastsdi->sdi_next) : &sdi_list;
226: *p;
227: p = &(*p)->sdi_next );
228: s->sdi_next = *p;
229: *p = s;
230: return;
231: }
232: if (op->flags_o&O_COMPLEX) /* not a simple address */
233: return(0);
234: s = sdi_alloc(&sdilist);
235: s->sdi_loc = dot; /* future bug here */
236: s->sdi_flags = flavor;
237: s->sdi_sym = op->sym_o;
238: s->sdi_off = op->value_o-op->sym_o->value_s; /* collect offset-from-label */
239: s->sdi_base = base;
240: s->sdi_leng = 2; /* shortest length */
241: # if EBUG
242: s->sdi_lineno = line_no;
243: # endif EBUG
244: loc = dot;
245: for ( p = (loc < lastloc) ? &sdi_list : &(lastsdi->sdi_next);
246: *p;
247: p = &(*p)->sdi_next)
248: if (loc < (*p)->sdi_loc)
249: break;
250: s->sdi_next = *p;
251: *p = s;
252: lastloc = loc;
253: lastsdi = s;
254: return(2); /* return the current length */
255: }
256:
257: /*
258: * resolve sdi's between pass1 and pass2
259: * basic algorithm is to repeatedly look for sdi that must use the
260: * long form, and update the span of other sdi's.
261: * When this terminates, all remaining sdi's can use the short form
262: */
263: sdi_resolve()
264: {
265: register struct sdi *s;
266: register struct sym_bkt *p;
267: register int t;
268: struct sdi *first, *end, *q;
269: long loc, big_delta = 0;
270: int *dest, *start;
271: int changed;
272: int csect_offsets[5];
273:
274: csect_offsets[C_UNDEF] = 0;
275: csect_offsets[C_TEXT ] = 0;
276: csect_offsets[C_DATA ] = tsize;
277: csect_offsets[C_DATA1] = tsize + dsize;
278: csect_offsets[C_DATA2] = tsize + dsize + d1size;
279:
280: for (s = sdi_list; s && s->sdi_loc == -1; s = s->sdi_next );
281: sdi_list = s; /* get rid of .proc at the beginning */
282:
283: for (s = sdi_list; s; s = s->sdi_next) {
284: if (s->sdi_loc == -1) continue;
285: p = s->sdi_sym;
286: if (SQUID(p->csect_s) && (p->attr_s & S_DEF)){
287: s->sdi_off += p->value_s + csect_offsets[p->csect_s];
288: s->sdi_sym = NULL;
289: } else
290: s->sdi_flags |= SDI_EXTERN;
291: }
292: ddi_resolve();
293: make_destlist();
294:
295: for (first = sdi_list; first; ) {
296: for (s=first; s && s->sdi_loc != -1; s=s->sdi_next )
297: end = s; /* find last sdi in this procedure */
298: for (s=end->sdi_next; s && s->sdi_loc == -1; s=s->sdi_next );
299: if (s)
300: loc = s->sdi_loc + total_delta;
301: else
302: loc = INFINITY;
303: if (destsize) {
304: for (dest = destlist;
305: *dest <= loc && dest < destlist + destsize;
306: dest++ );
307: start = --dest; /* last label before 'end' */
308: }
309: do {
310: changed = 0;
311: for (s = first; s && s->sdi_loc!=-1 ; s = s->sdi_next) {
312: if ((t = sdi_len(s) - s->sdi_leng) > 0) {
313: big_delta += t;
314: longsdi(s, t, first, start);
315: changed = 1;
316: } else if (t < 0) {
317: sys_error("Pathological sdi\n");
318: }
319: }
320: } while (changed);
321:
322: for (s=end->sdi_next; s && s->sdi_loc == -1; s=s->sdi_next );
323: first = s;
324: end->sdi_next = first; /* get rid of boundary .proc */
325: for (q = first; q; q = q->sdi_next )
326: q->sdi_base += big_delta;
327: if (destsize)
328: for ( dest = destlist + destsize - 1; dest > start; dest-- )
329: *dest += big_delta;
330: total_delta += big_delta;
331: big_delta = 0;
332: }
333: }
334:
335: /*
336: * update sdi list assuming the specified sdi must be long
337: */
338: longsdi(s, delta, first, start )
339: register struct sdi *s, *first;
340: register int delta;
341: int * start;
342: {
343: register struct sdi *t;
344: register long loc;
345: register int *dest;
346:
347: s->sdi_leng += delta; /* update the length of this sdi */
348: /* get the real location of the sdi */
349: loc = s->sdi_loc + sdi_inc( s->sdi_loc, first);
350: for (t = s->sdi_next; t && t->sdi_loc != -1; t = t->sdi_next)
351: t->sdi_base += delta;
352: if (destsize){
353: for ( dest = start; *dest > loc && dest >= destlist; dest-- )
354: *dest += delta;
355: }
356: }
357:
358: /*
359: * compute the length of the specified sdi by looking at the possible choices
360: */
361: sdi_len(s)
362: register struct sdi *s;
363: {
364: struct bchoice { int len; int lbound, ubound; };
365: static struct bchoice bsdi68[] = {
366: { 2, -128, 127 },
367: { 4, -32768, 32767 },
368: { 0, 0, 0 },
369: };
370: static struct bchoice bsdi4[] = {
371: { 2, -128, 127 },
372: { 0, 0, 0 },
373: };
374: static struct bchoice bsdip[] = {
375: { 2, -32768, 32767 },
376: { 0, 0, 0 },
377: };
378: /* SDI4, SDI6, SDI8, SDIP, */
379: static struct bchoice *blists[] = { bsdi4, bsdi68, bsdi68, bsdip, };
380: /* SDIX and SDIL are never span-dependent, so are not in this table! */
381:
382: register struct bchoice *b;
383: register span;
384:
385: span = *s->sdi_address - s->sdi_base;
386: if (!(s->sdi_flags&SDI_EXTERN)){
387: for (b = blists[ s->sdi_flags&SDI_TYPE ]; b->len; b++ )
388: if ( b->lbound <= span && span <= b->ubound)
389: return(b->len);
390: }
391: /* only the most general case will do */
392: return(glen[s->sdi_flags&SDI_TYPE]);
393: }
394:
395: /*
396: * return the total number of extra bytes due to long sdi's before
397: * the specified offset
398: */
399: sdi_inc(offset, first)
400: struct sdi *first;
401: register long offset;
402: {
403: register struct sdi *s;
404: register int total;
405:
406: if (first) {
407: s = first;
408: total = total_delta;
409: } else {
410: s = sdi_list;
411: total = 0;
412: }
413: for (; s; s = s->sdi_next) {
414: if (s->sdi_loc == -1 ) continue;
415: if (offset <= s->sdi_loc)
416: break;
417: total += s->sdi_leng - 2;
418: if (s->sdi_flags&SDI_DDI){
419: total -= 2;
420: }
421: }
422: for (s = ddi_list ; s; s = s->sdi_next) {
423: if (offset <= s->sdi_loc)
424: break;
425: total -= s->sdi_flags; /* if its still on the list, it shrank */
426: }
427: return(total);
428: }
429:
430: /*
431: * We are given an array of pointers to symbol-table entries for
432: * text labels, sorted by location. Update these by the changes in the
433: * sdi's. This used to be done by repeated calls to sdi_inc(), but this
434: * was obscenely expensive. Now that we have the lists sorted the same way,
435: * we should be able to compute this incrementally. Of course, there was
436: * the extra overhead of sorting the symbol list in the first place.
437: */
438: sdi_sym_update( symp, nsyms )
439: register struct sym_bkt **symp;
440: register int nsyms;
441: {
442: register struct sdi *sdi;
443: register struct sdi *ddi;
444: register curloc, curdelta;
445: register symloc, curddi;
446: curdelta = 0;
447:
448: if (nsyms==0) return;
449: if ((sdi = sdi_list) == NULL)
450: curloc = INFINITY;
451: else
452: curloc = sdi->sdi_loc;
453: if ((ddi = ddi_list) == NULL)
454: curddi = INFINITY;
455: else
456: curddi = ddi->sdi_loc;
457: while (nsyms--){
458: symloc = (*symp)->value_s;
459: while (symloc > curloc){
460: curdelta += sdi->sdi_leng - 2;
461: if (sdi->sdi_flags&SDI_DDI){
462: curdelta -= 2;
463: }
464: if ((sdi = sdi->sdi_next) == NULL){
465: curloc = INFINITY;
466: } else {
467: curloc = sdi->sdi_loc;
468: }
469: }
470: while (symloc > curddi){
471: curdelta -= ddi->sdi_flags ; /* if on ddi list, it shrank */
472: if ((ddi = ddi->sdi_next) == NULL){
473: curddi = INFINITY;
474: } else {
475: curddi = ddi->sdi_loc;
476: }
477: }
478: (*symp++)->value_s = symloc + curdelta;
479: }
480: }
481:
482: /*
483: * Data-dependent instructions
484: * are those whose length we may not be able to ascertain at first pass,
485: * but which we would like to address in the most effecient manner.
486: * Determining their length could, in full generality, be an iterative
487: * process, but I think we can make some useful simplifications that
488: * will do most of what we desire in one pass over our intermediate
489: * data structure. The gross structure will mimic the sdi code above.
490: * The instructions we are dealing with here have three forms:
491: * long absolute, word absolute, and PC-relative. Thus, there are
492: * two lengths of addressing extensions: two bytes and four bytes.
493: */
494:
495: /*
496: * Statistically, ALL data references are long. Thus it makes little
497: * sense to follow the sdi strategy of assuming the shortest form until
498: * proven otherwise. Since the ddi list is only looked at once, we
499: * don't have to maintain the data structures required by the sdi algorithm.
500: * In fact, once we've decided that a reference is long, we can take it
501: * entirely off the list, if we make this assumption.
502: */
503: makeddi(op, base, flavor, wrtflg )
504: struct oper *op;/* the operand of the sdi */
505: long int base; /* origin of the the initial span of the sdi, to be */
506: /* corrected between pass1 and pass2 by subtracting */
507: /* from the value of the symbol of the operand */
508: /* i.e. 0 for resolving short absolute address modes */
509: /* Dot[+increment] for PC relative addresses */
510: int flavor; /* form of ddi: usually SDIP, but for index SDIX, or SDIL for link*/
511: int wrtflg; /* 0 => not memory write destination: PC-relative ok */
512: /* 1 => memory write destination: PC-relative NOT ok */
513: {
514: register struct sdi *s, **p;
515: register int loc;
516: static long lastloc = INFINITY; /* you wanna see hackery? */
517: static struct sdi * lastddi; /* we got hackery */
518:
519: if (op->flags_o&O_COMPLEX) /* not a simple address */
520: return(0);
521: s = sdi_alloc( &ddilist );
522: s->sdi_loc = dot; /* soon to be a bug */
523: s->sdi_sym = op->sym_o;
524: s->sdi_off = op->value_o;
525: s->sdi_base = base;
526: s->sdi_leng = 4; /* assumed length */
527: s->sdi_flags = flavor;
528: # if EBUG
529: s->sdi_lineno = line_no;
530: # endif EBUG
531: if (wrtflg) s->sdi_flags |= SDI_DDI;
532: loc = dot;
533:
534: for ( p = (loc < lastloc) ? &ddi_list : &(lastddi->sdi_next);
535: *p;
536: p = &(*p)->sdi_next)
537: if (loc < (*p)->sdi_loc)
538: break;
539: s->sdi_next = *p;
540: lastloc = loc;
541: lastddi = s;
542: *p = s;
543: return(flavor==SDI6?6:4); /* return the current length */
544: }
545:
546:
547: ddi_resolve()
548: {
549: register struct sdi *s, **spp, *q;
550: register struct sym_bkt *p;
551: register int t;
552:
553: spp = &ddi_list;
554: while (s = *spp){
555: p = s->sdi_sym;
556: switch (s->sdi_flags){
557: case SDIP:
558: if (SQUID(p->csect_s ) && (p->attr_s & S_DEF) ){
559: /* this looks like a job for PC@() */
560: /* fill out the sdi structure, and
561: insert it in the sdi list */
562: register struct sdi **pp;
563: struct sdi *newsdi;
564:
565: s->sdi_off += p->value_s;
566: s->sdi_sym = NULL;
567: /* take ourselves off of ddi list */
568: *spp = s->sdi_next;
569: /*
570: * here's the tricky part:
571: * all the addresses in our lists assume this
572: * address has length four. We will now change
573: * them so it appears to have length two.
574: */
575: shortddi( s, 2 );
576: s->sdi_flags = SDI_DDI|SDIP;
577: /* now put ourselves in the sdi list */
578: for (pp = &sdi_list; *pp; pp = &(*pp)->sdi_next)
579: if (s->sdi_loc < (*pp)->sdi_loc)
580: break;
581: newsdi = sdi_alloc(&sdilist);
582: *newsdi = *s;
583: newsdi->sdi_next = *pp;
584: *pp = newsdi;
585: /* fix addresses on sdi list, too */
586: newsdi->sdi_leng -= 2;
587: for ( q= newsdi->sdi_next; q; q = q->sdi_next )
588: q->sdi_base -= 2;
589: /* sdi routines will fix it up later */
590: continue;
591: }
592: /* else fall through */
593: case SDIP|SDI_DDI:
594: case SDI4:
595: case SDI4|SDI_DDI:
596: if ((p->attr_s & S_DEF) && p->csect_s == C_UNDEF) {
597: /* try on a short absolute */
598: t = p->value_s + s->sdi_off;
599: if (t >= -32768 && t <= 32767 ){
600: shortddi( s, 2 );
601: spp = &s->sdi_next;
602: continue;
603: }
604:
605: }
606: /* else it does not shrink -- take off list */
607: break;
608: case SDI6:
609: case SDI6|SDI_DDI:
610: /*
611: * Index mode.
612: */
613: /* Write bit only confuses us: delete it */
614: s->sdi_flags = SDI6;
615: if ((p->attr_s & S_DEF) && p->csect_s == C_UNDEF){
616: /* try very short, then just plain short */
617: t = p->value_s + s->sdi_off;
618: if ( t >= -128 && t <= 127 ){
619: /* shrinks much */
620: shortddi( s, 4 );
621: spp = &s->sdi_next;
622: continue;
623: } else if (t >= -32768 && t <= 32767 ){
624: /* shrinks some */
625: shortddi( s, 2 );
626: spp = &s->sdi_next;
627: continue;
628: }
629: }
630: /* else it does not shrink -- take off list */
631: break;
632: case SDIX:
633: case SDIX|SDI_DDI:
634: /*
635: * should be displacement mode, but will be
636: * index mode with supressed indexing if the
637: * displacement is too big.
638: */
639: /* FALL THROUGH */
640: case SDIL:
641: /*
642: * link instruction: looks like SDIP, but is not
643: * PC-relative.
644: */
645: /* Write bit only confuses us: delete it */
646: s->sdi_flags &= SDI_TYPE;
647: if ((p->attr_s & S_DEF) && p->csect_s == C_UNDEF){
648: /* try short */
649: t = p->value_s + s->sdi_off;
650: if (t >= -32768 && t <= 32767 ){
651: /* shrinks */
652: shortddi( s, glen[s->sdi_flags&SDI_TYPE] - 2 );
653: spp = &s->sdi_next;
654: continue;
655: }
656: }
657: /* else it does not shrink -- take off list */
658: break;
659: }
660: /* take ddi off the list */
661: *spp = s->sdi_next;
662: }
663: if (ddi_list == NULL){
664: sdi_free(&ddilist); /* all gone */
665: } else {
666: register int cursdi;
667: /*
668: * Sweep through ddi list and sdi list in parallel,
669: * fixing up sdi base-addresses.
670: */
671: s = ddi_list;
672: t = 0;
673: q = sdi_list;
674: while (q != NULL){
675: cursdi = q->sdi_base;
676: while ( s != NULL && s->sdi_base < cursdi ){
677: t += s->sdi_flags;
678: s = s->sdi_next;
679: }
680: q->sdi_base -= t;
681: q = q->sdi_next;
682: }
683: }
684: }
685:
686: shortddi( s, d )
687: register struct sdi *s;
688: register d;
689: {
690: /*
691: * A ddi shrank! Adjust all lists accordingly.
692: */
693: register struct sdi *t;
694: register loc = s->sdi_loc+sdi_inc( s->sdi_loc, NULL);
695:
696: s->sdi_flags = d; /* how much I shrank */
697: for (t = ddi_list; t; t = t->sdi_next)
698: if (t != s && t->sdi_base > loc)
699: t->sdi_base -= d;
700: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.