xref: /original-bsd/old/as.vax/asjxxx.c (revision 5fb3de76)
1 /* Copyright (c) 1980 Regents of the University of California */
2 static	char sccsid[] = "@(#)asjxxx.c 4.5 08/20/80";
3 #include	<stdio.h>
4 #include	"as.h"
5 #include	"assyms.h"
6 
7 #define	JBR	0x11
8 #define	BRW	0x31
9 #define	JMP	0x17
10 
11 /*
12  *	The number of bytes to add if the jxxx must be "exploded"
13  *	into the long form
14  */
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 
20 int	jbrfsize = JBRDELTA;
21 int	jxxxfsize = JXXXDELTA;
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  */
28 struct 	symtab	*lastnam;
29 struct	symtab	*lastjxxx;
30 
31 initijxxx()
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 }
42 /*
43  *	Handle jxxx instructions
44  */
45 ijxout(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;
61 		jumpfrom->s_tag = JXACTIVE;
62 		jumpfrom->s_jxbump = 0;
63 		if (op == JBR)
64 			jumpfrom->s_jxfear = jbrfsize;
65 		else
66 			jumpfrom->s_jxfear = jxxxfsize;
67 		if (lastnam == 0)
68 			yyerror("jxxx destination not a label");
69 		jumpfrom->s_dest = lastnam;
70 		jumpfrom->s_type = dotp->e_xtype;	/*only TEXT or DATA*/
71 		jumpfrom->s_index = dotp-usedot;
72 		/*
73 		 *	value ALWAYS (ALWAYS!!!) indexes the next instruction
74 		 *	after the jump, even in the jump must be exploded
75 		 *	(bumped)
76 		 */
77 		jumpfrom->s_value = dotp->e_xvalue;
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;
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*/
94 				    - 3			/* size of brw + word*/
95 				    + ( ( (tunnel->s_jxfear == jbrfsize) &&
96 					  (tunnel->s_jxbump == 0))?1:0);
97 							/*non bumped branch byteis only 2 back*/
98 		}
99 		if (lastjxxx->s_jxbump == 0){	/*wasn't bumped, so is short form*/
100 			putins(op, ap, nact);
101 		} else {
102 			if (op != JBR){	/*branch reverse conditional byte over
103 					  branch unconditional word*/
104 				oxvalue = xp->e_xvalue;
105 				xp->e_xvalue = lastjxxx->s_value;
106 				putins(op^1, ap, nact);
107 				xp->e_xvalue = oxvalue;
108 			}
109 			putins(jxxxJUMP ? JMP : BRW, aplast, 1);
110 		}
111 	}
112 }	/*end of ijxout*/
113 
114 jalign(xp, sp)
115 	register struct exp *xp;
116 	register struct symtab *sp;
117 {
118 	register	int	mask;
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 	 */
137 	if (   (xp->e_xtype != XABS)
138 	    || (xp->e_xvalue < 0)
139 	    || (xp->e_xvalue > 16)
140 	    ) {
141 		yyerror("Illegal `align' argument");
142 		return;
143 	}
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;
152 	}
153 	flushfield(NBPW/4);
154 	if (passno == 1) {
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;
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 		 */
172 		dotp->e_xvalue += 1;
173 		sp->s_value = dotp->e_xvalue;
174 		njxxx++;
175 	} else {
176 		mask = (1 << xp->e_xvalue) - 1;
177 		while (dotp->e_xvalue & mask){
178 #ifdef UNIX
179 			outb(0);
180 #endif UNIX
181 #ifdef VMS
182 			*vms_obj_ptr++ = -1;
183 			*vms_obj_ptr++ = 0;
184 			dotp->e_xvalue += 1;
185 #endif VMS
186 		}
187 	}
188 }
189 
190 /*
191  *	Pass 1.5, resolve jxxx instructions and .align in .text
192  */
193 jxxxfix()
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, ++){
238 			tag = jumpfrom->s_tag;
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 			}
245 			if (   jumpfrom->s_jxfear == jbrfsize	/*unconditional*/
246 			    || (   tag == JXINACTIVE		/*inactive bumped*/
247 				&& (jumpfrom->s_jxbump != 0)
248 			       )
249 			   ) tunnel = jumpfrom;
250 			if (tag != JXACTIVE)
251 				continue;
252 			dest = jumpfrom->s_dest;
253 			if (jumpfrom->s_index != dest->s_index){
254 				yyerror("Intersegment jxxx");
255 				continue;
256 			}
257 			displ = dest->s_value - jumpfrom->s_value;
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.
270 				 *
271 				 *	No tunnels if doing jumps...
272 				 */
273 				if (    (!jxxxJUMP)
274 				     && (jumpfrom->s_jxfear > jbrfsize)
275 				     && (tunnel)
276 				     && (tunnel->s_dest == jumpfrom->s_dest)
277 				     && (tunnel->s_index == jumpfrom->s_index)
278 				     && (tunnel->s_value - jumpfrom->s_value >=
279 						MINBYTE + jxxxfsize)
280 				   ) {
281 						/*
282 						 *	tunnelling is OK
283 						 */
284 						jumpfrom->s_dest = tunnel;
285 						/*
286 						 * no bumping needed, this
287 						 * is now effectively inactive
288 						 * but must be remembered
289 						 */
290 						jumpfrom->s_tag = JXTUNNEL;
291 #ifdef DEBUG
292 						if(debug)
293 						printf("Tunnel from %s from line %d\n",
294 							jumpfrom->s_name, lineno);
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;
305 					jumpfrom->s_tag = JXNOTYET;
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, ++){
316 					if (intdest->s_value > dest->s_value)
317 						break; /* beyond destination */
318 					if (intdest->s_tag <= JXQUESTIONABLE)
319 						continue;	/*frozen solid*/
320 					if (intdest->s_tag == JXALIGN){
321 						jumpfrom->s_jxoveralign = 1;
322 						badjxalign++;
323 					}
324 					/*
325 					 *	we assume the worst case
326 					 *	for unfrozen jxxxxes
327 					 */
328 					displ += intdest->s_jxfear;
329 				}
330 				if (displ <= MAXBYTE){
331 					/*
332 					 *	the worst possible conditions
333 					 *	can't hurt us, so forget about
334 					 *	this jump
335 					 */
336 					jumpfrom->s_tag = JXINACTIVE;
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, --){
346 					if (intdest->s_value <= dest->s_value)
347 						break; /* beyond destination */
348 					if (intdest->s_tag <= JXQUESTIONABLE)
349 						continue;	/*frozen solid*/
350 					if (intdest->s_tag == JXALIGN){
351 						jumpfrom->s_jxoveralign = 1;
352 						badjxalign++;
353 					}
354 					displ -= intdest->s_jxfear;
355 				}
356 				if (displ >= MINBYTE) {
357 					jumpfrom->s_tag = JXINACTIVE;
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, ++){
386 					if (jumpfrom->s_tag == JXACTIVE){
387 						jumpfrom->s_tag =
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, ++){
400 			    if (jumpfrom->s_tag == JXALIGN){
401 				/*
402 				 *	Predict the true displacement
403 				 *	needed, irregardless of the
404 				 *	fact that we guessed 1
405 				 */
406 				displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear;
407 				if (displ == 0){	/*no virtual displacement*/
408 					jumpfrom->s_jxfear = -1;
409 				} else {
410 					jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ;
411 					/*
412 					 *	assert jumpfrom->s_jxfear > 0
413 					 */
414 					if (jumpfrom->s_jxfear == 1){
415 						/*our prediction was correct*/
416 						continue;
417 					}
418 					/*
419 					 *	assert jumpfrom->s_jxfear > 1
420 					 */
421 					jumpfrom->s_jxfear -= 1;	/*correct guess*/
422 				}
423 				/*
424 				 *	assert jumpfrom->s_jxfear = -1, +1...2**n-1
425 				 */
426 				jumpfrom->s_tag = JXNOTYET;	/*signal*/
427 				jxxxbump(segno, cojumpfrom);
428 				jumpfrom->s_tag = JXINACTIVE;
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 
452 jxxxbump(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, ++){
463 		tag = sp->s_tag;
464 		if (tag == JXNOTYET){
465 #ifdef DEBUG
466 			if (debug){
467 			if (sp->s_dest != 0)
468 				printf("Explode jump to %s on line %d\n",
469 					sp->s_dest->s_name, lineno);
470 			else
471 				printf("Explode an align!\n");
472 			}
473 #endif
474 			sp->s_tag = JXINACTIVE;
475 			sp->s_jxbump = 1;
476 			cum_bump += sp->s_jxfear;
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*/
485 			sp->s_value += cum_bump;
486 	}
487 	usedot[segno].e_xvalue += cum_bump;
488 }
489