15825Srrh /* 25825Srrh * Copyright (c) 1982 Regents of the University of California 35825Srrh */ 45825Srrh #ifndef lint 5*13512Srrh static char sccsid[] = "@(#)asjxxx.c 4.7 06/30/83"; 65825Srrh #endif not lint 75825Srrh 8595Sbill #include <stdio.h> 9595Sbill #include "as.h" 10595Sbill #include "assyms.h" 11595Sbill 12636Shenry #define JBR 0x11 13636Shenry #define BRW 0x31 14636Shenry #define JMP 0x17 15595Sbill 16595Sbill /* 17595Sbill * The number of bytes to add if the jxxx must be "exploded" 18595Sbill * into the long form 19595Sbill */ 20636Shenry #define JBRDELTA 1 /* brb <byte> ==> brw <byte> <byte> */ 21636Shenry #define JXXXDELTA 3 /* brb <byte> ==> brb <byte> brw <byte> <byte> */ 22636Shenry #define JBRJDELTA d124 /* brb <byte> ==> jmp L^(pc) <byte>*d124 */ 23636Shenry #define JXXXJDELTA d124+2 /* brb <byte> ==> brb <byte> jmp L^(pc) <byte>*d124 */ 24595Sbill 25636Shenry int jbrfsize = JBRDELTA; 26636Shenry int jxxxfsize = JXXXDELTA; 27636Shenry 28595Sbill /* 29595Sbill * These variables are filled by asscan.c with the 30595Sbill * last name encountered (a pointer buried in the intermediate file), 31595Sbill * and the last jxxx symbol table entry encountered. 32595Sbill */ 33595Sbill struct symtab *lastnam; 34595Sbill struct symtab *lastjxxx; 35595Sbill 36636Shenry initijxxx() 37636Shenry { 38636Shenry jbrfsize = jxxxJUMP ? JBRJDELTA : JBRDELTA; 39636Shenry jxxxfsize = jxxxJUMP ? JXXXJDELTA : JXXXDELTA; 40636Shenry /* 41636Shenry * Note: ifjxxxJUMP is set, then we do NOT do any tunnelling; 42636Shenry * this was too complicated to figure out, and in the first 43636Shenry * version of the assembler, tunnelling proved to be the hardest 44636Shenry * to get to work! 45636Shenry */ 46636Shenry } 47595Sbill /* 48595Sbill * Handle jxxx instructions 49595Sbill */ 505825Srrh ijxout(opcode, ap, nact) 515825Srrh struct Opcode opcode; 525825Srrh struct arg *ap; 535825Srrh int nact; 54595Sbill { 55595Sbill if (passno == 1){ 56595Sbill /* 57595Sbill * READ THIS BEFORE LOOKING AT jxxxfix() 58595Sbill * 59595Sbill * Record the jxxx in a special symbol table entry 60595Sbill */ 61595Sbill register struct symtab *jumpfrom; 62595Sbill 63595Sbill /* 64595Sbill * We assume the MINIMAL length 65595Sbill */ 665825Srrh putins(opcode, ap, nact); 67595Sbill jumpfrom = lastjxxx; 68630Shenry jumpfrom->s_tag = JXACTIVE; 69630Shenry jumpfrom->s_jxbump = 0; 705825Srrh if (opcode.Op_popcode == JBR) 71636Shenry jumpfrom->s_jxfear = jbrfsize; 72595Sbill else 73636Shenry jumpfrom->s_jxfear = jxxxfsize; 74595Sbill if (lastnam == 0) 75595Sbill yyerror("jxxx destination not a label"); 76630Shenry jumpfrom->s_dest = lastnam; 77630Shenry jumpfrom->s_type = dotp->e_xtype; /*only TEXT or DATA*/ 78630Shenry jumpfrom->s_index = dotp-usedot; 79595Sbill /* 80595Sbill * value ALWAYS (ALWAYS!!!) indexes the next instruction 81595Sbill * after the jump, even in the jump must be exploded 82595Sbill * (bumped) 83595Sbill */ 84630Shenry jumpfrom->s_value = dotp->e_xvalue; 85595Sbill njxxx++; 86595Sbill } else {/* pass2, resolve */ 87595Sbill /* 88595Sbill * READ THIS AFTER LOOKING AT jxxxfix() 89595Sbill */ 905825Srrh reg long oxvalue; 915825Srrh reg struct exp *xp; 925825Srrh reg struct symtab *tunnel; 935825Srrh reg struct arg *aplast; 945825Srrh struct Opcode nopcode; 95595Sbill 96595Sbill aplast = ap + nact - 1; 97630Shenry xp = aplast->a_xp; 98630Shenry if (lastjxxx->s_tag == JXTUNNEL){ 99630Shenry lastjxxx->s_tag = JXINACTIVE; 100630Shenry tunnel = lastjxxx->s_dest; 101630Shenry xp->e_xvalue = tunnel->s_value /*index of instruction following*/ 102595Sbill - 3 /* size of brw + word*/ 103636Shenry + ( ( (tunnel->s_jxfear == jbrfsize) && 104630Shenry (tunnel->s_jxbump == 0))?1:0); 105595Sbill /*non bumped branch byteis only 2 back*/ 106595Sbill } 107630Shenry if (lastjxxx->s_jxbump == 0){ /*wasn't bumped, so is short form*/ 1085825Srrh putins(opcode, ap, nact); 109595Sbill } else { 1105825Srrh if (opcode.Op_popcode != JBR){ 1115825Srrh /* 1125825Srrh * branch reverse conditional byte over 1135825Srrh * branch unconditional word 1145825Srrh */ 115630Shenry oxvalue = xp->e_xvalue; 116630Shenry xp->e_xvalue = lastjxxx->s_value; 1175825Srrh nopcode = opcode; 1185825Srrh nopcode.Op_popcode ^= 1; 1195825Srrh putins(nopcode, ap, nact); 120630Shenry xp->e_xvalue = oxvalue; 121595Sbill } 1225825Srrh nopcode.Op_eopcode = CORE; 1235825Srrh nopcode.Op_popcode = jxxxJUMP ? JMP : BRW; 1245825Srrh putins(nopcode, aplast, 1); 125595Sbill } 126595Sbill } 1275825Srrh } 128595Sbill 129595Sbill jalign(xp, sp) 130595Sbill register struct exp *xp; 131595Sbill register struct symtab *sp; 132595Sbill { 133595Sbill register int mask; 134680Shenry /* 135680Shenry * Problem with .align 136680Shenry * 137680Shenry * When the loader constructs an executable file from 138680Shenry * a number of objects, it effectively concatnates 139680Shenry * together all of the text segments from all objects, 140680Shenry * and then all of the data segments. 141680Shenry * 142680Shenry * If we do an align by a large value, we can align 143680Shenry * within the a.out this assembly produces, but 144680Shenry * after the loader concatnates, the alignment can't 145680Shenry * be guaranteed if the objects preceding this one 146680Shenry * in the load are also aligned to the same size. 147680Shenry * 148680Shenry * Currently, the loader guarantees full word alignment. 149680Shenry * So, ridiculous aligns are caught here and converted 150680Shenry * to a .align 2, if possible. 151680Shenry */ 1525825Srrh if ( ( (xp->e_xtype & XTYPE) != XABS) 153678Shenry || (xp->e_xvalue < 0) 154678Shenry || (xp->e_xvalue > 16) 155678Shenry ) { 156595Sbill yyerror("Illegal `align' argument"); 157595Sbill return; 158595Sbill } 159680Shenry if (xp->e_xvalue > 2){ 160680Shenry if (passno == 1){ 1615825Srrh yywarning(".align %d is NOT preserved by the loader", 1625825Srrh xp->e_xvalue); 1635825Srrh yywarning(".align %d converted to .align 2", 1645825Srrh xp->e_xvalue); 165680Shenry } 166680Shenry xp->e_xvalue = 2; 167678Shenry } 168595Sbill flushfield(NBPW/4); 169595Sbill if (passno == 1) { 170630Shenry sp->s_tag = JXALIGN; 171630Shenry sp->s_jxfear = (1 << xp->e_xvalue) - 1; 172630Shenry sp->s_type = dotp->e_xtype; 173630Shenry sp->s_index = dotp-usedot; 174595Sbill /* 175595Sbill * We guess that the align will take up at least one 176595Sbill * byte in the code output. We will correct for this 177595Sbill * initial high guess when we explode (bump) aligns 178595Sbill * when we fix the jxxxes. We must do this guess 179595Sbill * so that the symbol table is sorted correctly 180595Sbill * and labels declared to fall before the align 181595Sbill * really get their, instead of guessing zero size 182595Sbill * and have the label (incorrectly) fall after the jxxx. 183595Sbill * This is a quirk of our requirement that indices into 184595Sbill * the code stream point to the next byte following 185595Sbill * the logical entry in the symbol table 186595Sbill */ 187630Shenry dotp->e_xvalue += 1; 188630Shenry sp->s_value = dotp->e_xvalue; 189595Sbill njxxx++; 190595Sbill } else { 191630Shenry mask = (1 << xp->e_xvalue) - 1; 1925825Srrh while (dotp->e_xvalue & mask) 1935825Srrh Outb(0); 194595Sbill } 195595Sbill } 196595Sbill 197595Sbill /* 198595Sbill * Pass 1.5, resolve jxxx instructions and .align in .text 199595Sbill */ 200595Sbill jxxxfix() 201595Sbill { 202595Sbill register struct symtab *jumpfrom; 203595Sbill struct symtab **cojumpfrom, *ubjumpfrom; 204595Sbill register struct symtab *dest; 205595Sbill register struct symtab *intdest; /*intermediate dest*/ 206595Sbill register struct symtab **cointdest, *ubintdest; 207595Sbill 208595Sbill register struct symtab *tunnel; 209595Sbill int displ,nchange; 210595Sbill int badjxalign; /*if jump across an align*/ 211595Sbill int stillactives; /*if still active jxxxes*/ 212595Sbill int segno; /*current segment number*/ 213595Sbill int topono; /*which iteration in the topo sort*/ 214595Sbill register unsigned char tag; 215595Sbill /* 216595Sbill * consider each segment in turn... 217595Sbill */ 218595Sbill for (segno = 0; segno < NLOC + NLOC; segno++){ 219595Sbill badjxalign = 0; /*done on a per segment basis*/ 220595Sbill /* 221595Sbill * Do a lazy topological sort. 222595Sbill */ 223595Sbill for (topono = 1, nchange = 1; nchange != 0; topono++){ 2245825Srrh #ifdef lint 2255825Srrh topno = topno; 2265825Srrh #endif lint 227595Sbill #ifdef DEBUG 228595Sbill if (debug) 229595Sbill printf("\nSegment %d, topo iteration %d\n", 230595Sbill segno, topono); 231595Sbill #endif 232595Sbill nchange = 0; 233595Sbill stillactives = 0; 234595Sbill /* 235595Sbill * We keep track of one possible tunnel location. 236595Sbill * A tunnel will eventually be an unconditional 237595Sbill * branch to the same place that another jxxx 238595Sbill * will want to branch to. We will turn a 239595Sbill * branch conditional/unconditional (word) that would 240595Sbill * have to get bumped because its destination is too 241595Sbill * far away, into a branch conditional/unconditional 242595Sbill * byte to the tunnel branch conditional/unconditional. 243595Sbill * Of course, the tunnel must branch to the same place 244595Sbill * as we want to go. 245595Sbill */ 246595Sbill tunnel = 0; /*initially, no tunnel*/ 247595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){ 248630Shenry tag = jumpfrom->s_tag; 249595Sbill if (tag <= IGNOREBOUND) 250595Sbill continue; /*just an ordinary symbol*/ 251595Sbill if (tag == JXALIGN){ 252595Sbill tunnel = 0; /*avoid tunneling across a flex alocation*/ 253595Sbill continue; /*we take care of these later*/ 254595Sbill } 255636Shenry if ( jumpfrom->s_jxfear == jbrfsize /*unconditional*/ 256595Sbill || ( tag == JXINACTIVE /*inactive bumped*/ 257630Shenry && (jumpfrom->s_jxbump != 0) 258595Sbill ) 259595Sbill ) tunnel = jumpfrom; 260595Sbill if (tag != JXACTIVE) 261595Sbill continue; 262630Shenry dest = jumpfrom->s_dest; 263630Shenry if (jumpfrom->s_index != dest->s_index){ 264595Sbill yyerror("Intersegment jxxx"); 265595Sbill continue; 266595Sbill } 267630Shenry displ = dest->s_value - jumpfrom->s_value; 268595Sbill if (displ < MINBYTE || displ > MAXBYTE) { 269595Sbill /* 270595Sbill * This is an immediate lose! 271595Sbill * 272595Sbill * We first attempt to tunnel 273595Sbill * by finding an intervening jump that 274595Sbill * has the same destination. 275595Sbill * The tunnel is always the first preceeding 276595Sbill * jxxx instruction, so the displacement 277595Sbill * to the tunnel is less than zero, and 278595Sbill * its relative position will be unaffected 279595Sbill * by future jxxx expansions. 280636Shenry * 281636Shenry * No tunnels if doing jumps... 282595Sbill */ 283636Shenry if ( (!jxxxJUMP) 284636Shenry && (jumpfrom->s_jxfear > jbrfsize) 285595Sbill && (tunnel) 286630Shenry && (tunnel->s_dest == jumpfrom->s_dest) 287630Shenry && (tunnel->s_index == jumpfrom->s_index) 288630Shenry && (tunnel->s_value - jumpfrom->s_value >= 289636Shenry MINBYTE + jxxxfsize) 290595Sbill ) { 291595Sbill /* 292595Sbill * tunnelling is OK 293595Sbill */ 294630Shenry jumpfrom->s_dest = tunnel; 295595Sbill /* 296595Sbill * no bumping needed, this 297595Sbill * is now effectively inactive 298595Sbill * but must be remembered 299595Sbill */ 300630Shenry jumpfrom->s_tag = JXTUNNEL; 301595Sbill #ifdef DEBUG 302595Sbill if(debug) 303595Sbill printf("Tunnel from %s from line %d\n", 304*13512Srrh FETCHNAME(jumpfrom), 305*13512Srrh lineno); 306595Sbill #endif 307595Sbill continue; 308595Sbill } else { /*tunneling not possible*/ 309595Sbill /* 310595Sbill * since this will be turned 311595Sbill * into a bumped jump, we can 312595Sbill * use the unconditional jump 313595Sbill * as a tunnel 314595Sbill */ 315595Sbill tunnel = jumpfrom; 316630Shenry jumpfrom->s_tag = JXNOTYET; 317595Sbill ++nchange; 318595Sbill continue; 319595Sbill } 320595Sbill } /*end of immediate lose*/ 321595Sbill /* 322595Sbill * Do a forward search for an intervening jxxx 323595Sbill */ 324595Sbill if (displ >= 0) { 325595Sbill SEGITERATE(segno, cojumpfrom + 1,0,cointdest, 326595Sbill intdest, ubintdest, ++){ 327630Shenry if (intdest->s_value > dest->s_value) 328595Sbill break; /* beyond destination */ 329630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 330595Sbill continue; /*frozen solid*/ 331630Shenry if (intdest->s_tag == JXALIGN){ 332630Shenry jumpfrom->s_jxoveralign = 1; 333595Sbill badjxalign++; 334595Sbill } 335595Sbill /* 336595Sbill * we assume the worst case 337595Sbill * for unfrozen jxxxxes 338595Sbill */ 339630Shenry displ += intdest->s_jxfear; 340595Sbill } 341595Sbill if (displ <= MAXBYTE){ 342595Sbill /* 343595Sbill * the worst possible conditions 344595Sbill * can't hurt us, so forget about 345595Sbill * this jump 346595Sbill */ 347630Shenry jumpfrom->s_tag = JXINACTIVE; 348595Sbill } else { 349595Sbill stillactives++; 350595Sbill } 351595Sbill } else { 352595Sbill /* 353595Sbill * backward search for intervening jxxx 354595Sbill */ 355595Sbill SEGITERATE(segno, cojumpfrom - 1,1,cointdest, 356595Sbill intdest, ubintdest, --){ 357630Shenry if (intdest->s_value <= dest->s_value) 358595Sbill break; /* beyond destination */ 359630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 360595Sbill continue; /*frozen solid*/ 361630Shenry if (intdest->s_tag == JXALIGN){ 362630Shenry jumpfrom->s_jxoveralign = 1; 363595Sbill badjxalign++; 364595Sbill } 365630Shenry displ -= intdest->s_jxfear; 366595Sbill } 367595Sbill if (displ >= MINBYTE) { 368630Shenry jumpfrom->s_tag = JXINACTIVE; 369595Sbill } else { 370595Sbill stillactives++; 371595Sbill } 372595Sbill } /*end of backwards search*/ 373595Sbill } /*end of iterating through all symbols in this seg*/ 374595Sbill 375595Sbill if (nchange == 0) { 376595Sbill /* 377595Sbill * Now, if there are still active jxxx entries, 378595Sbill * we are partially deadlocked. We can leave 379595Sbill * these jxxx entries in their assumed short jump 380595Sbill * form, as all initial displacement calcualtions 381595Sbill * are hanging on unresolved jxxx instructions 382595Sbill * that might explode into a long form, causing 383595Sbill * other jxxxes jumping across the first set of 384595Sbill * jxxxes to explode, etc. 385595Sbill * However, if a jxxx jumps across a .align, 386595Sbill * we assume the worst for the deadlock cycle, 387595Sbill * and resolve all of them towards the long 388595Sbill * jump. 389595Sbill * Currently, the C compiler does not produce 390595Sbill * jumps across aligns, as aligns are only used 391595Sbill * in data segments, or in text segments to align 392595Sbill * functions. 393595Sbill */ 394595Sbill if (stillactives){ 395595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 396595Sbill ubjumpfrom, ++){ 397630Shenry if (jumpfrom->s_tag == JXACTIVE){ 398630Shenry jumpfrom->s_tag = 399595Sbill badjxalign?JXNOTYET:JXINACTIVE; 400595Sbill } 401595Sbill } 402595Sbill if (badjxalign){ 403595Sbill jxxxbump(segno, (struct symtab **)0); 404595Sbill } 405595Sbill } 406595Sbill /* 407595Sbill * Handle all of the .align s 408595Sbill */ 409595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 410595Sbill ubjumpfrom, ++){ 411630Shenry if (jumpfrom->s_tag == JXALIGN){ 412595Sbill /* 413595Sbill * Predict the true displacement 414595Sbill * needed, irregardless of the 415595Sbill * fact that we guessed 1 416595Sbill */ 417630Shenry displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear; 418595Sbill if (displ == 0){ /*no virtual displacement*/ 419630Shenry jumpfrom->s_jxfear = -1; 420595Sbill } else { 421630Shenry jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ; 422595Sbill /* 423630Shenry * assert jumpfrom->s_jxfear > 0 424595Sbill */ 425630Shenry if (jumpfrom->s_jxfear == 1){ 426595Sbill /*our prediction was correct*/ 427595Sbill continue; 428595Sbill } 429595Sbill /* 430630Shenry * assert jumpfrom->s_jxfear > 1 431595Sbill */ 432630Shenry jumpfrom->s_jxfear -= 1; /*correct guess*/ 433595Sbill } 434595Sbill /* 435630Shenry * assert jumpfrom->s_jxfear = -1, +1...2**n-1 436595Sbill */ 437630Shenry jumpfrom->s_tag = JXNOTYET; /*signal*/ 438595Sbill jxxxbump(segno, cojumpfrom); 439630Shenry jumpfrom->s_tag = JXINACTIVE; 440595Sbill /* 441595Sbill * Assert jxfrom->jxvalue indexes the first 442595Sbill * code byte after the added bytes, and 443595Sbill * has n low order zeroes. 444595Sbill */ 445595Sbill } 446595Sbill } /*end of walking through each segment*/ 447595Sbill } /*end of no changes */ 448595Sbill else { /*changes, and still have to try another pass*/ 449595Sbill jxxxbump(segno, (struct symtab **)0); 450595Sbill } 451595Sbill } /*end of doing the topologic sort*/ 452595Sbill } /*end of iterating through all segments*/ 453595Sbill } /*end of jxxxfix*/ 454595Sbill 455595Sbill /* 456595Sbill * Go through the symbols in a given segment number, 457595Sbill * and see which entries are jxxx entries that have 458595Sbill * been logically "exploded" (expanded), but for which 459595Sbill * the value of textually following symbols has not been 460595Sbill * increased 461595Sbill */ 462595Sbill 463595Sbill jxxxbump(segno, starthint) 464595Sbill int segno; 465595Sbill struct symtab **starthint; 466595Sbill { 467595Sbill register struct symtab **cosp, *sp; 468595Sbill register struct symtab *ub; 469595Sbill register int cum_bump; 470595Sbill register unsigned char tag; 471595Sbill 472595Sbill cum_bump = 0; 473595Sbill SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){ 474630Shenry tag = sp->s_tag; 475595Sbill if (tag == JXNOTYET){ 476595Sbill #ifdef DEBUG 477595Sbill if (debug){ 478630Shenry if (sp->s_dest != 0) 479595Sbill printf("Explode jump to %s on line %d\n", 480*13512Srrh FETCHNAME(sp->s_dest), lineno); 481595Sbill else 482595Sbill printf("Explode an align!\n"); 483595Sbill } 484595Sbill #endif 485630Shenry sp->s_tag = JXINACTIVE; 486630Shenry sp->s_jxbump = 1; 487630Shenry cum_bump += sp->s_jxfear; 488595Sbill } 489595Sbill /* 490595Sbill * Only bump labels and jxxxes. Ignored entries can 491595Sbill * be incremented, as they are thrown away later on. 492595Sbill * Stabds are given their final value in the second 493595Sbill * pass. 494595Sbill */ 495595Sbill if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/ 496630Shenry sp->s_value += cum_bump; 497595Sbill } 498630Shenry usedot[segno].e_xvalue += cum_bump; 499595Sbill } 500