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