15825Srrh /*
219823Sdist * Copyright (c) 1982 Regents of the University of California.
319823Sdist * All rights reserved. The Berkeley software License Agreement
419823Sdist * specifies the terms and conditions for redistribution.
55825Srrh */
619823Sdist
75825Srrh #ifndef lint
8*32984Sdonn static char sccsid[] = "@(#)asjxxx.c 5.4 (Berkeley) 12/11/87";
95825Srrh #endif not lint
105825Srrh
11595Sbill #include <stdio.h>
12595Sbill #include "as.h"
13595Sbill #include "assyms.h"
14595Sbill
15636Shenry #define JBR 0x11
16636Shenry #define BRW 0x31
17636Shenry #define JMP 0x17
18595Sbill
19595Sbill /*
20595Sbill * The number of bytes to add if the jxxx must be "exploded"
21595Sbill * into the long form
22595Sbill */
23636Shenry #define JBRDELTA 1 /* brb <byte> ==> brw <byte> <byte> */
24636Shenry #define JXXXDELTA 3 /* brb <byte> ==> brb <byte> brw <byte> <byte> */
25636Shenry #define JBRJDELTA d124 /* brb <byte> ==> jmp L^(pc) <byte>*d124 */
26636Shenry #define JXXXJDELTA d124+2 /* brb <byte> ==> brb <byte> jmp L^(pc) <byte>*d124 */
27595Sbill
28636Shenry int jbrfsize = JBRDELTA;
29636Shenry int jxxxfsize = JXXXDELTA;
30636Shenry
31595Sbill /*
32595Sbill * These variables are filled by asscan.c with the
33595Sbill * last name encountered (a pointer buried in the intermediate file),
34595Sbill * and the last jxxx symbol table entry encountered.
35595Sbill */
36595Sbill struct symtab *lastnam;
37595Sbill struct symtab *lastjxxx;
38595Sbill
initijxxx()39636Shenry initijxxx()
40636Shenry {
41636Shenry jbrfsize = jxxxJUMP ? JBRJDELTA : JBRDELTA;
42636Shenry jxxxfsize = jxxxJUMP ? JXXXJDELTA : JXXXDELTA;
43636Shenry /*
44636Shenry * Note: ifjxxxJUMP is set, then we do NOT do any tunnelling;
45636Shenry * this was too complicated to figure out, and in the first
46636Shenry * version of the assembler, tunnelling proved to be the hardest
47636Shenry * to get to work!
48636Shenry */
49636Shenry }
50595Sbill /*
51595Sbill * Handle jxxx instructions
52595Sbill */
535825Srrh ijxout(opcode, ap, nact)
545825Srrh struct Opcode opcode;
555825Srrh struct arg *ap;
565825Srrh int nact;
57595Sbill {
58595Sbill if (passno == 1){
59595Sbill /*
60595Sbill * READ THIS BEFORE LOOKING AT jxxxfix()
61595Sbill *
62595Sbill * Record the jxxx in a special symbol table entry
63595Sbill */
64595Sbill register struct symtab *jumpfrom;
65595Sbill
66595Sbill /*
67595Sbill * We assume the MINIMAL length
68595Sbill */
695825Srrh putins(opcode, ap, nact);
70595Sbill jumpfrom = lastjxxx;
71630Shenry jumpfrom->s_tag = JXACTIVE;
72630Shenry jumpfrom->s_jxbump = 0;
735825Srrh if (opcode.Op_popcode == JBR)
74636Shenry jumpfrom->s_jxfear = jbrfsize;
75595Sbill else
76636Shenry jumpfrom->s_jxfear = jxxxfsize;
77595Sbill if (lastnam == 0)
78595Sbill yyerror("jxxx destination not a label");
79630Shenry jumpfrom->s_dest = lastnam;
80630Shenry jumpfrom->s_type = dotp->e_xtype; /*only TEXT or DATA*/
81630Shenry jumpfrom->s_index = dotp-usedot;
8215234Sralph #ifdef DEBUG
8315234Sralph jumpfrom->s_name = ITABFETCH(opcode)->i_name;
8415234Sralph jumpfrom->s_jxline = lineno;
8515234Sralph #endif
86595Sbill /*
87595Sbill * value ALWAYS (ALWAYS!!!) indexes the next instruction
8815234Sralph * after the jump, even if the jump must be exploded
89595Sbill * (bumped)
90595Sbill */
91630Shenry jumpfrom->s_value = dotp->e_xvalue;
92595Sbill njxxx++;
93595Sbill } else {/* pass2, resolve */
94595Sbill /*
95595Sbill * READ THIS AFTER LOOKING AT jxxxfix()
96595Sbill */
975825Srrh reg long oxvalue;
985825Srrh reg struct exp *xp;
995825Srrh reg struct symtab *tunnel;
1005825Srrh reg struct arg *aplast;
1015825Srrh struct Opcode nopcode;
102595Sbill
103595Sbill aplast = ap + nact - 1;
104630Shenry xp = aplast->a_xp;
105630Shenry if (lastjxxx->s_tag == JXTUNNEL){
106630Shenry lastjxxx->s_tag = JXINACTIVE;
107630Shenry tunnel = lastjxxx->s_dest;
108630Shenry xp->e_xvalue = tunnel->s_value /*index of instruction following*/
109595Sbill - 3 /* size of brw + word*/
110636Shenry + ( ( (tunnel->s_jxfear == jbrfsize) &&
111630Shenry (tunnel->s_jxbump == 0))?1:0);
112595Sbill /*non bumped branch byteis only 2 back*/
113595Sbill }
114630Shenry if (lastjxxx->s_jxbump == 0){ /*wasn't bumped, so is short form*/
1155825Srrh putins(opcode, ap, nact);
116595Sbill } else {
1175825Srrh if (opcode.Op_popcode != JBR){
1185825Srrh /*
1195825Srrh * branch reverse conditional byte over
1205825Srrh * branch unconditional word
1215825Srrh */
122630Shenry oxvalue = xp->e_xvalue;
123630Shenry xp->e_xvalue = lastjxxx->s_value;
1245825Srrh nopcode = opcode;
1255825Srrh nopcode.Op_popcode ^= 1;
1265825Srrh putins(nopcode, ap, nact);
127630Shenry xp->e_xvalue = oxvalue;
128595Sbill }
1295825Srrh nopcode.Op_eopcode = CORE;
1305825Srrh nopcode.Op_popcode = jxxxJUMP ? JMP : BRW;
1315825Srrh putins(nopcode, aplast, 1);
132595Sbill }
133595Sbill }
1345825Srrh }
135595Sbill
jalign(xp,sp)136595Sbill jalign(xp, sp)
137595Sbill register struct exp *xp;
138595Sbill register struct symtab *sp;
139595Sbill {
140595Sbill register int mask;
14115234Sralph #ifdef DEBUG
14215234Sralph static struct strdesc noname;
14315234Sralph #endif
144680Shenry /*
145680Shenry * Problem with .align
146680Shenry *
147680Shenry * When the loader constructs an executable file from
148680Shenry * a number of objects, it effectively concatnates
149680Shenry * together all of the text segments from all objects,
150680Shenry * and then all of the data segments.
151680Shenry *
152680Shenry * If we do an align by a large value, we can align
153680Shenry * within the a.out this assembly produces, but
154680Shenry * after the loader concatnates, the alignment can't
155680Shenry * be guaranteed if the objects preceding this one
156680Shenry * in the load are also aligned to the same size.
157680Shenry *
158680Shenry * Currently, the loader guarantees full word alignment.
159680Shenry * So, ridiculous aligns are caught here and converted
16015559Srrh * to a .align (maxalign), if possible, where maxalign
16115559Srrh * is set in the command line, and defaults to 2.
162680Shenry */
1635825Srrh if ( ( (xp->e_xtype & XTYPE) != XABS)
164678Shenry || (xp->e_xvalue < 0)
165678Shenry || (xp->e_xvalue > 16)
166678Shenry ) {
167595Sbill yyerror("Illegal `align' argument");
168595Sbill return;
169595Sbill }
17015559Srrh if (xp->e_xvalue > maxalign){
171680Shenry if (passno == 1){
1725825Srrh yywarning(".align %d is NOT preserved by the loader",
1735825Srrh xp->e_xvalue);
17415559Srrh yywarning(".align %d converted to .align %d",
17515559Srrh xp->e_xvalue, maxalign);
176680Shenry }
17715559Srrh xp->e_xvalue = maxalign;
178678Shenry }
17923579Smckusick flushfield(NBWD/4);
180595Sbill if (passno == 1) {
181630Shenry sp->s_tag = JXALIGN;
182630Shenry sp->s_jxfear = (1 << xp->e_xvalue) - 1;
183630Shenry sp->s_type = dotp->e_xtype;
184630Shenry sp->s_index = dotp-usedot;
18515234Sralph #ifdef DEBUG
18615234Sralph sp->s_name = (char *)&noname;
18715234Sralph sp->s_jxline = lineno;
18815234Sralph #endif
189595Sbill /*
190595Sbill * We guess that the align will take up at least one
191595Sbill * byte in the code output. We will correct for this
192595Sbill * initial high guess when we explode (bump) aligns
193595Sbill * when we fix the jxxxes. We must do this guess
194595Sbill * so that the symbol table is sorted correctly
195595Sbill * and labels declared to fall before the align
196595Sbill * really get their, instead of guessing zero size
197595Sbill * and have the label (incorrectly) fall after the jxxx.
198595Sbill * This is a quirk of our requirement that indices into
199595Sbill * the code stream point to the next byte following
200595Sbill * the logical entry in the symbol table
201595Sbill */
202630Shenry dotp->e_xvalue += 1;
203630Shenry sp->s_value = dotp->e_xvalue;
204595Sbill njxxx++;
205595Sbill } else {
206630Shenry mask = (1 << xp->e_xvalue) - 1;
2075825Srrh while (dotp->e_xvalue & mask)
2085825Srrh Outb(0);
209595Sbill }
210595Sbill }
211595Sbill
212595Sbill /*
213595Sbill * Pass 1.5, resolve jxxx instructions and .align in .text
214595Sbill */
jxxxfix()215595Sbill jxxxfix()
216595Sbill {
217595Sbill register struct symtab *jumpfrom;
218595Sbill struct symtab **cojumpfrom, *ubjumpfrom;
219595Sbill register struct symtab *dest;
220595Sbill register struct symtab *intdest; /*intermediate dest*/
221595Sbill register struct symtab **cointdest, *ubintdest;
222595Sbill
223595Sbill register struct symtab *tunnel;
224595Sbill int displ,nchange;
225595Sbill int badjxalign; /*if jump across an align*/
226595Sbill int stillactives; /*if still active jxxxes*/
227595Sbill int segno; /*current segment number*/
228595Sbill int topono; /*which iteration in the topo sort*/
229595Sbill register unsigned char tag;
230595Sbill /*
231595Sbill * consider each segment in turn...
232595Sbill */
233595Sbill for (segno = 0; segno < NLOC + NLOC; segno++){
234595Sbill badjxalign = 0; /*done on a per segment basis*/
235595Sbill /*
236595Sbill * Do a lazy topological sort.
237595Sbill */
238595Sbill for (topono = 1, nchange = 1; nchange != 0; topono++){
2395825Srrh #ifdef lint
2405825Srrh topno = topno;
2415825Srrh #endif lint
242595Sbill #ifdef DEBUG
243595Sbill if (debug)
244595Sbill printf("\nSegment %d, topo iteration %d\n",
245595Sbill segno, topono);
246595Sbill #endif
247595Sbill nchange = 0;
248595Sbill stillactives = 0;
249595Sbill /*
250595Sbill * We keep track of one possible tunnel location.
251595Sbill * A tunnel will eventually be an unconditional
252595Sbill * branch to the same place that another jxxx
253595Sbill * will want to branch to. We will turn a
254595Sbill * branch conditional/unconditional (word) that would
255595Sbill * have to get bumped because its destination is too
256595Sbill * far away, into a branch conditional/unconditional
257595Sbill * byte to the tunnel branch conditional/unconditional.
258595Sbill * Of course, the tunnel must branch to the same place
259595Sbill * as we want to go.
260595Sbill */
261595Sbill tunnel = 0; /*initially, no tunnel*/
262595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){
263630Shenry tag = jumpfrom->s_tag;
264595Sbill if (tag <= IGNOREBOUND)
265595Sbill continue; /*just an ordinary symbol*/
266595Sbill if (tag == JXALIGN){
267595Sbill tunnel = 0; /*avoid tunneling across a flex alocation*/
268595Sbill continue; /*we take care of these later*/
269595Sbill }
270636Shenry if ( jumpfrom->s_jxfear == jbrfsize /*unconditional*/
271595Sbill || ( tag == JXINACTIVE /*inactive bumped*/
272630Shenry && (jumpfrom->s_jxbump != 0)
273595Sbill )
274595Sbill ) tunnel = jumpfrom;
275595Sbill if (tag != JXACTIVE)
276595Sbill continue;
277630Shenry dest = jumpfrom->s_dest;
278630Shenry if (jumpfrom->s_index != dest->s_index){
279595Sbill yyerror("Intersegment jxxx");
280595Sbill continue;
281595Sbill }
282630Shenry displ = dest->s_value - jumpfrom->s_value;
283595Sbill if (displ < MINBYTE || displ > MAXBYTE) {
284595Sbill /*
285595Sbill * This is an immediate lose!
286595Sbill *
287595Sbill * We first attempt to tunnel
288595Sbill * by finding an intervening jump that
289595Sbill * has the same destination.
290595Sbill * The tunnel is always the first preceeding
291595Sbill * jxxx instruction, so the displacement
292595Sbill * to the tunnel is less than zero, and
293595Sbill * its relative position will be unaffected
294595Sbill * by future jxxx expansions.
295636Shenry *
296636Shenry * No tunnels if doing jumps...
297595Sbill */
298636Shenry if ( (!jxxxJUMP)
299636Shenry && (jumpfrom->s_jxfear > jbrfsize)
300595Sbill && (tunnel)
301630Shenry && (tunnel->s_dest == jumpfrom->s_dest)
302630Shenry && (tunnel->s_index == jumpfrom->s_index)
303630Shenry && (tunnel->s_value - jumpfrom->s_value >=
304636Shenry MINBYTE + jxxxfsize)
305595Sbill ) {
306595Sbill /*
307595Sbill * tunnelling is OK
308595Sbill */
309630Shenry jumpfrom->s_dest = tunnel;
310595Sbill /*
311595Sbill * no bumping needed, this
312595Sbill * is now effectively inactive
313595Sbill * but must be remembered
314595Sbill */
315630Shenry jumpfrom->s_tag = JXTUNNEL;
316595Sbill #ifdef DEBUG
317595Sbill if(debug)
318595Sbill printf("Tunnel from %s from line %d\n",
31913512Srrh FETCHNAME(jumpfrom),
32015234Sralph jumpfrom->s_jxline);
321595Sbill #endif
322595Sbill continue;
323595Sbill } else { /*tunneling not possible*/
324595Sbill /*
325595Sbill * since this will be turned
326595Sbill * into a bumped jump, we can
327595Sbill * use the unconditional jump
328595Sbill * as a tunnel
329595Sbill */
330595Sbill tunnel = jumpfrom;
331630Shenry jumpfrom->s_tag = JXNOTYET;
332595Sbill ++nchange;
333595Sbill continue;
334595Sbill }
335595Sbill } /*end of immediate lose*/
336595Sbill /*
337595Sbill * Do a forward search for an intervening jxxx
338595Sbill */
339595Sbill if (displ >= 0) {
340595Sbill SEGITERATE(segno, cojumpfrom + 1,0,cointdest,
341595Sbill intdest, ubintdest, ++){
34232983Sdonn if (intdest == dest)
343595Sbill break; /* beyond destination */
344630Shenry if (intdest->s_tag <= JXQUESTIONABLE)
345595Sbill continue; /*frozen solid*/
346630Shenry if (intdest->s_tag == JXALIGN){
347630Shenry jumpfrom->s_jxoveralign = 1;
348595Sbill badjxalign++;
349595Sbill }
350595Sbill /*
351595Sbill * we assume the worst case
352595Sbill * for unfrozen jxxxxes
353595Sbill */
354630Shenry displ += intdest->s_jxfear;
355595Sbill }
356595Sbill if (displ <= MAXBYTE){
357595Sbill /*
358595Sbill * the worst possible conditions
359595Sbill * can't hurt us, so forget about
360595Sbill * this jump
361595Sbill */
362630Shenry jumpfrom->s_tag = JXINACTIVE;
363595Sbill } else {
364595Sbill stillactives++;
365595Sbill }
366595Sbill } else {
367595Sbill /*
368595Sbill * backward search for intervening jxxx
369595Sbill */
370595Sbill SEGITERATE(segno, cojumpfrom - 1,1,cointdest,
371595Sbill intdest, ubintdest, --){
37232983Sdonn if (intdest == dest)
373595Sbill break; /* beyond destination */
374630Shenry if (intdest->s_tag <= JXQUESTIONABLE)
375595Sbill continue; /*frozen solid*/
376630Shenry if (intdest->s_tag == JXALIGN){
377630Shenry jumpfrom->s_jxoveralign = 1;
378595Sbill badjxalign++;
379595Sbill }
380630Shenry displ -= intdest->s_jxfear;
381595Sbill }
382595Sbill if (displ >= MINBYTE) {
383630Shenry jumpfrom->s_tag = JXINACTIVE;
384595Sbill } else {
385595Sbill stillactives++;
386595Sbill }
387595Sbill } /*end of backwards search*/
388595Sbill } /*end of iterating through all symbols in this seg*/
389595Sbill
390595Sbill if (nchange == 0) {
391595Sbill /*
392595Sbill * Now, if there are still active jxxx entries,
393595Sbill * we are partially deadlocked. We can leave
394595Sbill * these jxxx entries in their assumed short jump
395595Sbill * form, as all initial displacement calcualtions
396595Sbill * are hanging on unresolved jxxx instructions
397595Sbill * that might explode into a long form, causing
398595Sbill * other jxxxes jumping across the first set of
399595Sbill * jxxxes to explode, etc.
400595Sbill * However, if a jxxx jumps across a .align,
401595Sbill * we assume the worst for the deadlock cycle,
402595Sbill * and resolve all of them towards the long
403595Sbill * jump.
404595Sbill * Currently, the C compiler does not produce
405595Sbill * jumps across aligns, as aligns are only used
406595Sbill * in data segments, or in text segments to align
407595Sbill * functions.
408595Sbill */
409595Sbill if (stillactives){
410595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
411595Sbill ubjumpfrom, ++){
412630Shenry if (jumpfrom->s_tag == JXACTIVE){
413630Shenry jumpfrom->s_tag =
414595Sbill badjxalign?JXNOTYET:JXINACTIVE;
415595Sbill }
416595Sbill }
417595Sbill if (badjxalign){
418595Sbill jxxxbump(segno, (struct symtab **)0);
419595Sbill }
420595Sbill }
421595Sbill /*
422595Sbill * Handle all of the .align s
423595Sbill */
424595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
425595Sbill ubjumpfrom, ++){
426630Shenry if (jumpfrom->s_tag == JXALIGN){
427595Sbill /*
428595Sbill * Predict the true displacement
429595Sbill * needed, irregardless of the
430595Sbill * fact that we guessed 1
431595Sbill */
432630Shenry displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear;
433595Sbill if (displ == 0){ /*no virtual displacement*/
434630Shenry jumpfrom->s_jxfear = -1;
435595Sbill } else {
436630Shenry jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ;
437595Sbill /*
438630Shenry * assert jumpfrom->s_jxfear > 0
439595Sbill */
440630Shenry if (jumpfrom->s_jxfear == 1){
441595Sbill /*our prediction was correct*/
442595Sbill continue;
443595Sbill }
444595Sbill /*
445630Shenry * assert jumpfrom->s_jxfear > 1
446595Sbill */
447630Shenry jumpfrom->s_jxfear -= 1; /*correct guess*/
448595Sbill }
449595Sbill /*
450630Shenry * assert jumpfrom->s_jxfear = -1, +1...2**n-1
451595Sbill */
452630Shenry jumpfrom->s_tag = JXNOTYET; /*signal*/
453595Sbill jxxxbump(segno, cojumpfrom);
454630Shenry jumpfrom->s_tag = JXINACTIVE;
455595Sbill /*
456595Sbill * Assert jxfrom->jxvalue indexes the first
457595Sbill * code byte after the added bytes, and
458595Sbill * has n low order zeroes.
459595Sbill */
460595Sbill }
461595Sbill } /*end of walking through each segment*/
462595Sbill } /*end of no changes */
463595Sbill else { /*changes, and still have to try another pass*/
464595Sbill jxxxbump(segno, (struct symtab **)0);
465595Sbill }
466595Sbill } /*end of doing the topologic sort*/
467595Sbill } /*end of iterating through all segments*/
468595Sbill } /*end of jxxxfix*/
469595Sbill
470595Sbill /*
471595Sbill * Go through the symbols in a given segment number,
472595Sbill * and see which entries are jxxx entries that have
473595Sbill * been logically "exploded" (expanded), but for which
474595Sbill * the value of textually following symbols has not been
475595Sbill * increased
476595Sbill */
477595Sbill
jxxxbump(segno,starthint)478595Sbill jxxxbump(segno, starthint)
479595Sbill int segno;
480595Sbill struct symtab **starthint;
481595Sbill {
482595Sbill register struct symtab **cosp, *sp;
483595Sbill register struct symtab *ub;
484595Sbill register int cum_bump;
485595Sbill register unsigned char tag;
486595Sbill
487595Sbill cum_bump = 0;
488595Sbill SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){
489630Shenry tag = sp->s_tag;
490595Sbill if (tag == JXNOTYET){
491595Sbill #ifdef DEBUG
492595Sbill if (debug){
493630Shenry if (sp->s_dest != 0)
494595Sbill printf("Explode jump to %s on line %d\n",
49515234Sralph FETCHNAME(sp->s_dest), sp->s_jxline);
496595Sbill else
49715234Sralph printf("Explode an align! on line %d\n",
49815234Sralph sp->s_jxline);
499595Sbill }
500595Sbill #endif
501630Shenry sp->s_tag = JXINACTIVE;
502630Shenry sp->s_jxbump = 1;
503630Shenry cum_bump += sp->s_jxfear;
504595Sbill }
505595Sbill /*
506595Sbill * Only bump labels and jxxxes. Ignored entries can
507595Sbill * be incremented, as they are thrown away later on.
508595Sbill * Stabds are given their final value in the second
509595Sbill * pass.
510595Sbill */
511595Sbill if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/
512630Shenry sp->s_value += cum_bump;
513595Sbill }
514630Shenry usedot[segno].e_xvalue += cum_bump;
515595Sbill }
516