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