1595Sbill /* Copyright (c) 1980 Regents of the University of California */ 2*680Shenry static char sccsid[] = "@(#)asjxxx.c 4.5 08/20/80"; 3595Sbill #include <stdio.h> 4595Sbill #include "as.h" 5595Sbill #include "assyms.h" 6595Sbill 7636Shenry #define JBR 0x11 8636Shenry #define BRW 0x31 9636Shenry #define JMP 0x17 10595Sbill 11595Sbill /* 12595Sbill * The number of bytes to add if the jxxx must be "exploded" 13595Sbill * into the long form 14595Sbill */ 15636Shenry #define JBRDELTA 1 /* brb <byte> ==> brw <byte> <byte> */ 16636Shenry #define JXXXDELTA 3 /* brb <byte> ==> brb <byte> brw <byte> <byte> */ 17636Shenry #define JBRJDELTA d124 /* brb <byte> ==> jmp L^(pc) <byte>*d124 */ 18636Shenry #define JXXXJDELTA d124+2 /* brb <byte> ==> brb <byte> jmp L^(pc) <byte>*d124 */ 19595Sbill 20636Shenry int jbrfsize = JBRDELTA; 21636Shenry int jxxxfsize = JXXXDELTA; 22636Shenry 23595Sbill /* 24595Sbill * These variables are filled by asscan.c with the 25595Sbill * last name encountered (a pointer buried in the intermediate file), 26595Sbill * and the last jxxx symbol table entry encountered. 27595Sbill */ 28595Sbill struct symtab *lastnam; 29595Sbill struct symtab *lastjxxx; 30595Sbill 31636Shenry initijxxx() 32636Shenry { 33636Shenry jbrfsize = jxxxJUMP ? JBRJDELTA : JBRDELTA; 34636Shenry jxxxfsize = jxxxJUMP ? JXXXJDELTA : JXXXDELTA; 35636Shenry /* 36636Shenry * Note: ifjxxxJUMP is set, then we do NOT do any tunnelling; 37636Shenry * this was too complicated to figure out, and in the first 38636Shenry * version of the assembler, tunnelling proved to be the hardest 39636Shenry * to get to work! 40636Shenry */ 41636Shenry } 42595Sbill /* 43595Sbill * Handle jxxx instructions 44595Sbill */ 45595Sbill ijxout(op,ap,nact) 46595Sbill struct arg *ap; 47595Sbill { 48595Sbill if (passno == 1){ 49595Sbill /* 50595Sbill * READ THIS BEFORE LOOKING AT jxxxfix() 51595Sbill * 52595Sbill * Record the jxxx in a special symbol table entry 53595Sbill */ 54595Sbill register struct symtab *jumpfrom; 55595Sbill 56595Sbill /* 57595Sbill * We assume the MINIMAL length 58595Sbill */ 59595Sbill putins(op,ap,nact); 60595Sbill jumpfrom = lastjxxx; 61630Shenry jumpfrom->s_tag = JXACTIVE; 62630Shenry jumpfrom->s_jxbump = 0; 63595Sbill if (op == JBR) 64636Shenry jumpfrom->s_jxfear = jbrfsize; 65595Sbill else 66636Shenry jumpfrom->s_jxfear = jxxxfsize; 67595Sbill if (lastnam == 0) 68595Sbill yyerror("jxxx destination not a label"); 69630Shenry jumpfrom->s_dest = lastnam; 70630Shenry jumpfrom->s_type = dotp->e_xtype; /*only TEXT or DATA*/ 71630Shenry jumpfrom->s_index = dotp-usedot; 72595Sbill /* 73595Sbill * value ALWAYS (ALWAYS!!!) indexes the next instruction 74595Sbill * after the jump, even in the jump must be exploded 75595Sbill * (bumped) 76595Sbill */ 77630Shenry jumpfrom->s_value = dotp->e_xvalue; 78595Sbill njxxx++; 79595Sbill } else {/* pass2, resolve */ 80595Sbill /* 81595Sbill * READ THIS AFTER LOOKING AT jxxxfix() 82595Sbill */ 83595Sbill register long oxvalue; 84595Sbill register struct exp *xp; 85595Sbill register struct symtab *tunnel; 86595Sbill register struct arg *aplast; 87595Sbill 88595Sbill aplast = ap + nact - 1; 89630Shenry xp = aplast->a_xp; 90630Shenry if (lastjxxx->s_tag == JXTUNNEL){ 91630Shenry lastjxxx->s_tag = JXINACTIVE; 92630Shenry tunnel = lastjxxx->s_dest; 93630Shenry xp->e_xvalue = tunnel->s_value /*index of instruction following*/ 94595Sbill - 3 /* size of brw + word*/ 95636Shenry + ( ( (tunnel->s_jxfear == jbrfsize) && 96630Shenry (tunnel->s_jxbump == 0))?1:0); 97595Sbill /*non bumped branch byteis only 2 back*/ 98595Sbill } 99630Shenry if (lastjxxx->s_jxbump == 0){ /*wasn't bumped, so is short form*/ 100595Sbill putins(op, ap, nact); 101595Sbill } else { 102595Sbill if (op != JBR){ /*branch reverse conditional byte over 103595Sbill branch unconditional word*/ 104630Shenry oxvalue = xp->e_xvalue; 105630Shenry xp->e_xvalue = lastjxxx->s_value; 106595Sbill putins(op^1, ap, nact); 107630Shenry xp->e_xvalue = oxvalue; 108595Sbill } 109636Shenry putins(jxxxJUMP ? JMP : BRW, aplast, 1); 110595Sbill } 111595Sbill } 112595Sbill } /*end of ijxout*/ 113595Sbill 114595Sbill jalign(xp, sp) 115595Sbill register struct exp *xp; 116595Sbill register struct symtab *sp; 117595Sbill { 118595Sbill register int mask; 119*680Shenry /* 120*680Shenry * Problem with .align 121*680Shenry * 122*680Shenry * When the loader constructs an executable file from 123*680Shenry * a number of objects, it effectively concatnates 124*680Shenry * together all of the text segments from all objects, 125*680Shenry * and then all of the data segments. 126*680Shenry * 127*680Shenry * If we do an align by a large value, we can align 128*680Shenry * within the a.out this assembly produces, but 129*680Shenry * after the loader concatnates, the alignment can't 130*680Shenry * be guaranteed if the objects preceding this one 131*680Shenry * in the load are also aligned to the same size. 132*680Shenry * 133*680Shenry * Currently, the loader guarantees full word alignment. 134*680Shenry * So, ridiculous aligns are caught here and converted 135*680Shenry * to a .align 2, if possible. 136*680Shenry */ 137678Shenry if ( (xp->e_xtype != XABS) 138678Shenry || (xp->e_xvalue < 0) 139678Shenry || (xp->e_xvalue > 16) 140678Shenry ) { 141595Sbill yyerror("Illegal `align' argument"); 142595Sbill return; 143595Sbill } 144*680Shenry if (xp->e_xvalue > 2){ 145*680Shenry if (passno == 1){ 146*680Shenry yywarning(".align %d in any segment is NOT preserved by the loader", 147*680Shenry xp->e_xvalue); 148*680Shenry yywarning(".align %d converted to .align 2", 149*680Shenry xp->e_xvalue); 150*680Shenry } 151*680Shenry xp->e_xvalue = 2; 152678Shenry } 153595Sbill flushfield(NBPW/4); 154595Sbill if (passno == 1) { 155630Shenry sp->s_tag = JXALIGN; 156630Shenry sp->s_jxfear = (1 << xp->e_xvalue) - 1; 157630Shenry sp->s_type = dotp->e_xtype; 158630Shenry sp->s_index = dotp-usedot; 159595Sbill /* 160595Sbill * We guess that the align will take up at least one 161595Sbill * byte in the code output. We will correct for this 162595Sbill * initial high guess when we explode (bump) aligns 163595Sbill * when we fix the jxxxes. We must do this guess 164595Sbill * so that the symbol table is sorted correctly 165595Sbill * and labels declared to fall before the align 166595Sbill * really get their, instead of guessing zero size 167595Sbill * and have the label (incorrectly) fall after the jxxx. 168595Sbill * This is a quirk of our requirement that indices into 169595Sbill * the code stream point to the next byte following 170595Sbill * the logical entry in the symbol table 171595Sbill */ 172630Shenry dotp->e_xvalue += 1; 173630Shenry sp->s_value = dotp->e_xvalue; 174595Sbill njxxx++; 175595Sbill } else { 176630Shenry mask = (1 << xp->e_xvalue) - 1; 177630Shenry while (dotp->e_xvalue & mask){ 178595Sbill #ifdef UNIX 179595Sbill outb(0); 180595Sbill #endif UNIX 181595Sbill #ifdef VMS 182595Sbill *vms_obj_ptr++ = -1; 183595Sbill *vms_obj_ptr++ = 0; 184630Shenry dotp->e_xvalue += 1; 185595Sbill #endif VMS 186595Sbill } 187595Sbill } 188595Sbill } 189595Sbill 190595Sbill /* 191595Sbill * Pass 1.5, resolve jxxx instructions and .align in .text 192595Sbill */ 193595Sbill jxxxfix() 194595Sbill { 195595Sbill register struct symtab *jumpfrom; 196595Sbill struct symtab **cojumpfrom, *ubjumpfrom; 197595Sbill register struct symtab *dest; 198595Sbill register struct symtab *intdest; /*intermediate dest*/ 199595Sbill register struct symtab **cointdest, *ubintdest; 200595Sbill 201595Sbill register struct symtab *tunnel; 202595Sbill int displ,nchange; 203595Sbill int badjxalign; /*if jump across an align*/ 204595Sbill int stillactives; /*if still active jxxxes*/ 205595Sbill int segno; /*current segment number*/ 206595Sbill int topono; /*which iteration in the topo sort*/ 207595Sbill register unsigned char tag; 208595Sbill /* 209595Sbill * consider each segment in turn... 210595Sbill */ 211595Sbill for (segno = 0; segno < NLOC + NLOC; segno++){ 212595Sbill badjxalign = 0; /*done on a per segment basis*/ 213595Sbill /* 214595Sbill * Do a lazy topological sort. 215595Sbill */ 216595Sbill for (topono = 1, nchange = 1; nchange != 0; topono++){ 217595Sbill #ifdef DEBUG 218595Sbill if (debug) 219595Sbill printf("\nSegment %d, topo iteration %d\n", 220595Sbill segno, topono); 221595Sbill #endif 222595Sbill nchange = 0; 223595Sbill stillactives = 0; 224595Sbill /* 225595Sbill * We keep track of one possible tunnel location. 226595Sbill * A tunnel will eventually be an unconditional 227595Sbill * branch to the same place that another jxxx 228595Sbill * will want to branch to. We will turn a 229595Sbill * branch conditional/unconditional (word) that would 230595Sbill * have to get bumped because its destination is too 231595Sbill * far away, into a branch conditional/unconditional 232595Sbill * byte to the tunnel branch conditional/unconditional. 233595Sbill * Of course, the tunnel must branch to the same place 234595Sbill * as we want to go. 235595Sbill */ 236595Sbill tunnel = 0; /*initially, no tunnel*/ 237595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){ 238630Shenry tag = jumpfrom->s_tag; 239595Sbill if (tag <= IGNOREBOUND) 240595Sbill continue; /*just an ordinary symbol*/ 241595Sbill if (tag == JXALIGN){ 242595Sbill tunnel = 0; /*avoid tunneling across a flex alocation*/ 243595Sbill continue; /*we take care of these later*/ 244595Sbill } 245636Shenry if ( jumpfrom->s_jxfear == jbrfsize /*unconditional*/ 246595Sbill || ( tag == JXINACTIVE /*inactive bumped*/ 247630Shenry && (jumpfrom->s_jxbump != 0) 248595Sbill ) 249595Sbill ) tunnel = jumpfrom; 250595Sbill if (tag != JXACTIVE) 251595Sbill continue; 252630Shenry dest = jumpfrom->s_dest; 253630Shenry if (jumpfrom->s_index != dest->s_index){ 254595Sbill yyerror("Intersegment jxxx"); 255595Sbill continue; 256595Sbill } 257630Shenry displ = dest->s_value - jumpfrom->s_value; 258595Sbill if (displ < MINBYTE || displ > MAXBYTE) { 259595Sbill /* 260595Sbill * This is an immediate lose! 261595Sbill * 262595Sbill * We first attempt to tunnel 263595Sbill * by finding an intervening jump that 264595Sbill * has the same destination. 265595Sbill * The tunnel is always the first preceeding 266595Sbill * jxxx instruction, so the displacement 267595Sbill * to the tunnel is less than zero, and 268595Sbill * its relative position will be unaffected 269595Sbill * by future jxxx expansions. 270636Shenry * 271636Shenry * No tunnels if doing jumps... 272595Sbill */ 273636Shenry if ( (!jxxxJUMP) 274636Shenry && (jumpfrom->s_jxfear > jbrfsize) 275595Sbill && (tunnel) 276630Shenry && (tunnel->s_dest == jumpfrom->s_dest) 277630Shenry && (tunnel->s_index == jumpfrom->s_index) 278630Shenry && (tunnel->s_value - jumpfrom->s_value >= 279636Shenry MINBYTE + jxxxfsize) 280595Sbill ) { 281595Sbill /* 282595Sbill * tunnelling is OK 283595Sbill */ 284630Shenry jumpfrom->s_dest = tunnel; 285595Sbill /* 286595Sbill * no bumping needed, this 287595Sbill * is now effectively inactive 288595Sbill * but must be remembered 289595Sbill */ 290630Shenry jumpfrom->s_tag = JXTUNNEL; 291595Sbill #ifdef DEBUG 292595Sbill if(debug) 293595Sbill printf("Tunnel from %s from line %d\n", 294630Shenry jumpfrom->s_name, lineno); 295595Sbill #endif 296595Sbill continue; 297595Sbill } else { /*tunneling not possible*/ 298595Sbill /* 299595Sbill * since this will be turned 300595Sbill * into a bumped jump, we can 301595Sbill * use the unconditional jump 302595Sbill * as a tunnel 303595Sbill */ 304595Sbill tunnel = jumpfrom; 305630Shenry jumpfrom->s_tag = JXNOTYET; 306595Sbill ++nchange; 307595Sbill continue; 308595Sbill } 309595Sbill } /*end of immediate lose*/ 310595Sbill /* 311595Sbill * Do a forward search for an intervening jxxx 312595Sbill */ 313595Sbill if (displ >= 0) { 314595Sbill SEGITERATE(segno, cojumpfrom + 1,0,cointdest, 315595Sbill intdest, ubintdest, ++){ 316630Shenry if (intdest->s_value > dest->s_value) 317595Sbill break; /* beyond destination */ 318630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 319595Sbill continue; /*frozen solid*/ 320630Shenry if (intdest->s_tag == JXALIGN){ 321630Shenry jumpfrom->s_jxoveralign = 1; 322595Sbill badjxalign++; 323595Sbill } 324595Sbill /* 325595Sbill * we assume the worst case 326595Sbill * for unfrozen jxxxxes 327595Sbill */ 328630Shenry displ += intdest->s_jxfear; 329595Sbill } 330595Sbill if (displ <= MAXBYTE){ 331595Sbill /* 332595Sbill * the worst possible conditions 333595Sbill * can't hurt us, so forget about 334595Sbill * this jump 335595Sbill */ 336630Shenry jumpfrom->s_tag = JXINACTIVE; 337595Sbill } else { 338595Sbill stillactives++; 339595Sbill } 340595Sbill } else { 341595Sbill /* 342595Sbill * backward search for intervening jxxx 343595Sbill */ 344595Sbill SEGITERATE(segno, cojumpfrom - 1,1,cointdest, 345595Sbill intdest, ubintdest, --){ 346630Shenry if (intdest->s_value <= dest->s_value) 347595Sbill break; /* beyond destination */ 348630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 349595Sbill continue; /*frozen solid*/ 350630Shenry if (intdest->s_tag == JXALIGN){ 351630Shenry jumpfrom->s_jxoveralign = 1; 352595Sbill badjxalign++; 353595Sbill } 354630Shenry displ -= intdest->s_jxfear; 355595Sbill } 356595Sbill if (displ >= MINBYTE) { 357630Shenry jumpfrom->s_tag = JXINACTIVE; 358595Sbill } else { 359595Sbill stillactives++; 360595Sbill } 361595Sbill } /*end of backwards search*/ 362595Sbill } /*end of iterating through all symbols in this seg*/ 363595Sbill 364595Sbill if (nchange == 0) { 365595Sbill /* 366595Sbill * Now, if there are still active jxxx entries, 367595Sbill * we are partially deadlocked. We can leave 368595Sbill * these jxxx entries in their assumed short jump 369595Sbill * form, as all initial displacement calcualtions 370595Sbill * are hanging on unresolved jxxx instructions 371595Sbill * that might explode into a long form, causing 372595Sbill * other jxxxes jumping across the first set of 373595Sbill * jxxxes to explode, etc. 374595Sbill * However, if a jxxx jumps across a .align, 375595Sbill * we assume the worst for the deadlock cycle, 376595Sbill * and resolve all of them towards the long 377595Sbill * jump. 378595Sbill * Currently, the C compiler does not produce 379595Sbill * jumps across aligns, as aligns are only used 380595Sbill * in data segments, or in text segments to align 381595Sbill * functions. 382595Sbill */ 383595Sbill if (stillactives){ 384595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 385595Sbill ubjumpfrom, ++){ 386630Shenry if (jumpfrom->s_tag == JXACTIVE){ 387630Shenry jumpfrom->s_tag = 388595Sbill badjxalign?JXNOTYET:JXINACTIVE; 389595Sbill } 390595Sbill } 391595Sbill if (badjxalign){ 392595Sbill jxxxbump(segno, (struct symtab **)0); 393595Sbill } 394595Sbill } 395595Sbill /* 396595Sbill * Handle all of the .align s 397595Sbill */ 398595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 399595Sbill ubjumpfrom, ++){ 400630Shenry if (jumpfrom->s_tag == JXALIGN){ 401595Sbill /* 402595Sbill * Predict the true displacement 403595Sbill * needed, irregardless of the 404595Sbill * fact that we guessed 1 405595Sbill */ 406630Shenry displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear; 407595Sbill if (displ == 0){ /*no virtual displacement*/ 408630Shenry jumpfrom->s_jxfear = -1; 409595Sbill } else { 410630Shenry jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ; 411595Sbill /* 412630Shenry * assert jumpfrom->s_jxfear > 0 413595Sbill */ 414630Shenry if (jumpfrom->s_jxfear == 1){ 415595Sbill /*our prediction was correct*/ 416595Sbill continue; 417595Sbill } 418595Sbill /* 419630Shenry * assert jumpfrom->s_jxfear > 1 420595Sbill */ 421630Shenry jumpfrom->s_jxfear -= 1; /*correct guess*/ 422595Sbill } 423595Sbill /* 424630Shenry * assert jumpfrom->s_jxfear = -1, +1...2**n-1 425595Sbill */ 426630Shenry jumpfrom->s_tag = JXNOTYET; /*signal*/ 427595Sbill jxxxbump(segno, cojumpfrom); 428630Shenry jumpfrom->s_tag = JXINACTIVE; 429595Sbill /* 430595Sbill * Assert jxfrom->jxvalue indexes the first 431595Sbill * code byte after the added bytes, and 432595Sbill * has n low order zeroes. 433595Sbill */ 434595Sbill } 435595Sbill } /*end of walking through each segment*/ 436595Sbill } /*end of no changes */ 437595Sbill else { /*changes, and still have to try another pass*/ 438595Sbill jxxxbump(segno, (struct symtab **)0); 439595Sbill } 440595Sbill } /*end of doing the topologic sort*/ 441595Sbill } /*end of iterating through all segments*/ 442595Sbill } /*end of jxxxfix*/ 443595Sbill 444595Sbill /* 445595Sbill * Go through the symbols in a given segment number, 446595Sbill * and see which entries are jxxx entries that have 447595Sbill * been logically "exploded" (expanded), but for which 448595Sbill * the value of textually following symbols has not been 449595Sbill * increased 450595Sbill */ 451595Sbill 452595Sbill jxxxbump(segno, starthint) 453595Sbill int segno; 454595Sbill struct symtab **starthint; 455595Sbill { 456595Sbill register struct symtab **cosp, *sp; 457595Sbill register struct symtab *ub; 458595Sbill register int cum_bump; 459595Sbill register unsigned char tag; 460595Sbill 461595Sbill cum_bump = 0; 462595Sbill SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){ 463630Shenry tag = sp->s_tag; 464595Sbill if (tag == JXNOTYET){ 465595Sbill #ifdef DEBUG 466595Sbill if (debug){ 467630Shenry if (sp->s_dest != 0) 468595Sbill printf("Explode jump to %s on line %d\n", 469630Shenry sp->s_dest->s_name, lineno); 470595Sbill else 471595Sbill printf("Explode an align!\n"); 472595Sbill } 473595Sbill #endif 474630Shenry sp->s_tag = JXINACTIVE; 475630Shenry sp->s_jxbump = 1; 476630Shenry cum_bump += sp->s_jxfear; 477595Sbill } 478595Sbill /* 479595Sbill * Only bump labels and jxxxes. Ignored entries can 480595Sbill * be incremented, as they are thrown away later on. 481595Sbill * Stabds are given their final value in the second 482595Sbill * pass. 483595Sbill */ 484595Sbill if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/ 485630Shenry sp->s_value += cum_bump; 486595Sbill } 487630Shenry usedot[segno].e_xvalue += cum_bump; 488595Sbill } 489