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