1 /* 2 * Copyright (c) 1982 Regents of the University of California 3 */ 4 #ifndef lint 5 static char sccsid[] = "@(#)asjxxx.c 4.7 06/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 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 FETCHNAME(jumpfrom), 305 lineno); 306 #endif 307 continue; 308 } else { /*tunneling not possible*/ 309 /* 310 * since this will be turned 311 * into a bumped jump, we can 312 * use the unconditional jump 313 * as a tunnel 314 */ 315 tunnel = jumpfrom; 316 jumpfrom->s_tag = JXNOTYET; 317 ++nchange; 318 continue; 319 } 320 } /*end of immediate lose*/ 321 /* 322 * Do a forward search for an intervening jxxx 323 */ 324 if (displ >= 0) { 325 SEGITERATE(segno, cojumpfrom + 1,0,cointdest, 326 intdest, ubintdest, ++){ 327 if (intdest->s_value > dest->s_value) 328 break; /* beyond destination */ 329 if (intdest->s_tag <= JXQUESTIONABLE) 330 continue; /*frozen solid*/ 331 if (intdest->s_tag == JXALIGN){ 332 jumpfrom->s_jxoveralign = 1; 333 badjxalign++; 334 } 335 /* 336 * we assume the worst case 337 * for unfrozen jxxxxes 338 */ 339 displ += intdest->s_jxfear; 340 } 341 if (displ <= MAXBYTE){ 342 /* 343 * the worst possible conditions 344 * can't hurt us, so forget about 345 * this jump 346 */ 347 jumpfrom->s_tag = JXINACTIVE; 348 } else { 349 stillactives++; 350 } 351 } else { 352 /* 353 * backward search for intervening jxxx 354 */ 355 SEGITERATE(segno, cojumpfrom - 1,1,cointdest, 356 intdest, ubintdest, --){ 357 if (intdest->s_value <= dest->s_value) 358 break; /* beyond destination */ 359 if (intdest->s_tag <= JXQUESTIONABLE) 360 continue; /*frozen solid*/ 361 if (intdest->s_tag == JXALIGN){ 362 jumpfrom->s_jxoveralign = 1; 363 badjxalign++; 364 } 365 displ -= intdest->s_jxfear; 366 } 367 if (displ >= MINBYTE) { 368 jumpfrom->s_tag = JXINACTIVE; 369 } else { 370 stillactives++; 371 } 372 } /*end of backwards search*/ 373 } /*end of iterating through all symbols in this seg*/ 374 375 if (nchange == 0) { 376 /* 377 * Now, if there are still active jxxx entries, 378 * we are partially deadlocked. We can leave 379 * these jxxx entries in their assumed short jump 380 * form, as all initial displacement calcualtions 381 * are hanging on unresolved jxxx instructions 382 * that might explode into a long form, causing 383 * other jxxxes jumping across the first set of 384 * jxxxes to explode, etc. 385 * However, if a jxxx jumps across a .align, 386 * we assume the worst for the deadlock cycle, 387 * and resolve all of them towards the long 388 * jump. 389 * Currently, the C compiler does not produce 390 * jumps across aligns, as aligns are only used 391 * in data segments, or in text segments to align 392 * functions. 393 */ 394 if (stillactives){ 395 SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 396 ubjumpfrom, ++){ 397 if (jumpfrom->s_tag == JXACTIVE){ 398 jumpfrom->s_tag = 399 badjxalign?JXNOTYET:JXINACTIVE; 400 } 401 } 402 if (badjxalign){ 403 jxxxbump(segno, (struct symtab **)0); 404 } 405 } 406 /* 407 * Handle all of the .align s 408 */ 409 SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 410 ubjumpfrom, ++){ 411 if (jumpfrom->s_tag == JXALIGN){ 412 /* 413 * Predict the true displacement 414 * needed, irregardless of the 415 * fact that we guessed 1 416 */ 417 displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear; 418 if (displ == 0){ /*no virtual displacement*/ 419 jumpfrom->s_jxfear = -1; 420 } else { 421 jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ; 422 /* 423 * assert jumpfrom->s_jxfear > 0 424 */ 425 if (jumpfrom->s_jxfear == 1){ 426 /*our prediction was correct*/ 427 continue; 428 } 429 /* 430 * assert jumpfrom->s_jxfear > 1 431 */ 432 jumpfrom->s_jxfear -= 1; /*correct guess*/ 433 } 434 /* 435 * assert jumpfrom->s_jxfear = -1, +1...2**n-1 436 */ 437 jumpfrom->s_tag = JXNOTYET; /*signal*/ 438 jxxxbump(segno, cojumpfrom); 439 jumpfrom->s_tag = JXINACTIVE; 440 /* 441 * Assert jxfrom->jxvalue indexes the first 442 * code byte after the added bytes, and 443 * has n low order zeroes. 444 */ 445 } 446 } /*end of walking through each segment*/ 447 } /*end of no changes */ 448 else { /*changes, and still have to try another pass*/ 449 jxxxbump(segno, (struct symtab **)0); 450 } 451 } /*end of doing the topologic sort*/ 452 } /*end of iterating through all segments*/ 453 } /*end of jxxxfix*/ 454 455 /* 456 * Go through the symbols in a given segment number, 457 * and see which entries are jxxx entries that have 458 * been logically "exploded" (expanded), but for which 459 * the value of textually following symbols has not been 460 * increased 461 */ 462 463 jxxxbump(segno, starthint) 464 int segno; 465 struct symtab **starthint; 466 { 467 register struct symtab **cosp, *sp; 468 register struct symtab *ub; 469 register int cum_bump; 470 register unsigned char tag; 471 472 cum_bump = 0; 473 SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){ 474 tag = sp->s_tag; 475 if (tag == JXNOTYET){ 476 #ifdef DEBUG 477 if (debug){ 478 if (sp->s_dest != 0) 479 printf("Explode jump to %s on line %d\n", 480 FETCHNAME(sp->s_dest), lineno); 481 else 482 printf("Explode an align!\n"); 483 } 484 #endif 485 sp->s_tag = JXINACTIVE; 486 sp->s_jxbump = 1; 487 cum_bump += sp->s_jxfear; 488 } 489 /* 490 * Only bump labels and jxxxes. Ignored entries can 491 * be incremented, as they are thrown away later on. 492 * Stabds are given their final value in the second 493 * pass. 494 */ 495 if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/ 496 sp->s_value += cum_bump; 497 } 498 usedot[segno].e_xvalue += cum_bump; 499 } 500