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