xref: /original-bsd/old/as.tahoe/asjxxx.c (revision 27b5b994)
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