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