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