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