utah rcsid 1.2 87/01/12 04:27:27: A bug in jxxxfix() was fixed(!). After
[unix-history] / usr / src / old / as.vax / asjxxx.c
CommitLineData
f70ab843 1/*
bcf1365c
DF
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.
f70ab843 5 */
bcf1365c 6
f70ab843 7#ifndef lint
562434ea 8static char sccsid[] = "@(#)asjxxx.c 5.3 (Berkeley) %G%";
f70ab843
RH
9#endif not lint
10
d0d638ee 11#include <stdio.h>
d0d638ee
BJ
12#include "as.h"
13#include "assyms.h"
14
e5b9ebfb
RH
15#define JBR 0x11
16#define BRW 0x31
17#define JMP 0x17
d0d638ee
BJ
18
19/*
20 * The number of bytes to add if the jxxx must be "exploded"
21 * into the long form
22 */
e5b9ebfb
RH
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
28int jbrfsize = JBRDELTA;
29int jxxxfsize = JXXXDELTA;
d0d638ee
BJ
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 */
36struct symtab *lastnam;
37struct symtab *lastjxxx;
38
e5b9ebfb
RH
39initijxxx()
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}
d0d638ee
BJ
50/*
51 * Handle jxxx instructions
52 */
f70ab843
RH
53ijxout(opcode, ap, nact)
54 struct Opcode opcode;
55 struct arg *ap;
56 int nact;
d0d638ee
BJ
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 */
f70ab843 69 putins(opcode, ap, nact);
d0d638ee 70 jumpfrom = lastjxxx;
451260e7
RH
71 jumpfrom->s_tag = JXACTIVE;
72 jumpfrom->s_jxbump = 0;
f70ab843 73 if (opcode.Op_popcode == JBR)
e5b9ebfb 74 jumpfrom->s_jxfear = jbrfsize;
d0d638ee 75 else
e5b9ebfb 76 jumpfrom->s_jxfear = jxxxfsize;
d0d638ee
BJ
77 if (lastnam == 0)
78 yyerror("jxxx destination not a label");
451260e7
RH
79 jumpfrom->s_dest = lastnam;
80 jumpfrom->s_type = dotp->e_xtype; /*only TEXT or DATA*/
81 jumpfrom->s_index = dotp-usedot;
d5932397
RC
82#ifdef DEBUG
83 jumpfrom->s_name = ITABFETCH(opcode)->i_name;
84 jumpfrom->s_jxline = lineno;
85#endif
d0d638ee
BJ
86 /*
87 * value ALWAYS (ALWAYS!!!) indexes the next instruction
d5932397 88 * after the jump, even if the jump must be exploded
d0d638ee
BJ
89 * (bumped)
90 */
451260e7 91 jumpfrom->s_value = dotp->e_xvalue;
d0d638ee
BJ
92 njxxx++;
93 } else {/* pass2, resolve */
94 /*
95 * READ THIS AFTER LOOKING AT jxxxfix()
96 */
f70ab843
RH
97 reg long oxvalue;
98 reg struct exp *xp;
99 reg struct symtab *tunnel;
100 reg struct arg *aplast;
101 struct Opcode nopcode;
d0d638ee
BJ
102
103 aplast = ap + nact - 1;
451260e7
RH
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*/
d0d638ee 109 - 3 /* size of brw + word*/
e5b9ebfb 110 + ( ( (tunnel->s_jxfear == jbrfsize) &&
451260e7 111 (tunnel->s_jxbump == 0))?1:0);
d0d638ee
BJ
112 /*non bumped branch byteis only 2 back*/
113 }
451260e7 114 if (lastjxxx->s_jxbump == 0){ /*wasn't bumped, so is short form*/
f70ab843 115 putins(opcode, ap, nact);
d0d638ee 116 } else {
f70ab843
RH
117 if (opcode.Op_popcode != JBR){
118 /*
119 * branch reverse conditional byte over
120 * branch unconditional word
121 */
451260e7
RH
122 oxvalue = xp->e_xvalue;
123 xp->e_xvalue = lastjxxx->s_value;
f70ab843
RH
124 nopcode = opcode;
125 nopcode.Op_popcode ^= 1;
126 putins(nopcode, ap, nact);
451260e7 127 xp->e_xvalue = oxvalue;
d0d638ee 128 }
f70ab843
RH
129 nopcode.Op_eopcode = CORE;
130 nopcode.Op_popcode = jxxxJUMP ? JMP : BRW;
131 putins(nopcode, aplast, 1);
d0d638ee
BJ
132 }
133 }
f70ab843 134}
d0d638ee
BJ
135
136jalign(xp, sp)
137 register struct exp *xp;
138 register struct symtab *sp;
139{
140 register int mask;
d5932397
RC
141#ifdef DEBUG
142 static struct strdesc noname;
143#endif
7a5aec15
RH
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
ea01d993
RH
160 * to a .align (maxalign), if possible, where maxalign
161 * is set in the command line, and defaults to 2.
7a5aec15 162 */
f70ab843 163 if ( ( (xp->e_xtype & XTYPE) != XABS)
8efb1a2c
RH
164 || (xp->e_xvalue < 0)
165 || (xp->e_xvalue > 16)
166 ) {
d0d638ee
BJ
167 yyerror("Illegal `align' argument");
168 return;
169 }
ea01d993 170 if (xp->e_xvalue > maxalign){
7a5aec15 171 if (passno == 1){
f70ab843
RH
172 yywarning(".align %d is NOT preserved by the loader",
173 xp->e_xvalue);
ea01d993
RH
174 yywarning(".align %d converted to .align %d",
175 xp->e_xvalue, maxalign);
7a5aec15 176 }
ea01d993 177 xp->e_xvalue = maxalign;
8efb1a2c 178 }
3a304944 179 flushfield(NBWD/4);
d0d638ee 180 if (passno == 1) {
451260e7
RH
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;
d5932397
RC
185#ifdef DEBUG
186 sp->s_name = (char *)&noname;
187 sp->s_jxline = lineno;
188#endif
d0d638ee
BJ
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 */
451260e7
RH
202 dotp->e_xvalue += 1;
203 sp->s_value = dotp->e_xvalue;
d0d638ee
BJ
204 njxxx++;
205 } else {
451260e7 206 mask = (1 << xp->e_xvalue) - 1;
f70ab843
RH
207 while (dotp->e_xvalue & mask)
208 Outb(0);
d0d638ee
BJ
209 }
210}
211
212/*
213 * Pass 1.5, resolve jxxx instructions and .align in .text
214 */
215jxxxfix()
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++){
f70ab843
RH
239#ifdef lint
240 topno = topno;
241#endif lint
d0d638ee
BJ
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, ++){
451260e7 263 tag = jumpfrom->s_tag;
d0d638ee
BJ
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 }
e5b9ebfb 270 if ( jumpfrom->s_jxfear == jbrfsize /*unconditional*/
d0d638ee 271 || ( tag == JXINACTIVE /*inactive bumped*/
451260e7 272 && (jumpfrom->s_jxbump != 0)
d0d638ee
BJ
273 )
274 ) tunnel = jumpfrom;
275 if (tag != JXACTIVE)
276 continue;
451260e7
RH
277 dest = jumpfrom->s_dest;
278 if (jumpfrom->s_index != dest->s_index){
d0d638ee
BJ
279 yyerror("Intersegment jxxx");
280 continue;
281 }
451260e7 282 displ = dest->s_value - jumpfrom->s_value;
d0d638ee
BJ
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.
e5b9ebfb
RH
295 *
296 * No tunnels if doing jumps...
d0d638ee 297 */
e5b9ebfb
RH
298 if ( (!jxxxJUMP)
299 && (jumpfrom->s_jxfear > jbrfsize)
d0d638ee 300 && (tunnel)
451260e7
RH
301 && (tunnel->s_dest == jumpfrom->s_dest)
302 && (tunnel->s_index == jumpfrom->s_index)
303 && (tunnel->s_value - jumpfrom->s_value >=
e5b9ebfb 304 MINBYTE + jxxxfsize)
d0d638ee
BJ
305 ) {
306 /*
307 * tunnelling is OK
308 */
451260e7 309 jumpfrom->s_dest = tunnel;
d0d638ee
BJ
310 /*
311 * no bumping needed, this
312 * is now effectively inactive
313 * but must be remembered
314 */
451260e7 315 jumpfrom->s_tag = JXTUNNEL;
d0d638ee
BJ
316#ifdef DEBUG
317 if(debug)
318 printf("Tunnel from %s from line %d\n",
ec43bca4 319 FETCHNAME(jumpfrom),
d5932397 320 jumpfrom->s_jxline);
d0d638ee
BJ
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;
451260e7 331 jumpfrom->s_tag = JXNOTYET;
d0d638ee
BJ
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, ++){
562434ea 342 if (intdest == dest)
d0d638ee 343 break; /* beyond destination */
451260e7 344 if (intdest->s_tag <= JXQUESTIONABLE)
d0d638ee 345 continue; /*frozen solid*/
451260e7
RH
346 if (intdest->s_tag == JXALIGN){
347 jumpfrom->s_jxoveralign = 1;
d0d638ee
BJ
348 badjxalign++;
349 }
350 /*
351 * we assume the worst case
352 * for unfrozen jxxxxes
353 */
451260e7 354 displ += intdest->s_jxfear;
d0d638ee
BJ
355 }
356 if (displ <= MAXBYTE){
357 /*
358 * the worst possible conditions
359 * can't hurt us, so forget about
360 * this jump
361 */
451260e7 362 jumpfrom->s_tag = JXINACTIVE;
d0d638ee
BJ
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, --){
562434ea 372 if (intdest == dest)
d0d638ee 373 break; /* beyond destination */
451260e7 374 if (intdest->s_tag <= JXQUESTIONABLE)
d0d638ee 375 continue; /*frozen solid*/
451260e7
RH
376 if (intdest->s_tag == JXALIGN){
377 jumpfrom->s_jxoveralign = 1;
d0d638ee
BJ
378 badjxalign++;
379 }
451260e7 380 displ -= intdest->s_jxfear;
d0d638ee
BJ
381 }
382 if (displ >= MINBYTE) {
451260e7 383 jumpfrom->s_tag = JXINACTIVE;
d0d638ee
BJ
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, ++){
451260e7
RH
412 if (jumpfrom->s_tag == JXACTIVE){
413 jumpfrom->s_tag =
d0d638ee
BJ
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, ++){
451260e7 426 if (jumpfrom->s_tag == JXALIGN){
d0d638ee
BJ
427 /*
428 * Predict the true displacement
429 * needed, irregardless of the
430 * fact that we guessed 1
431 */
451260e7 432 displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear;
d0d638ee 433 if (displ == 0){ /*no virtual displacement*/
451260e7 434 jumpfrom->s_jxfear = -1;
d0d638ee 435 } else {
451260e7 436 jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ;
d0d638ee 437 /*
451260e7 438 * assert jumpfrom->s_jxfear > 0
d0d638ee 439 */
451260e7 440 if (jumpfrom->s_jxfear == 1){
d0d638ee
BJ
441 /*our prediction was correct*/
442 continue;
443 }
444 /*
451260e7 445 * assert jumpfrom->s_jxfear > 1
d0d638ee 446 */
451260e7 447 jumpfrom->s_jxfear -= 1; /*correct guess*/
d0d638ee
BJ
448 }
449 /*
451260e7 450 * assert jumpfrom->s_jxfear = -1, +1...2**n-1
d0d638ee 451 */
451260e7 452 jumpfrom->s_tag = JXNOTYET; /*signal*/
d0d638ee 453 jxxxbump(segno, cojumpfrom);
451260e7 454 jumpfrom->s_tag = JXINACTIVE;
d0d638ee
BJ
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
478jxxxbump(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, ++){
451260e7 489 tag = sp->s_tag;
d0d638ee
BJ
490 if (tag == JXNOTYET){
491#ifdef DEBUG
492 if (debug){
451260e7 493 if (sp->s_dest != 0)
d0d638ee 494 printf("Explode jump to %s on line %d\n",
d5932397 495 FETCHNAME(sp->s_dest), sp->s_jxline);
d0d638ee 496 else
d5932397
RC
497 printf("Explode an align! on line %d\n",
498 sp->s_jxline);
d0d638ee
BJ
499 }
500#endif
451260e7
RH
501 sp->s_tag = JXINACTIVE;
502 sp->s_jxbump = 1;
503 cum_bump += sp->s_jxfear;
d0d638ee
BJ
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*/
451260e7 512 sp->s_value += cum_bump;
d0d638ee 513 }
451260e7 514 usedot[segno].e_xvalue += cum_bump;
d0d638ee 515}