1595Sbill /* Copyright (c) 1980 Regents of the University of California */ 2*630Shenry static char sccsid[] = "@(#)asjxxx.c 4.2 08/15/80"; 3595Sbill #include <stdio.h> 4595Sbill #include "as.h" 5595Sbill #include "assyms.h" 6595Sbill 7595Sbill #define JBR 0x11 8595Sbill #define BRW 0x31 9595Sbill 10595Sbill /* 11595Sbill * The number of bytes to add if the jxxx must be "exploded" 12595Sbill * into the long form 13595Sbill */ 14595Sbill #define JBRFSIZE 1 /*goes to brw*/ 15595Sbill #define JXXXFSIZE 3 /*goes to brb, brw <byte> <byte> */ 16595Sbill 17595Sbill /* 18595Sbill * These variables are filled by asscan.c with the 19595Sbill * last name encountered (a pointer buried in the intermediate file), 20595Sbill * and the last jxxx symbol table entry encountered. 21595Sbill */ 22595Sbill struct symtab *lastnam; 23595Sbill struct symtab *lastjxxx; 24595Sbill 25595Sbill /* 26595Sbill * Handle jxxx instructions 27595Sbill */ 28595Sbill ijxout(op,ap,nact) 29595Sbill struct arg *ap; 30595Sbill { 31595Sbill if (passno == 1){ 32595Sbill /* 33595Sbill * READ THIS BEFORE LOOKING AT jxxxfix() 34595Sbill * 35595Sbill * Record the jxxx in a special symbol table entry 36595Sbill */ 37595Sbill register struct symtab *jumpfrom; 38595Sbill 39595Sbill /* 40595Sbill * We assume the MINIMAL length 41595Sbill */ 42595Sbill putins(op,ap,nact); 43595Sbill jumpfrom = lastjxxx; 44*630Shenry jumpfrom->s_tag = JXACTIVE; 45*630Shenry jumpfrom->s_jxbump = 0; 46595Sbill if (op == JBR) 47*630Shenry jumpfrom->s_jxfear = JBRFSIZE; 48595Sbill else 49*630Shenry jumpfrom->s_jxfear = JXXXFSIZE; 50595Sbill if (lastnam == 0) 51595Sbill yyerror("jxxx destination not a label"); 52*630Shenry jumpfrom->s_dest = lastnam; 53*630Shenry jumpfrom->s_type = dotp->e_xtype; /*only TEXT or DATA*/ 54*630Shenry jumpfrom->s_index = dotp-usedot; 55595Sbill /* 56595Sbill * value ALWAYS (ALWAYS!!!) indexes the next instruction 57595Sbill * after the jump, even in the jump must be exploded 58595Sbill * (bumped) 59595Sbill */ 60*630Shenry jumpfrom->s_value = dotp->e_xvalue; 61595Sbill njxxx++; 62595Sbill } else {/* pass2, resolve */ 63595Sbill /* 64595Sbill * READ THIS AFTER LOOKING AT jxxxfix() 65595Sbill */ 66595Sbill register long oxvalue; 67595Sbill register struct exp *xp; 68595Sbill register struct symtab *tunnel; 69595Sbill register struct arg *aplast; 70595Sbill 71595Sbill aplast = ap + nact - 1; 72*630Shenry xp = aplast->a_xp; 73*630Shenry if (lastjxxx->s_tag == JXTUNNEL){ 74*630Shenry lastjxxx->s_tag = JXINACTIVE; 75*630Shenry tunnel = lastjxxx->s_dest; 76*630Shenry xp->e_xvalue = tunnel->s_value /*index of instruction following*/ 77595Sbill - 3 /* size of brw + word*/ 78*630Shenry + ( ( (tunnel->s_jxfear == JBRFSIZE) && 79*630Shenry (tunnel->s_jxbump == 0))?1:0); 80595Sbill /*non bumped branch byteis only 2 back*/ 81595Sbill } 82*630Shenry if (lastjxxx->s_jxbump == 0){ /*wasn't bumped, so is short form*/ 83595Sbill putins(op, ap, nact); 84595Sbill } else { 85595Sbill if (op != JBR){ /*branch reverse conditional byte over 86595Sbill branch unconditional word*/ 87*630Shenry oxvalue = xp->e_xvalue; 88*630Shenry xp->e_xvalue = lastjxxx->s_value; 89595Sbill putins(op^1, ap, nact); 90*630Shenry xp->e_xvalue = oxvalue; 91595Sbill } 92595Sbill putins(BRW, aplast, 1); 93595Sbill } 94595Sbill } 95595Sbill } /*end of ijxout*/ 96595Sbill 97595Sbill jalign(xp, sp) 98595Sbill register struct exp *xp; 99595Sbill register struct symtab *sp; 100595Sbill { 101595Sbill register int mask; 102*630Shenry if (xp->e_xtype != XABS || xp->e_xvalue < 0 || xp->e_xvalue > 16) { 103595Sbill yyerror("Illegal `align' argument"); 104595Sbill return; 105595Sbill } 106595Sbill flushfield(NBPW/4); 107595Sbill if (passno == 1) { 108*630Shenry sp->s_tag = JXALIGN; 109*630Shenry sp->s_jxfear = (1 << xp->e_xvalue) - 1; 110*630Shenry sp->s_type = dotp->e_xtype; 111*630Shenry sp->s_index = dotp-usedot; 112595Sbill /* 113595Sbill * We guess that the align will take up at least one 114595Sbill * byte in the code output. We will correct for this 115595Sbill * initial high guess when we explode (bump) aligns 116595Sbill * when we fix the jxxxes. We must do this guess 117595Sbill * so that the symbol table is sorted correctly 118595Sbill * and labels declared to fall before the align 119595Sbill * really get their, instead of guessing zero size 120595Sbill * and have the label (incorrectly) fall after the jxxx. 121595Sbill * This is a quirk of our requirement that indices into 122595Sbill * the code stream point to the next byte following 123595Sbill * the logical entry in the symbol table 124595Sbill */ 125*630Shenry dotp->e_xvalue += 1; 126*630Shenry sp->s_value = dotp->e_xvalue; 127595Sbill njxxx++; 128595Sbill } else { 129*630Shenry mask = (1 << xp->e_xvalue) - 1; 130*630Shenry while (dotp->e_xvalue & mask){ 131595Sbill #ifdef UNIX 132595Sbill outb(0); 133595Sbill #endif UNIX 134595Sbill #ifdef VMS 135595Sbill *vms_obj_ptr++ = -1; 136595Sbill *vms_obj_ptr++ = 0; 137*630Shenry dotp->e_xvalue += 1; 138595Sbill #endif VMS 139595Sbill } 140595Sbill } 141595Sbill } 142595Sbill 143595Sbill /* 144595Sbill * Pass 1.5, resolve jxxx instructions and .align in .text 145595Sbill */ 146595Sbill jxxxfix() 147595Sbill { 148595Sbill register struct symtab *jumpfrom; 149595Sbill struct symtab **cojumpfrom, *ubjumpfrom; 150595Sbill register struct symtab *dest; 151595Sbill register struct symtab *intdest; /*intermediate dest*/ 152595Sbill register struct symtab **cointdest, *ubintdest; 153595Sbill 154595Sbill register struct symtab *tunnel; 155595Sbill int displ,nchange; 156595Sbill int badjxalign; /*if jump across an align*/ 157595Sbill int stillactives; /*if still active jxxxes*/ 158595Sbill int segno; /*current segment number*/ 159595Sbill int topono; /*which iteration in the topo sort*/ 160595Sbill register unsigned char tag; 161595Sbill /* 162595Sbill * consider each segment in turn... 163595Sbill */ 164595Sbill for (segno = 0; segno < NLOC + NLOC; segno++){ 165595Sbill badjxalign = 0; /*done on a per segment basis*/ 166595Sbill /* 167595Sbill * Do a lazy topological sort. 168595Sbill */ 169595Sbill for (topono = 1, nchange = 1; nchange != 0; topono++){ 170595Sbill #ifdef DEBUG 171595Sbill if (debug) 172595Sbill printf("\nSegment %d, topo iteration %d\n", 173595Sbill segno, topono); 174595Sbill #endif 175595Sbill nchange = 0; 176595Sbill stillactives = 0; 177595Sbill /* 178595Sbill * We keep track of one possible tunnel location. 179595Sbill * A tunnel will eventually be an unconditional 180595Sbill * branch to the same place that another jxxx 181595Sbill * will want to branch to. We will turn a 182595Sbill * branch conditional/unconditional (word) that would 183595Sbill * have to get bumped because its destination is too 184595Sbill * far away, into a branch conditional/unconditional 185595Sbill * byte to the tunnel branch conditional/unconditional. 186595Sbill * Of course, the tunnel must branch to the same place 187595Sbill * as we want to go. 188595Sbill */ 189595Sbill tunnel = 0; /*initially, no tunnel*/ 190595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){ 191*630Shenry tag = jumpfrom->s_tag; 192595Sbill if (tag <= IGNOREBOUND) 193595Sbill continue; /*just an ordinary symbol*/ 194595Sbill if (tag == JXALIGN){ 195595Sbill tunnel = 0; /*avoid tunneling across a flex alocation*/ 196595Sbill continue; /*we take care of these later*/ 197595Sbill } 198*630Shenry if ( jumpfrom->s_jxfear == JBRFSIZE /*unconditional*/ 199595Sbill || ( tag == JXINACTIVE /*inactive bumped*/ 200*630Shenry && (jumpfrom->s_jxbump != 0) 201595Sbill ) 202595Sbill ) tunnel = jumpfrom; 203595Sbill if (tag != JXACTIVE) 204595Sbill continue; 205*630Shenry dest = jumpfrom->s_dest; 206*630Shenry if (jumpfrom->s_index != dest->s_index){ 207595Sbill yyerror("Intersegment jxxx"); 208595Sbill continue; 209595Sbill } 210*630Shenry displ = dest->s_value - jumpfrom->s_value; 211595Sbill if (displ < MINBYTE || displ > MAXBYTE) { 212595Sbill /* 213595Sbill * This is an immediate lose! 214595Sbill * 215595Sbill * We first attempt to tunnel 216595Sbill * by finding an intervening jump that 217595Sbill * has the same destination. 218595Sbill * The tunnel is always the first preceeding 219595Sbill * jxxx instruction, so the displacement 220595Sbill * to the tunnel is less than zero, and 221595Sbill * its relative position will be unaffected 222595Sbill * by future jxxx expansions. 223595Sbill */ 224*630Shenry if ( (jumpfrom->s_jxfear > JBRFSIZE) 225595Sbill && (tunnel) 226*630Shenry && (tunnel->s_dest == jumpfrom->s_dest) 227*630Shenry && (tunnel->s_index == jumpfrom->s_index) 228*630Shenry && (tunnel->s_value - jumpfrom->s_value >= 229595Sbill MINBYTE + JXXXFSIZE) 230595Sbill ) { 231595Sbill /* 232595Sbill * tunnelling is OK 233595Sbill */ 234*630Shenry jumpfrom->s_dest = tunnel; 235595Sbill /* 236595Sbill * no bumping needed, this 237595Sbill * is now effectively inactive 238595Sbill * but must be remembered 239595Sbill */ 240*630Shenry jumpfrom->s_tag = JXTUNNEL; 241595Sbill #ifdef DEBUG 242595Sbill if(debug) 243595Sbill printf("Tunnel from %s from line %d\n", 244*630Shenry jumpfrom->s_name, lineno); 245595Sbill #endif 246595Sbill continue; 247595Sbill } else { /*tunneling not possible*/ 248595Sbill /* 249595Sbill * since this will be turned 250595Sbill * into a bumped jump, we can 251595Sbill * use the unconditional jump 252595Sbill * as a tunnel 253595Sbill */ 254595Sbill tunnel = jumpfrom; 255*630Shenry jumpfrom->s_tag = JXNOTYET; 256595Sbill ++nchange; 257595Sbill continue; 258595Sbill } 259595Sbill } /*end of immediate lose*/ 260595Sbill /* 261595Sbill * Do a forward search for an intervening jxxx 262595Sbill */ 263595Sbill if (displ >= 0) { 264595Sbill SEGITERATE(segno, cojumpfrom + 1,0,cointdest, 265595Sbill intdest, ubintdest, ++){ 266*630Shenry if (intdest->s_value > dest->s_value) 267595Sbill break; /* beyond destination */ 268*630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 269595Sbill continue; /*frozen solid*/ 270*630Shenry if (intdest->s_tag == JXALIGN){ 271*630Shenry jumpfrom->s_jxoveralign = 1; 272595Sbill badjxalign++; 273595Sbill } 274595Sbill /* 275595Sbill * we assume the worst case 276595Sbill * for unfrozen jxxxxes 277595Sbill */ 278*630Shenry displ += intdest->s_jxfear; 279595Sbill } 280595Sbill if (displ <= MAXBYTE){ 281595Sbill /* 282595Sbill * the worst possible conditions 283595Sbill * can't hurt us, so forget about 284595Sbill * this jump 285595Sbill */ 286*630Shenry jumpfrom->s_tag = JXINACTIVE; 287595Sbill } else { 288595Sbill stillactives++; 289595Sbill } 290595Sbill } else { 291595Sbill /* 292595Sbill * backward search for intervening jxxx 293595Sbill */ 294595Sbill SEGITERATE(segno, cojumpfrom - 1,1,cointdest, 295595Sbill intdest, ubintdest, --){ 296*630Shenry if (intdest->s_value <= dest->s_value) 297595Sbill break; /* beyond destination */ 298*630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 299595Sbill continue; /*frozen solid*/ 300*630Shenry if (intdest->s_tag == JXALIGN){ 301*630Shenry jumpfrom->s_jxoveralign = 1; 302595Sbill badjxalign++; 303595Sbill } 304*630Shenry displ -= intdest->s_jxfear; 305595Sbill } 306595Sbill if (displ >= MINBYTE) { 307*630Shenry jumpfrom->s_tag = JXINACTIVE; 308595Sbill } else { 309595Sbill stillactives++; 310595Sbill } 311595Sbill } /*end of backwards search*/ 312595Sbill } /*end of iterating through all symbols in this seg*/ 313595Sbill 314595Sbill if (nchange == 0) { 315595Sbill /* 316595Sbill * Now, if there are still active jxxx entries, 317595Sbill * we are partially deadlocked. We can leave 318595Sbill * these jxxx entries in their assumed short jump 319595Sbill * form, as all initial displacement calcualtions 320595Sbill * are hanging on unresolved jxxx instructions 321595Sbill * that might explode into a long form, causing 322595Sbill * other jxxxes jumping across the first set of 323595Sbill * jxxxes to explode, etc. 324595Sbill * However, if a jxxx jumps across a .align, 325595Sbill * we assume the worst for the deadlock cycle, 326595Sbill * and resolve all of them towards the long 327595Sbill * jump. 328595Sbill * Currently, the C compiler does not produce 329595Sbill * jumps across aligns, as aligns are only used 330595Sbill * in data segments, or in text segments to align 331595Sbill * functions. 332595Sbill */ 333595Sbill if (stillactives){ 334595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 335595Sbill ubjumpfrom, ++){ 336*630Shenry if (jumpfrom->s_tag == JXACTIVE){ 337*630Shenry jumpfrom->s_tag = 338595Sbill badjxalign?JXNOTYET:JXINACTIVE; 339595Sbill } 340595Sbill } 341595Sbill if (badjxalign){ 342595Sbill jxxxbump(segno, (struct symtab **)0); 343595Sbill } 344595Sbill } 345595Sbill /* 346595Sbill * Handle all of the .align s 347595Sbill */ 348595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 349595Sbill ubjumpfrom, ++){ 350*630Shenry if (jumpfrom->s_tag == JXALIGN){ 351595Sbill /* 352595Sbill * Predict the true displacement 353595Sbill * needed, irregardless of the 354595Sbill * fact that we guessed 1 355595Sbill */ 356*630Shenry displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear; 357595Sbill if (displ == 0){ /*no virtual displacement*/ 358*630Shenry jumpfrom->s_jxfear = -1; 359595Sbill } else { 360*630Shenry jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ; 361595Sbill /* 362*630Shenry * assert jumpfrom->s_jxfear > 0 363595Sbill */ 364*630Shenry if (jumpfrom->s_jxfear == 1){ 365595Sbill /*our prediction was correct*/ 366595Sbill continue; 367595Sbill } 368595Sbill /* 369*630Shenry * assert jumpfrom->s_jxfear > 1 370595Sbill */ 371*630Shenry jumpfrom->s_jxfear -= 1; /*correct guess*/ 372595Sbill } 373595Sbill /* 374*630Shenry * assert jumpfrom->s_jxfear = -1, +1...2**n-1 375595Sbill */ 376*630Shenry jumpfrom->s_tag = JXNOTYET; /*signal*/ 377595Sbill jxxxbump(segno, cojumpfrom); 378*630Shenry jumpfrom->s_tag = JXINACTIVE; 379595Sbill /* 380595Sbill * Assert jxfrom->jxvalue indexes the first 381595Sbill * code byte after the added bytes, and 382595Sbill * has n low order zeroes. 383595Sbill */ 384595Sbill } 385595Sbill } /*end of walking through each segment*/ 386595Sbill } /*end of no changes */ 387595Sbill else { /*changes, and still have to try another pass*/ 388595Sbill jxxxbump(segno, (struct symtab **)0); 389595Sbill } 390595Sbill } /*end of doing the topologic sort*/ 391595Sbill } /*end of iterating through all segments*/ 392595Sbill } /*end of jxxxfix*/ 393595Sbill 394595Sbill /* 395595Sbill * Go through the symbols in a given segment number, 396595Sbill * and see which entries are jxxx entries that have 397595Sbill * been logically "exploded" (expanded), but for which 398595Sbill * the value of textually following symbols has not been 399595Sbill * increased 400595Sbill */ 401595Sbill 402595Sbill jxxxbump(segno, starthint) 403595Sbill int segno; 404595Sbill struct symtab **starthint; 405595Sbill { 406595Sbill register struct symtab **cosp, *sp; 407595Sbill register struct symtab *ub; 408595Sbill register int cum_bump; 409595Sbill register unsigned char tag; 410595Sbill 411595Sbill cum_bump = 0; 412595Sbill SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){ 413*630Shenry tag = sp->s_tag; 414595Sbill if (tag == JXNOTYET){ 415595Sbill #ifdef DEBUG 416595Sbill if (debug){ 417*630Shenry if (sp->s_dest != 0) 418595Sbill printf("Explode jump to %s on line %d\n", 419*630Shenry sp->s_dest->s_name, lineno); 420595Sbill else 421595Sbill printf("Explode an align!\n"); 422595Sbill } 423595Sbill #endif 424*630Shenry sp->s_tag = JXINACTIVE; 425*630Shenry sp->s_jxbump = 1; 426*630Shenry cum_bump += sp->s_jxfear; 427595Sbill } 428595Sbill /* 429595Sbill * Only bump labels and jxxxes. Ignored entries can 430595Sbill * be incremented, as they are thrown away later on. 431595Sbill * Stabds are given their final value in the second 432595Sbill * pass. 433595Sbill */ 434595Sbill if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/ 435*630Shenry sp->s_value += cum_bump; 436595Sbill } 437*630Shenry usedot[segno].e_xvalue += cum_bump; 438595Sbill } 439