1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char sccsid[] = "@(#)asjxxx.c 4.5 08/20/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 /* 120 * Problem with .align 121 * 122 * When the loader constructs an executable file from 123 * a number of objects, it effectively concatnates 124 * together all of the text segments from all objects, 125 * and then all of the data segments. 126 * 127 * If we do an align by a large value, we can align 128 * within the a.out this assembly produces, but 129 * after the loader concatnates, the alignment can't 130 * be guaranteed if the objects preceding this one 131 * in the load are also aligned to the same size. 132 * 133 * Currently, the loader guarantees full word alignment. 134 * So, ridiculous aligns are caught here and converted 135 * to a .align 2, if possible. 136 */ 137 if ( (xp->e_xtype != XABS) 138 || (xp->e_xvalue < 0) 139 || (xp->e_xvalue > 16) 140 ) { 141 yyerror("Illegal `align' argument"); 142 return; 143 } 144 if (xp->e_xvalue > 2){ 145 if (passno == 1){ 146 yywarning(".align %d in any segment is NOT preserved by the loader", 147 xp->e_xvalue); 148 yywarning(".align %d converted to .align 2", 149 xp->e_xvalue); 150 } 151 xp->e_xvalue = 2; 152 } 153 flushfield(NBPW/4); 154 if (passno == 1) { 155 sp->s_tag = JXALIGN; 156 sp->s_jxfear = (1 << xp->e_xvalue) - 1; 157 sp->s_type = dotp->e_xtype; 158 sp->s_index = dotp-usedot; 159 /* 160 * We guess that the align will take up at least one 161 * byte in the code output. We will correct for this 162 * initial high guess when we explode (bump) aligns 163 * when we fix the jxxxes. We must do this guess 164 * so that the symbol table is sorted correctly 165 * and labels declared to fall before the align 166 * really get their, instead of guessing zero size 167 * and have the label (incorrectly) fall after the jxxx. 168 * This is a quirk of our requirement that indices into 169 * the code stream point to the next byte following 170 * the logical entry in the symbol table 171 */ 172 dotp->e_xvalue += 1; 173 sp->s_value = dotp->e_xvalue; 174 njxxx++; 175 } else { 176 mask = (1 << xp->e_xvalue) - 1; 177 while (dotp->e_xvalue & mask){ 178 #ifdef UNIX 179 outb(0); 180 #endif UNIX 181 #ifdef VMS 182 *vms_obj_ptr++ = -1; 183 *vms_obj_ptr++ = 0; 184 dotp->e_xvalue += 1; 185 #endif VMS 186 } 187 } 188 } 189 190 /* 191 * Pass 1.5, resolve jxxx instructions and .align in .text 192 */ 193 jxxxfix() 194 { 195 register struct symtab *jumpfrom; 196 struct symtab **cojumpfrom, *ubjumpfrom; 197 register struct symtab *dest; 198 register struct symtab *intdest; /*intermediate dest*/ 199 register struct symtab **cointdest, *ubintdest; 200 201 register struct symtab *tunnel; 202 int displ,nchange; 203 int badjxalign; /*if jump across an align*/ 204 int stillactives; /*if still active jxxxes*/ 205 int segno; /*current segment number*/ 206 int topono; /*which iteration in the topo sort*/ 207 register unsigned char tag; 208 /* 209 * consider each segment in turn... 210 */ 211 for (segno = 0; segno < NLOC + NLOC; segno++){ 212 badjxalign = 0; /*done on a per segment basis*/ 213 /* 214 * Do a lazy topological sort. 215 */ 216 for (topono = 1, nchange = 1; nchange != 0; topono++){ 217 #ifdef DEBUG 218 if (debug) 219 printf("\nSegment %d, topo iteration %d\n", 220 segno, topono); 221 #endif 222 nchange = 0; 223 stillactives = 0; 224 /* 225 * We keep track of one possible tunnel location. 226 * A tunnel will eventually be an unconditional 227 * branch to the same place that another jxxx 228 * will want to branch to. We will turn a 229 * branch conditional/unconditional (word) that would 230 * have to get bumped because its destination is too 231 * far away, into a branch conditional/unconditional 232 * byte to the tunnel branch conditional/unconditional. 233 * Of course, the tunnel must branch to the same place 234 * as we want to go. 235 */ 236 tunnel = 0; /*initially, no tunnel*/ 237 SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){ 238 tag = jumpfrom->s_tag; 239 if (tag <= IGNOREBOUND) 240 continue; /*just an ordinary symbol*/ 241 if (tag == JXALIGN){ 242 tunnel = 0; /*avoid tunneling across a flex alocation*/ 243 continue; /*we take care of these later*/ 244 } 245 if ( jumpfrom->s_jxfear == jbrfsize /*unconditional*/ 246 || ( tag == JXINACTIVE /*inactive bumped*/ 247 && (jumpfrom->s_jxbump != 0) 248 ) 249 ) tunnel = jumpfrom; 250 if (tag != JXACTIVE) 251 continue; 252 dest = jumpfrom->s_dest; 253 if (jumpfrom->s_index != dest->s_index){ 254 yyerror("Intersegment jxxx"); 255 continue; 256 } 257 displ = dest->s_value - jumpfrom->s_value; 258 if (displ < MINBYTE || displ > MAXBYTE) { 259 /* 260 * This is an immediate lose! 261 * 262 * We first attempt to tunnel 263 * by finding an intervening jump that 264 * has the same destination. 265 * The tunnel is always the first preceeding 266 * jxxx instruction, so the displacement 267 * to the tunnel is less than zero, and 268 * its relative position will be unaffected 269 * by future jxxx expansions. 270 * 271 * No tunnels if doing jumps... 272 */ 273 if ( (!jxxxJUMP) 274 && (jumpfrom->s_jxfear > jbrfsize) 275 && (tunnel) 276 && (tunnel->s_dest == jumpfrom->s_dest) 277 && (tunnel->s_index == jumpfrom->s_index) 278 && (tunnel->s_value - jumpfrom->s_value >= 279 MINBYTE + jxxxfsize) 280 ) { 281 /* 282 * tunnelling is OK 283 */ 284 jumpfrom->s_dest = tunnel; 285 /* 286 * no bumping needed, this 287 * is now effectively inactive 288 * but must be remembered 289 */ 290 jumpfrom->s_tag = JXTUNNEL; 291 #ifdef DEBUG 292 if(debug) 293 printf("Tunnel from %s from line %d\n", 294 jumpfrom->s_name, lineno); 295 #endif 296 continue; 297 } else { /*tunneling not possible*/ 298 /* 299 * since this will be turned 300 * into a bumped jump, we can 301 * use the unconditional jump 302 * as a tunnel 303 */ 304 tunnel = jumpfrom; 305 jumpfrom->s_tag = JXNOTYET; 306 ++nchange; 307 continue; 308 } 309 } /*end of immediate lose*/ 310 /* 311 * Do a forward search for an intervening jxxx 312 */ 313 if (displ >= 0) { 314 SEGITERATE(segno, cojumpfrom + 1,0,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 /* 325 * we assume the worst case 326 * for unfrozen jxxxxes 327 */ 328 displ += intdest->s_jxfear; 329 } 330 if (displ <= MAXBYTE){ 331 /* 332 * the worst possible conditions 333 * can't hurt us, so forget about 334 * this jump 335 */ 336 jumpfrom->s_tag = JXINACTIVE; 337 } else { 338 stillactives++; 339 } 340 } else { 341 /* 342 * backward search for intervening jxxx 343 */ 344 SEGITERATE(segno, cojumpfrom - 1,1,cointdest, 345 intdest, ubintdest, --){ 346 if (intdest->s_value <= dest->s_value) 347 break; /* beyond destination */ 348 if (intdest->s_tag <= JXQUESTIONABLE) 349 continue; /*frozen solid*/ 350 if (intdest->s_tag == JXALIGN){ 351 jumpfrom->s_jxoveralign = 1; 352 badjxalign++; 353 } 354 displ -= intdest->s_jxfear; 355 } 356 if (displ >= MINBYTE) { 357 jumpfrom->s_tag = JXINACTIVE; 358 } else { 359 stillactives++; 360 } 361 } /*end of backwards search*/ 362 } /*end of iterating through all symbols in this seg*/ 363 364 if (nchange == 0) { 365 /* 366 * Now, if there are still active jxxx entries, 367 * we are partially deadlocked. We can leave 368 * these jxxx entries in their assumed short jump 369 * form, as all initial displacement calcualtions 370 * are hanging on unresolved jxxx instructions 371 * that might explode into a long form, causing 372 * other jxxxes jumping across the first set of 373 * jxxxes to explode, etc. 374 * However, if a jxxx jumps across a .align, 375 * we assume the worst for the deadlock cycle, 376 * and resolve all of them towards the long 377 * jump. 378 * Currently, the C compiler does not produce 379 * jumps across aligns, as aligns are only used 380 * in data segments, or in text segments to align 381 * functions. 382 */ 383 if (stillactives){ 384 SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 385 ubjumpfrom, ++){ 386 if (jumpfrom->s_tag == JXACTIVE){ 387 jumpfrom->s_tag = 388 badjxalign?JXNOTYET:JXINACTIVE; 389 } 390 } 391 if (badjxalign){ 392 jxxxbump(segno, (struct symtab **)0); 393 } 394 } 395 /* 396 * Handle all of the .align s 397 */ 398 SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 399 ubjumpfrom, ++){ 400 if (jumpfrom->s_tag == JXALIGN){ 401 /* 402 * Predict the true displacement 403 * needed, irregardless of the 404 * fact that we guessed 1 405 */ 406 displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear; 407 if (displ == 0){ /*no virtual displacement*/ 408 jumpfrom->s_jxfear = -1; 409 } else { 410 jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ; 411 /* 412 * assert jumpfrom->s_jxfear > 0 413 */ 414 if (jumpfrom->s_jxfear == 1){ 415 /*our prediction was correct*/ 416 continue; 417 } 418 /* 419 * assert jumpfrom->s_jxfear > 1 420 */ 421 jumpfrom->s_jxfear -= 1; /*correct guess*/ 422 } 423 /* 424 * assert jumpfrom->s_jxfear = -1, +1...2**n-1 425 */ 426 jumpfrom->s_tag = JXNOTYET; /*signal*/ 427 jxxxbump(segno, cojumpfrom); 428 jumpfrom->s_tag = JXINACTIVE; 429 /* 430 * Assert jxfrom->jxvalue indexes the first 431 * code byte after the added bytes, and 432 * has n low order zeroes. 433 */ 434 } 435 } /*end of walking through each segment*/ 436 } /*end of no changes */ 437 else { /*changes, and still have to try another pass*/ 438 jxxxbump(segno, (struct symtab **)0); 439 } 440 } /*end of doing the topologic sort*/ 441 } /*end of iterating through all segments*/ 442 } /*end of jxxxfix*/ 443 444 /* 445 * Go through the symbols in a given segment number, 446 * and see which entries are jxxx entries that have 447 * been logically "exploded" (expanded), but for which 448 * the value of textually following symbols has not been 449 * increased 450 */ 451 452 jxxxbump(segno, starthint) 453 int segno; 454 struct symtab **starthint; 455 { 456 register struct symtab **cosp, *sp; 457 register struct symtab *ub; 458 register int cum_bump; 459 register unsigned char tag; 460 461 cum_bump = 0; 462 SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){ 463 tag = sp->s_tag; 464 if (tag == JXNOTYET){ 465 #ifdef DEBUG 466 if (debug){ 467 if (sp->s_dest != 0) 468 printf("Explode jump to %s on line %d\n", 469 sp->s_dest->s_name, lineno); 470 else 471 printf("Explode an align!\n"); 472 } 473 #endif 474 sp->s_tag = JXINACTIVE; 475 sp->s_jxbump = 1; 476 cum_bump += sp->s_jxfear; 477 } 478 /* 479 * Only bump labels and jxxxes. Ignored entries can 480 * be incremented, as they are thrown away later on. 481 * Stabds are given their final value in the second 482 * pass. 483 */ 484 if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/ 485 sp->s_value += cum_bump; 486 } 487 usedot[segno].e_xvalue += cum_bump; 488 } 489