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