|
|
1.1 root 1: /* Copyright (c) 1980 Regents of the University of California */
2: static char sccsid[] = "@(#)asjxxx.c 4.5 8/20/80";
3: #include <stdio.h>
4: #include "as.h"
5: #include "assyms.h"
6:
7: #define JBR 0x11
8: #define BRW 0x31
9: #define JMP 0x17
10:
11: /*
12: * The number of bytes to add if the jxxx must be "exploded"
13: * into the long form
14: */
15: #define JBRDELTA 1 /* brb <byte> ==> brw <byte> <byte> */
16: #define JXXXDELTA 3 /* brb <byte> ==> brb <byte> brw <byte> <byte> */
17: #define JBRJDELTA d124 /* brb <byte> ==> jmp L^(pc) <byte>*d124 */
18: #define JXXXJDELTA d124+2 /* brb <byte> ==> brb <byte> jmp L^(pc) <byte>*d124 */
19:
20: int jbrfsize = JBRDELTA;
21: int jxxxfsize = JXXXDELTA;
22:
23: /*
24: * These variables are filled by asscan.c with the
25: * last name encountered (a pointer buried in the intermediate file),
26: * and the last jxxx symbol table entry encountered.
27: */
28: struct symtab *lastnam;
29: struct symtab *lastjxxx;
30:
31: initijxxx()
32: {
33: jbrfsize = jxxxJUMP ? JBRJDELTA : JBRDELTA;
34: jxxxfsize = jxxxJUMP ? JXXXJDELTA : JXXXDELTA;
35: /*
36: * Note: ifjxxxJUMP is set, then we do NOT do any tunnelling;
37: * this was too complicated to figure out, and in the first
38: * version of the assembler, tunnelling proved to be the hardest
39: * to get to work!
40: */
41: }
42: /*
43: * Handle jxxx instructions
44: */
45: ijxout(op,ap,nact)
46: struct arg *ap;
47: {
48: if (passno == 1){
49: /*
50: * READ THIS BEFORE LOOKING AT jxxxfix()
51: *
52: * Record the jxxx in a special symbol table entry
53: */
54: register struct symtab *jumpfrom;
55:
56: /*
57: * We assume the MINIMAL length
58: */
59: putins(op,ap,nact);
60: jumpfrom = lastjxxx;
61: jumpfrom->s_tag = JXACTIVE;
62: jumpfrom->s_jxbump = 0;
63: if (op == JBR)
64: jumpfrom->s_jxfear = jbrfsize;
65: else
66: jumpfrom->s_jxfear = jxxxfsize;
67: if (lastnam == 0)
68: yyerror("jxxx destination not a label");
69: jumpfrom->s_dest = lastnam;
70: jumpfrom->s_type = dotp->e_xtype; /*only TEXT or DATA*/
71: jumpfrom->s_index = dotp-usedot;
72: /*
73: * value ALWAYS (ALWAYS!!!) indexes the next instruction
74: * after the jump, even in the jump must be exploded
75: * (bumped)
76: */
77: jumpfrom->s_value = dotp->e_xvalue;
78: njxxx++;
79: } else {/* pass2, resolve */
80: /*
81: * READ THIS AFTER LOOKING AT jxxxfix()
82: */
83: register long oxvalue;
84: register struct exp *xp;
85: register struct symtab *tunnel;
86: register struct arg *aplast;
87:
88: aplast = ap + nact - 1;
89: xp = aplast->a_xp;
90: if (lastjxxx->s_tag == JXTUNNEL){
91: lastjxxx->s_tag = JXINACTIVE;
92: tunnel = lastjxxx->s_dest;
93: xp->e_xvalue = tunnel->s_value /*index of instruction following*/
94: - 3 /* size of brw + word*/
95: + ( ( (tunnel->s_jxfear == jbrfsize) &&
96: (tunnel->s_jxbump == 0))?1:0);
97: /*non bumped branch byteis only 2 back*/
98: }
99: if (lastjxxx->s_jxbump == 0){ /*wasn't bumped, so is short form*/
100: putins(op, ap, nact);
101: } else {
102: if (op != JBR){ /*branch reverse conditional byte over
103: branch unconditional word*/
104: oxvalue = xp->e_xvalue;
105: xp->e_xvalue = lastjxxx->s_value;
106: putins(op^1, ap, nact);
107: xp->e_xvalue = oxvalue;
108: }
109: putins(jxxxJUMP ? JMP : BRW, aplast, 1);
110: }
111: }
112: } /*end of ijxout*/
113:
114: jalign(xp, sp)
115: register struct exp *xp;
116: register struct symtab *sp;
117: {
118: register int mask;
119: /*
120: * Problem with .align
121: *
122: * When the loader constructs an executable file from
123: * a number of objects, it effectively concatnates
124: * together all of the text segments from all objects,
125: * and then all of the data segments.
126: *
127: * If we do an align by a large value, we can align
128: * within the a.out this assembly produces, but
129: * after the loader concatnates, the alignment can't
130: * be guaranteed if the objects preceding this one
131: * in the load are also aligned to the same size.
132: *
133: * Currently, the loader guarantees full word alignment.
134: * So, ridiculous aligns are caught here and converted
135: * to a .align 2, if possible.
136: *
137: * the code above and comment below was written by someone
138: * who needs a little more experience in the real world.
139: * if you wish to do big .aligns, please do so; beware
140: * what the loader will do, but so what?
141: */
142: if ( (xp->e_xtype != XABS)
143: || (xp->e_xvalue < 0)
144: || (xp->e_xvalue > 16)
145: ) {
146: yyerror("Illegal `align' argument");
147: return;
148: }
149: #ifdef CRINOID
150: if (xp->e_xvalue > 2){
151: if (passno == 1){
152: yywarning(".align %d in any segment is NOT preserved by the loader",
153: xp->e_xvalue);
154: yywarning(".align %d converted to .align 2",
155: xp->e_xvalue);
156: }
157: xp->e_xvalue = 2;
158: }
159: #endif
160: flushfield(NBPW/4);
161: if (passno == 1) {
162: sp->s_tag = JXALIGN;
163: sp->s_jxfear = (1 << xp->e_xvalue) - 1;
164: sp->s_type = dotp->e_xtype;
165: sp->s_index = dotp-usedot;
166: /*
167: * We guess that the align will take up at least one
168: * byte in the code output. We will correct for this
169: * initial high guess when we explode (bump) aligns
170: * when we fix the jxxxes. We must do this guess
171: * so that the symbol table is sorted correctly
172: * and labels declared to fall before the align
173: * really get their, instead of guessing zero size
174: * and have the label (incorrectly) fall after the jxxx.
175: * This is a quirk of our requirement that indices into
176: * the code stream point to the next byte following
177: * the logical entry in the symbol table
178: */
179: dotp->e_xvalue += 1;
180: sp->s_value = dotp->e_xvalue;
181: njxxx++;
182: } else {
183: mask = (1 << xp->e_xvalue) - 1;
184: while (dotp->e_xvalue & mask){
185: #ifdef UNIX
186: outb(0);
187: #endif UNIX
188: #ifdef VMS
189: *vms_obj_ptr++ = -1;
190: *vms_obj_ptr++ = 0;
191: dotp->e_xvalue += 1;
192: #endif VMS
193: }
194: }
195: }
196:
197: /*
198: * Pass 1.5, resolve jxxx instructions and .align in .text
199: */
200: jxxxfix()
201: {
202: register struct symtab *jumpfrom;
203: struct symtab **cojumpfrom, *ubjumpfrom;
204: register struct symtab *dest;
205: register struct symtab *intdest; /*intermediate dest*/
206: register struct symtab **cointdest, *ubintdest;
207:
208: register struct symtab *tunnel;
209: int displ,nchange;
210: int badjxalign; /*if jump across an align*/
211: int stillactives; /*if still active jxxxes*/
212: int segno; /*current segment number*/
213: int topono; /*which iteration in the topo sort*/
214: register unsigned char tag;
215: /*
216: * consider each segment in turn...
217: */
218: for (segno = 0; segno < NLOC + NLOC; segno++){
219: badjxalign = 0; /*done on a per segment basis*/
220: /*
221: * Do a lazy topological sort.
222: */
223: for (topono = 1, nchange = 1; nchange != 0; topono++){
224: #ifdef DEBUG
225: if (debug)
226: printf("\nSegment %d, topo iteration %d\n",
227: segno, topono);
228: #endif
229: nchange = 0;
230: stillactives = 0;
231: /*
232: * We keep track of one possible tunnel location.
233: * A tunnel will eventually be an unconditional
234: * branch to the same place that another jxxx
235: * will want to branch to. We will turn a
236: * branch conditional/unconditional (word) that would
237: * have to get bumped because its destination is too
238: * far away, into a branch conditional/unconditional
239: * byte to the tunnel branch conditional/unconditional.
240: * Of course, the tunnel must branch to the same place
241: * as we want to go.
242: */
243: tunnel = 0; /*initially, no tunnel*/
244: SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){
245: tag = jumpfrom->s_tag;
246: if (tag <= IGNOREBOUND)
247: continue; /*just an ordinary symbol*/
248: if (tag == JXALIGN){
249: tunnel = 0; /*avoid tunneling across a flex alocation*/
250: continue; /*we take care of these later*/
251: }
252: if ( jumpfrom->s_jxfear == jbrfsize /*unconditional*/
253: || ( tag == JXINACTIVE /*inactive bumped*/
254: && (jumpfrom->s_jxbump != 0)
255: )
256: ) tunnel = jumpfrom;
257: if (tag != JXACTIVE)
258: continue;
259: dest = jumpfrom->s_dest;
260: if (jumpfrom->s_index != dest->s_index){
261: yyerror("Intersegment jxxx");
262: continue;
263: }
264: displ = dest->s_value - jumpfrom->s_value;
265: if (displ < MINBYTE || displ > MAXBYTE) {
266: /*
267: * This is an immediate lose!
268: *
269: * We first attempt to tunnel
270: * by finding an intervening jump that
271: * has the same destination.
272: * The tunnel is always the first preceeding
273: * jxxx instruction, so the displacement
274: * to the tunnel is less than zero, and
275: * its relative position will be unaffected
276: * by future jxxx expansions.
277: *
278: * No tunnels if doing jumps...
279: */
280: if ( (!jxxxJUMP)
281: && (jumpfrom->s_jxfear > jbrfsize)
282: && (tunnel)
283: && (tunnel->s_dest == jumpfrom->s_dest)
284: && (tunnel->s_index == jumpfrom->s_index)
285: && (tunnel->s_value - jumpfrom->s_value >=
286: MINBYTE + jxxxfsize)
287: ) {
288: /*
289: * tunnelling is OK
290: */
291: jumpfrom->s_dest = tunnel;
292: /*
293: * no bumping needed, this
294: * is now effectively inactive
295: * but must be remembered
296: */
297: jumpfrom->s_tag = JXTUNNEL;
298: #ifdef DEBUG
299: if(debug)
300: printf("Tunnel from %s from line %d\n",
301: jumpfrom->s_name, lineno);
302: #endif
303: continue;
304: } else { /*tunneling not possible*/
305: /*
306: * since this will be turned
307: * into a bumped jump, we can
308: * use the unconditional jump
309: * as a tunnel
310: */
311: tunnel = jumpfrom;
312: jumpfrom->s_tag = JXNOTYET;
313: ++nchange;
314: continue;
315: }
316: } /*end of immediate lose*/
317: /*
318: * Do a forward search for an intervening jxxx
319: */
320: if (displ >= 0) {
321: SEGITERATE(segno, cojumpfrom + 1,0,cointdest,
322: intdest, ubintdest, ++){
323: if (intdest->s_value > dest->s_value)
324: break; /* beyond destination */
325: if (intdest->s_tag <= JXQUESTIONABLE)
326: continue; /*frozen solid*/
327: if (intdest->s_tag == JXALIGN){
328: jumpfrom->s_jxoveralign = 1;
329: badjxalign++;
330: }
331: /*
332: * we assume the worst case
333: * for unfrozen jxxxxes
334: */
335: displ += intdest->s_jxfear;
336: }
337: if (displ <= MAXBYTE){
338: /*
339: * the worst possible conditions
340: * can't hurt us, so forget about
341: * this jump
342: */
343: jumpfrom->s_tag = JXINACTIVE;
344: } else {
345: stillactives++;
346: }
347: } else {
348: /*
349: * backward search for intervening jxxx
350: */
351: SEGITERATE(segno, cojumpfrom - 1,1,cointdest,
352: intdest, ubintdest, --){
353: if (intdest->s_value <= dest->s_value)
354: break; /* beyond destination */
355: if (intdest->s_tag <= JXQUESTIONABLE)
356: continue; /*frozen solid*/
357: if (intdest->s_tag == JXALIGN){
358: jumpfrom->s_jxoveralign = 1;
359: badjxalign++;
360: }
361: displ -= intdest->s_jxfear;
362: }
363: if (displ >= MINBYTE) {
364: jumpfrom->s_tag = JXINACTIVE;
365: } else {
366: stillactives++;
367: }
368: } /*end of backwards search*/
369: } /*end of iterating through all symbols in this seg*/
370:
371: if (nchange == 0) {
372: /*
373: * Now, if there are still active jxxx entries,
374: * we are partially deadlocked. We can leave
375: * these jxxx entries in their assumed short jump
376: * form, as all initial displacement calcualtions
377: * are hanging on unresolved jxxx instructions
378: * that might explode into a long form, causing
379: * other jxxxes jumping across the first set of
380: * jxxxes to explode, etc.
381: * However, if a jxxx jumps across a .align,
382: * we assume the worst for the deadlock cycle,
383: * and resolve all of them towards the long
384: * jump.
385: * Currently, the C compiler does not produce
386: * jumps across aligns, as aligns are only used
387: * in data segments, or in text segments to align
388: * functions.
389: */
390: if (stillactives){
391: SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
392: ubjumpfrom, ++){
393: if (jumpfrom->s_tag == JXACTIVE){
394: jumpfrom->s_tag =
395: badjxalign?JXNOTYET:JXINACTIVE;
396: }
397: }
398: if (badjxalign){
399: jxxxbump(segno, (struct symtab **)0);
400: }
401: }
402: /*
403: * Handle all of the .align s
404: */
405: SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
406: ubjumpfrom, ++){
407: if (jumpfrom->s_tag == JXALIGN){
408: /*
409: * Predict the true displacement
410: * needed, irregardless of the
411: * fact that we guessed 1
412: */
413: displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear;
414: if (displ == 0){ /*no virtual displacement*/
415: jumpfrom->s_jxfear = -1;
416: } else {
417: jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ;
418: /*
419: * assert jumpfrom->s_jxfear > 0
420: */
421: if (jumpfrom->s_jxfear == 1){
422: /*our prediction was correct*/
423: continue;
424: }
425: /*
426: * assert jumpfrom->s_jxfear > 1
427: */
428: jumpfrom->s_jxfear -= 1; /*correct guess*/
429: }
430: /*
431: * assert jumpfrom->s_jxfear = -1, +1...2**n-1
432: */
433: jumpfrom->s_tag = JXNOTYET; /*signal*/
434: jxxxbump(segno, cojumpfrom);
435: jumpfrom->s_tag = JXINACTIVE;
436: /*
437: * Assert jxfrom->jxvalue indexes the first
438: * code byte after the added bytes, and
439: * has n low order zeroes.
440: */
441: }
442: } /*end of walking through each segment*/
443: } /*end of no changes */
444: else { /*changes, and still have to try another pass*/
445: jxxxbump(segno, (struct symtab **)0);
446: }
447: } /*end of doing the topologic sort*/
448: } /*end of iterating through all segments*/
449: } /*end of jxxxfix*/
450:
451: /*
452: * Go through the symbols in a given segment number,
453: * and see which entries are jxxx entries that have
454: * been logically "exploded" (expanded), but for which
455: * the value of textually following symbols has not been
456: * increased
457: */
458:
459: jxxxbump(segno, starthint)
460: int segno;
461: struct symtab **starthint;
462: {
463: register struct symtab **cosp, *sp;
464: register struct symtab *ub;
465: register int cum_bump;
466: register unsigned char tag;
467:
468: cum_bump = 0;
469: SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){
470: tag = sp->s_tag;
471: if (tag == JXNOTYET){
472: #ifdef DEBUG
473: if (debug){
474: if (sp->s_dest != 0)
475: printf("Explode jump to %s on line %d\n",
476: sp->s_dest->s_name, lineno);
477: else
478: printf("Explode an align!\n");
479: }
480: #endif
481: sp->s_tag = JXINACTIVE;
482: sp->s_jxbump = 1;
483: cum_bump += sp->s_jxfear;
484: }
485: /*
486: * Only bump labels and jxxxes. Ignored entries can
487: * be incremented, as they are thrown away later on.
488: * Stabds are given their final value in the second
489: * pass.
490: */
491: if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/
492: sp->s_value += cum_bump;
493: }
494: usedot[segno].e_xvalue += cum_bump;
495: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.