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