15825Srrh /* 2*19823Sdist * Copyright (c) 1982 Regents of the University of California. 3*19823Sdist * All rights reserved. The Berkeley software License Agreement 4*19823Sdist * specifies the terms and conditions for redistribution. 55825Srrh */ 6*19823Sdist 75825Srrh #ifndef lint 8*19823Sdist static char sccsid[] = "@(#)asjxxx.c 5.1 (Berkeley) 04/30/85"; 95825Srrh #endif not lint 105825Srrh 11595Sbill #include <stdio.h> 12595Sbill #include "as.h" 13595Sbill #include "assyms.h" 14595Sbill 15636Shenry #define JBR 0x11 16636Shenry #define BRW 0x31 17636Shenry #define JMP 0x17 18595Sbill 19595Sbill /* 20595Sbill * The number of bytes to add if the jxxx must be "exploded" 21595Sbill * into the long form 22595Sbill */ 23636Shenry #define JBRDELTA 1 /* brb <byte> ==> brw <byte> <byte> */ 24636Shenry #define JXXXDELTA 3 /* brb <byte> ==> brb <byte> brw <byte> <byte> */ 25636Shenry #define JBRJDELTA d124 /* brb <byte> ==> jmp L^(pc) <byte>*d124 */ 26636Shenry #define JXXXJDELTA d124+2 /* brb <byte> ==> brb <byte> jmp L^(pc) <byte>*d124 */ 27595Sbill 28636Shenry int jbrfsize = JBRDELTA; 29636Shenry int jxxxfsize = JXXXDELTA; 30636Shenry 31595Sbill /* 32595Sbill * These variables are filled by asscan.c with the 33595Sbill * last name encountered (a pointer buried in the intermediate file), 34595Sbill * and the last jxxx symbol table entry encountered. 35595Sbill */ 36595Sbill struct symtab *lastnam; 37595Sbill struct symtab *lastjxxx; 38595Sbill 39636Shenry initijxxx() 40636Shenry { 41636Shenry jbrfsize = jxxxJUMP ? JBRJDELTA : JBRDELTA; 42636Shenry jxxxfsize = jxxxJUMP ? JXXXJDELTA : JXXXDELTA; 43636Shenry /* 44636Shenry * Note: ifjxxxJUMP is set, then we do NOT do any tunnelling; 45636Shenry * this was too complicated to figure out, and in the first 46636Shenry * version of the assembler, tunnelling proved to be the hardest 47636Shenry * to get to work! 48636Shenry */ 49636Shenry } 50595Sbill /* 51595Sbill * Handle jxxx instructions 52595Sbill */ 535825Srrh ijxout(opcode, ap, nact) 545825Srrh struct Opcode opcode; 555825Srrh struct arg *ap; 565825Srrh int nact; 57595Sbill { 58595Sbill if (passno == 1){ 59595Sbill /* 60595Sbill * READ THIS BEFORE LOOKING AT jxxxfix() 61595Sbill * 62595Sbill * Record the jxxx in a special symbol table entry 63595Sbill */ 64595Sbill register struct symtab *jumpfrom; 65595Sbill 66595Sbill /* 67595Sbill * We assume the MINIMAL length 68595Sbill */ 695825Srrh putins(opcode, ap, nact); 70595Sbill jumpfrom = lastjxxx; 71630Shenry jumpfrom->s_tag = JXACTIVE; 72630Shenry jumpfrom->s_jxbump = 0; 735825Srrh if (opcode.Op_popcode == JBR) 74636Shenry jumpfrom->s_jxfear = jbrfsize; 75595Sbill else 76636Shenry jumpfrom->s_jxfear = jxxxfsize; 77595Sbill if (lastnam == 0) 78595Sbill yyerror("jxxx destination not a label"); 79630Shenry jumpfrom->s_dest = lastnam; 80630Shenry jumpfrom->s_type = dotp->e_xtype; /*only TEXT or DATA*/ 81630Shenry jumpfrom->s_index = dotp-usedot; 8215234Sralph #ifdef DEBUG 8315234Sralph jumpfrom->s_name = ITABFETCH(opcode)->i_name; 8415234Sralph jumpfrom->s_jxline = lineno; 8515234Sralph #endif 86595Sbill /* 87595Sbill * value ALWAYS (ALWAYS!!!) indexes the next instruction 8815234Sralph * after the jump, even if the jump must be exploded 89595Sbill * (bumped) 90595Sbill */ 91630Shenry jumpfrom->s_value = dotp->e_xvalue; 92595Sbill njxxx++; 93595Sbill } else {/* pass2, resolve */ 94595Sbill /* 95595Sbill * READ THIS AFTER LOOKING AT jxxxfix() 96595Sbill */ 975825Srrh reg long oxvalue; 985825Srrh reg struct exp *xp; 995825Srrh reg struct symtab *tunnel; 1005825Srrh reg struct arg *aplast; 1015825Srrh struct Opcode nopcode; 102595Sbill 103595Sbill aplast = ap + nact - 1; 104630Shenry xp = aplast->a_xp; 105630Shenry if (lastjxxx->s_tag == JXTUNNEL){ 106630Shenry lastjxxx->s_tag = JXINACTIVE; 107630Shenry tunnel = lastjxxx->s_dest; 108630Shenry xp->e_xvalue = tunnel->s_value /*index of instruction following*/ 109595Sbill - 3 /* size of brw + word*/ 110636Shenry + ( ( (tunnel->s_jxfear == jbrfsize) && 111630Shenry (tunnel->s_jxbump == 0))?1:0); 112595Sbill /*non bumped branch byteis only 2 back*/ 113595Sbill } 114630Shenry if (lastjxxx->s_jxbump == 0){ /*wasn't bumped, so is short form*/ 1155825Srrh putins(opcode, ap, nact); 116595Sbill } else { 1175825Srrh if (opcode.Op_popcode != JBR){ 1185825Srrh /* 1195825Srrh * branch reverse conditional byte over 1205825Srrh * branch unconditional word 1215825Srrh */ 122630Shenry oxvalue = xp->e_xvalue; 123630Shenry xp->e_xvalue = lastjxxx->s_value; 1245825Srrh nopcode = opcode; 1255825Srrh nopcode.Op_popcode ^= 1; 1265825Srrh putins(nopcode, ap, nact); 127630Shenry xp->e_xvalue = oxvalue; 128595Sbill } 1295825Srrh nopcode.Op_eopcode = CORE; 1305825Srrh nopcode.Op_popcode = jxxxJUMP ? JMP : BRW; 1315825Srrh putins(nopcode, aplast, 1); 132595Sbill } 133595Sbill } 1345825Srrh } 135595Sbill 136595Sbill jalign(xp, sp) 137595Sbill register struct exp *xp; 138595Sbill register struct symtab *sp; 139595Sbill { 140595Sbill register int mask; 14115234Sralph #ifdef DEBUG 14215234Sralph static struct strdesc noname; 14315234Sralph #endif 144680Shenry /* 145680Shenry * Problem with .align 146680Shenry * 147680Shenry * When the loader constructs an executable file from 148680Shenry * a number of objects, it effectively concatnates 149680Shenry * together all of the text segments from all objects, 150680Shenry * and then all of the data segments. 151680Shenry * 152680Shenry * If we do an align by a large value, we can align 153680Shenry * within the a.out this assembly produces, but 154680Shenry * after the loader concatnates, the alignment can't 155680Shenry * be guaranteed if the objects preceding this one 156680Shenry * in the load are also aligned to the same size. 157680Shenry * 158680Shenry * Currently, the loader guarantees full word alignment. 159680Shenry * So, ridiculous aligns are caught here and converted 16015559Srrh * to a .align (maxalign), if possible, where maxalign 16115559Srrh * is set in the command line, and defaults to 2. 162680Shenry */ 1635825Srrh if ( ( (xp->e_xtype & XTYPE) != XABS) 164678Shenry || (xp->e_xvalue < 0) 165678Shenry || (xp->e_xvalue > 16) 166678Shenry ) { 167595Sbill yyerror("Illegal `align' argument"); 168595Sbill return; 169595Sbill } 17015559Srrh if (xp->e_xvalue > maxalign){ 171680Shenry if (passno == 1){ 1725825Srrh yywarning(".align %d is NOT preserved by the loader", 1735825Srrh xp->e_xvalue); 17415559Srrh yywarning(".align %d converted to .align %d", 17515559Srrh xp->e_xvalue, maxalign); 176680Shenry } 17715559Srrh xp->e_xvalue = maxalign; 178678Shenry } 179595Sbill flushfield(NBPW/4); 180595Sbill if (passno == 1) { 181630Shenry sp->s_tag = JXALIGN; 182630Shenry sp->s_jxfear = (1 << xp->e_xvalue) - 1; 183630Shenry sp->s_type = dotp->e_xtype; 184630Shenry sp->s_index = dotp-usedot; 18515234Sralph #ifdef DEBUG 18615234Sralph sp->s_name = (char *)&noname; 18715234Sralph sp->s_jxline = lineno; 18815234Sralph #endif 189595Sbill /* 190595Sbill * We guess that the align will take up at least one 191595Sbill * byte in the code output. We will correct for this 192595Sbill * initial high guess when we explode (bump) aligns 193595Sbill * when we fix the jxxxes. We must do this guess 194595Sbill * so that the symbol table is sorted correctly 195595Sbill * and labels declared to fall before the align 196595Sbill * really get their, instead of guessing zero size 197595Sbill * and have the label (incorrectly) fall after the jxxx. 198595Sbill * This is a quirk of our requirement that indices into 199595Sbill * the code stream point to the next byte following 200595Sbill * the logical entry in the symbol table 201595Sbill */ 202630Shenry dotp->e_xvalue += 1; 203630Shenry sp->s_value = dotp->e_xvalue; 204595Sbill njxxx++; 205595Sbill } else { 206630Shenry mask = (1 << xp->e_xvalue) - 1; 2075825Srrh while (dotp->e_xvalue & mask) 2085825Srrh Outb(0); 209595Sbill } 210595Sbill } 211595Sbill 212595Sbill /* 213595Sbill * Pass 1.5, resolve jxxx instructions and .align in .text 214595Sbill */ 215595Sbill jxxxfix() 216595Sbill { 217595Sbill register struct symtab *jumpfrom; 218595Sbill struct symtab **cojumpfrom, *ubjumpfrom; 219595Sbill register struct symtab *dest; 220595Sbill register struct symtab *intdest; /*intermediate dest*/ 221595Sbill register struct symtab **cointdest, *ubintdest; 222595Sbill 223595Sbill register struct symtab *tunnel; 224595Sbill int displ,nchange; 225595Sbill int badjxalign; /*if jump across an align*/ 226595Sbill int stillactives; /*if still active jxxxes*/ 227595Sbill int segno; /*current segment number*/ 228595Sbill int topono; /*which iteration in the topo sort*/ 229595Sbill register unsigned char tag; 230595Sbill /* 231595Sbill * consider each segment in turn... 232595Sbill */ 233595Sbill for (segno = 0; segno < NLOC + NLOC; segno++){ 234595Sbill badjxalign = 0; /*done on a per segment basis*/ 235595Sbill /* 236595Sbill * Do a lazy topological sort. 237595Sbill */ 238595Sbill for (topono = 1, nchange = 1; nchange != 0; topono++){ 2395825Srrh #ifdef lint 2405825Srrh topno = topno; 2415825Srrh #endif lint 242595Sbill #ifdef DEBUG 243595Sbill if (debug) 244595Sbill printf("\nSegment %d, topo iteration %d\n", 245595Sbill segno, topono); 246595Sbill #endif 247595Sbill nchange = 0; 248595Sbill stillactives = 0; 249595Sbill /* 250595Sbill * We keep track of one possible tunnel location. 251595Sbill * A tunnel will eventually be an unconditional 252595Sbill * branch to the same place that another jxxx 253595Sbill * will want to branch to. We will turn a 254595Sbill * branch conditional/unconditional (word) that would 255595Sbill * have to get bumped because its destination is too 256595Sbill * far away, into a branch conditional/unconditional 257595Sbill * byte to the tunnel branch conditional/unconditional. 258595Sbill * Of course, the tunnel must branch to the same place 259595Sbill * as we want to go. 260595Sbill */ 261595Sbill tunnel = 0; /*initially, no tunnel*/ 262595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){ 263630Shenry tag = jumpfrom->s_tag; 264595Sbill if (tag <= IGNOREBOUND) 265595Sbill continue; /*just an ordinary symbol*/ 266595Sbill if (tag == JXALIGN){ 267595Sbill tunnel = 0; /*avoid tunneling across a flex alocation*/ 268595Sbill continue; /*we take care of these later*/ 269595Sbill } 270636Shenry if ( jumpfrom->s_jxfear == jbrfsize /*unconditional*/ 271595Sbill || ( tag == JXINACTIVE /*inactive bumped*/ 272630Shenry && (jumpfrom->s_jxbump != 0) 273595Sbill ) 274595Sbill ) tunnel = jumpfrom; 275595Sbill if (tag != JXACTIVE) 276595Sbill continue; 277630Shenry dest = jumpfrom->s_dest; 278630Shenry if (jumpfrom->s_index != dest->s_index){ 279595Sbill yyerror("Intersegment jxxx"); 280595Sbill continue; 281595Sbill } 282630Shenry displ = dest->s_value - jumpfrom->s_value; 283595Sbill if (displ < MINBYTE || displ > MAXBYTE) { 284595Sbill /* 285595Sbill * This is an immediate lose! 286595Sbill * 287595Sbill * We first attempt to tunnel 288595Sbill * by finding an intervening jump that 289595Sbill * has the same destination. 290595Sbill * The tunnel is always the first preceeding 291595Sbill * jxxx instruction, so the displacement 292595Sbill * to the tunnel is less than zero, and 293595Sbill * its relative position will be unaffected 294595Sbill * by future jxxx expansions. 295636Shenry * 296636Shenry * No tunnels if doing jumps... 297595Sbill */ 298636Shenry if ( (!jxxxJUMP) 299636Shenry && (jumpfrom->s_jxfear > jbrfsize) 300595Sbill && (tunnel) 301630Shenry && (tunnel->s_dest == jumpfrom->s_dest) 302630Shenry && (tunnel->s_index == jumpfrom->s_index) 303630Shenry && (tunnel->s_value - jumpfrom->s_value >= 304636Shenry MINBYTE + jxxxfsize) 305595Sbill ) { 306595Sbill /* 307595Sbill * tunnelling is OK 308595Sbill */ 309630Shenry jumpfrom->s_dest = tunnel; 310595Sbill /* 311595Sbill * no bumping needed, this 312595Sbill * is now effectively inactive 313595Sbill * but must be remembered 314595Sbill */ 315630Shenry jumpfrom->s_tag = JXTUNNEL; 316595Sbill #ifdef DEBUG 317595Sbill if(debug) 318595Sbill printf("Tunnel from %s from line %d\n", 31913512Srrh FETCHNAME(jumpfrom), 32015234Sralph jumpfrom->s_jxline); 321595Sbill #endif 322595Sbill continue; 323595Sbill } else { /*tunneling not possible*/ 324595Sbill /* 325595Sbill * since this will be turned 326595Sbill * into a bumped jump, we can 327595Sbill * use the unconditional jump 328595Sbill * as a tunnel 329595Sbill */ 330595Sbill tunnel = jumpfrom; 331630Shenry jumpfrom->s_tag = JXNOTYET; 332595Sbill ++nchange; 333595Sbill continue; 334595Sbill } 335595Sbill } /*end of immediate lose*/ 336595Sbill /* 337595Sbill * Do a forward search for an intervening jxxx 338595Sbill */ 339595Sbill if (displ >= 0) { 340595Sbill SEGITERATE(segno, cojumpfrom + 1,0,cointdest, 341595Sbill intdest, ubintdest, ++){ 34215289Sralph if (intdest->s_value > dest->s_value) 343595Sbill break; /* beyond destination */ 344630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 345595Sbill continue; /*frozen solid*/ 346630Shenry if (intdest->s_tag == JXALIGN){ 347630Shenry jumpfrom->s_jxoveralign = 1; 348595Sbill badjxalign++; 349595Sbill } 350595Sbill /* 351595Sbill * we assume the worst case 352595Sbill * for unfrozen jxxxxes 353595Sbill */ 354630Shenry displ += intdest->s_jxfear; 355595Sbill } 356595Sbill if (displ <= MAXBYTE){ 357595Sbill /* 358595Sbill * the worst possible conditions 359595Sbill * can't hurt us, so forget about 360595Sbill * this jump 361595Sbill */ 362630Shenry jumpfrom->s_tag = JXINACTIVE; 363595Sbill } else { 364595Sbill stillactives++; 365595Sbill } 366595Sbill } else { 367595Sbill /* 368595Sbill * backward search for intervening jxxx 369595Sbill */ 370595Sbill SEGITERATE(segno, cojumpfrom - 1,1,cointdest, 371595Sbill intdest, ubintdest, --){ 372630Shenry if (intdest->s_value <= dest->s_value) 373595Sbill break; /* beyond destination */ 374630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 375595Sbill continue; /*frozen solid*/ 376630Shenry if (intdest->s_tag == JXALIGN){ 377630Shenry jumpfrom->s_jxoveralign = 1; 378595Sbill badjxalign++; 379595Sbill } 380630Shenry displ -= intdest->s_jxfear; 381595Sbill } 382595Sbill if (displ >= MINBYTE) { 383630Shenry jumpfrom->s_tag = JXINACTIVE; 384595Sbill } else { 385595Sbill stillactives++; 386595Sbill } 387595Sbill } /*end of backwards search*/ 388595Sbill } /*end of iterating through all symbols in this seg*/ 389595Sbill 390595Sbill if (nchange == 0) { 391595Sbill /* 392595Sbill * Now, if there are still active jxxx entries, 393595Sbill * we are partially deadlocked. We can leave 394595Sbill * these jxxx entries in their assumed short jump 395595Sbill * form, as all initial displacement calcualtions 396595Sbill * are hanging on unresolved jxxx instructions 397595Sbill * that might explode into a long form, causing 398595Sbill * other jxxxes jumping across the first set of 399595Sbill * jxxxes to explode, etc. 400595Sbill * However, if a jxxx jumps across a .align, 401595Sbill * we assume the worst for the deadlock cycle, 402595Sbill * and resolve all of them towards the long 403595Sbill * jump. 404595Sbill * Currently, the C compiler does not produce 405595Sbill * jumps across aligns, as aligns are only used 406595Sbill * in data segments, or in text segments to align 407595Sbill * functions. 408595Sbill */ 409595Sbill if (stillactives){ 410595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 411595Sbill ubjumpfrom, ++){ 412630Shenry if (jumpfrom->s_tag == JXACTIVE){ 413630Shenry jumpfrom->s_tag = 414595Sbill badjxalign?JXNOTYET:JXINACTIVE; 415595Sbill } 416595Sbill } 417595Sbill if (badjxalign){ 418595Sbill jxxxbump(segno, (struct symtab **)0); 419595Sbill } 420595Sbill } 421595Sbill /* 422595Sbill * Handle all of the .align s 423595Sbill */ 424595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 425595Sbill ubjumpfrom, ++){ 426630Shenry if (jumpfrom->s_tag == JXALIGN){ 427595Sbill /* 428595Sbill * Predict the true displacement 429595Sbill * needed, irregardless of the 430595Sbill * fact that we guessed 1 431595Sbill */ 432630Shenry displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear; 433595Sbill if (displ == 0){ /*no virtual displacement*/ 434630Shenry jumpfrom->s_jxfear = -1; 435595Sbill } else { 436630Shenry jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ; 437595Sbill /* 438630Shenry * assert jumpfrom->s_jxfear > 0 439595Sbill */ 440630Shenry if (jumpfrom->s_jxfear == 1){ 441595Sbill /*our prediction was correct*/ 442595Sbill continue; 443595Sbill } 444595Sbill /* 445630Shenry * assert jumpfrom->s_jxfear > 1 446595Sbill */ 447630Shenry jumpfrom->s_jxfear -= 1; /*correct guess*/ 448595Sbill } 449595Sbill /* 450630Shenry * assert jumpfrom->s_jxfear = -1, +1...2**n-1 451595Sbill */ 452630Shenry jumpfrom->s_tag = JXNOTYET; /*signal*/ 453595Sbill jxxxbump(segno, cojumpfrom); 454630Shenry jumpfrom->s_tag = JXINACTIVE; 455595Sbill /* 456595Sbill * Assert jxfrom->jxvalue indexes the first 457595Sbill * code byte after the added bytes, and 458595Sbill * has n low order zeroes. 459595Sbill */ 460595Sbill } 461595Sbill } /*end of walking through each segment*/ 462595Sbill } /*end of no changes */ 463595Sbill else { /*changes, and still have to try another pass*/ 464595Sbill jxxxbump(segno, (struct symtab **)0); 465595Sbill } 466595Sbill } /*end of doing the topologic sort*/ 467595Sbill } /*end of iterating through all segments*/ 468595Sbill } /*end of jxxxfix*/ 469595Sbill 470595Sbill /* 471595Sbill * Go through the symbols in a given segment number, 472595Sbill * and see which entries are jxxx entries that have 473595Sbill * been logically "exploded" (expanded), but for which 474595Sbill * the value of textually following symbols has not been 475595Sbill * increased 476595Sbill */ 477595Sbill 478595Sbill jxxxbump(segno, starthint) 479595Sbill int segno; 480595Sbill struct symtab **starthint; 481595Sbill { 482595Sbill register struct symtab **cosp, *sp; 483595Sbill register struct symtab *ub; 484595Sbill register int cum_bump; 485595Sbill register unsigned char tag; 486595Sbill 487595Sbill cum_bump = 0; 488595Sbill SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){ 489630Shenry tag = sp->s_tag; 490595Sbill if (tag == JXNOTYET){ 491595Sbill #ifdef DEBUG 492595Sbill if (debug){ 493630Shenry if (sp->s_dest != 0) 494595Sbill printf("Explode jump to %s on line %d\n", 49515234Sralph FETCHNAME(sp->s_dest), sp->s_jxline); 496595Sbill else 49715234Sralph printf("Explode an align! on line %d\n", 49815234Sralph sp->s_jxline); 499595Sbill } 500595Sbill #endif 501630Shenry sp->s_tag = JXINACTIVE; 502630Shenry sp->s_jxbump = 1; 503630Shenry cum_bump += sp->s_jxfear; 504595Sbill } 505595Sbill /* 506595Sbill * Only bump labels and jxxxes. Ignored entries can 507595Sbill * be incremented, as they are thrown away later on. 508595Sbill * Stabds are given their final value in the second 509595Sbill * pass. 510595Sbill */ 511595Sbill if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/ 512630Shenry sp->s_value += cum_bump; 513595Sbill } 514630Shenry usedot[segno].e_xvalue += cum_bump; 515595Sbill } 516