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