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