/* Copyright (c) 1980 Regents of the University of California */
static char sccsid
[] = "@(#)asjxxx.c 4.5 %G%";
* The number of bytes to add if the jxxx must be "exploded"
#define JBRDELTA 1 /* brb <byte> ==> brw <byte> <byte> */
#define JXXXDELTA 3 /* brb <byte> ==> brb <byte> brw <byte> <byte> */
#define JBRJDELTA d124 /* brb <byte> ==> jmp L^(pc) <byte>*d124 */
#define JXXXJDELTA d124+2 /* brb <byte> ==> brb <byte> jmp L^(pc) <byte>*d124 */
int jxxxfsize
= JXXXDELTA
;
* These variables are filled by asscan.c with the
* last name encountered (a pointer buried in the intermediate file),
* and the last jxxx symbol table entry encountered.
jbrfsize
= jxxxJUMP
? JBRJDELTA
: JBRDELTA
;
jxxxfsize
= jxxxJUMP
? JXXXJDELTA
: JXXXDELTA
;
* Note: ifjxxxJUMP is set, then we do NOT do any tunnelling;
* this was too complicated to figure out, and in the first
* version of the assembler, tunnelling proved to be the hardest
* Handle jxxx instructions
* READ THIS BEFORE LOOKING AT jxxxfix()
* Record the jxxx in a special symbol table entry
register struct symtab
*jumpfrom
;
* We assume the MINIMAL length
jumpfrom
->s_tag
= JXACTIVE
;
jumpfrom
->s_jxfear
= jbrfsize
;
jumpfrom
->s_jxfear
= jxxxfsize
;
yyerror("jxxx destination not a label");
jumpfrom
->s_dest
= lastnam
;
jumpfrom
->s_type
= dotp
->e_xtype
; /*only TEXT or DATA*/
jumpfrom
->s_index
= dotp
-usedot
;
* value ALWAYS (ALWAYS!!!) indexes the next instruction
* after the jump, even in the jump must be exploded
jumpfrom
->s_value
= dotp
->e_xvalue
;
} else {/* pass2, resolve */
* READ THIS AFTER LOOKING AT jxxxfix()
register struct symtab
*tunnel
;
register struct arg
*aplast
;
if (lastjxxx
->s_tag
== JXTUNNEL
){
lastjxxx
->s_tag
= JXINACTIVE
;
tunnel
= lastjxxx
->s_dest
;
xp
->e_xvalue
= tunnel
->s_value
/*index of instruction following*/
- 3 /* size of brw + word*/
+ ( ( (tunnel
->s_jxfear
== jbrfsize
) &&
(tunnel
->s_jxbump
== 0))?1:0);
/*non bumped branch byteis only 2 back*/
if (lastjxxx
->s_jxbump
== 0){ /*wasn't bumped, so is short form*/
if (op
!= JBR
){ /*branch reverse conditional byte over
branch unconditional word*/
xp
->e_xvalue
= lastjxxx
->s_value
;
putins(jxxxJUMP
? JMP
: BRW
, aplast
, 1);
register struct symtab
*sp
;
* When the loader constructs an executable file from
* a number of objects, it effectively concatnates
* together all of the text segments from all objects,
* and then all of the data segments.
* If we do an align by a large value, we can align
* within the a.out this assembly produces, but
* after the loader concatnates, the alignment can't
* be guaranteed if the objects preceding this one
* in the load are also aligned to the same size.
* Currently, the loader guarantees full word alignment.
* So, ridiculous aligns are caught here and converted
* to a .align 2, if possible.
if ( (xp
->e_xtype
!= XABS
)
yyerror("Illegal `align' argument");
yywarning(".align %d in any segment is NOT preserved by the loader",
yywarning(".align %d converted to .align 2",
sp
->s_jxfear
= (1 << xp
->e_xvalue
) - 1;
sp
->s_type
= dotp
->e_xtype
;
sp
->s_index
= dotp
-usedot
;
* We guess that the align will take up at least one
* byte in the code output. We will correct for this
* initial high guess when we explode (bump) aligns
* when we fix the jxxxes. We must do this guess
* so that the symbol table is sorted correctly
* and labels declared to fall before the align
* really get their, instead of guessing zero size
* and have the label (incorrectly) fall after the jxxx.
* This is a quirk of our requirement that indices into
* the code stream point to the next byte following
* the logical entry in the symbol table
sp
->s_value
= dotp
->e_xvalue
;
mask
= (1 << xp
->e_xvalue
) - 1;
while (dotp
->e_xvalue
& mask
){
* Pass 1.5, resolve jxxx instructions and .align in .text
register struct symtab
*jumpfrom
;
struct symtab
**cojumpfrom
, *ubjumpfrom
;
register struct symtab
*dest
;
register struct symtab
*intdest
; /*intermediate dest*/
register struct symtab
**cointdest
, *ubintdest
;
register struct symtab
*tunnel
;
int badjxalign
; /*if jump across an align*/
int stillactives
; /*if still active jxxxes*/
int segno
; /*current segment number*/
int topono
; /*which iteration in the topo sort*/
register unsigned char tag
;
* consider each segment in turn...
for (segno
= 0; segno
< NLOC
+ NLOC
; segno
++){
badjxalign
= 0; /*done on a per segment basis*/
* Do a lazy topological sort.
for (topono
= 1, nchange
= 1; nchange
!= 0; topono
++){
printf("\nSegment %d, topo iteration %d\n",
* We keep track of one possible tunnel location.
* A tunnel will eventually be an unconditional
* branch to the same place that another jxxx
* will want to branch to. We will turn a
* branch conditional/unconditional (word) that would
* have to get bumped because its destination is too
* far away, into a branch conditional/unconditional
* byte to the tunnel branch conditional/unconditional.
* Of course, the tunnel must branch to the same place
tunnel
= 0; /*initially, no tunnel*/
SEGITERATE(segno
, 0, 0, cojumpfrom
, jumpfrom
, ubjumpfrom
, ++){
continue; /*just an ordinary symbol*/
tunnel
= 0; /*avoid tunneling across a flex alocation*/
continue; /*we take care of these later*/
if ( jumpfrom
->s_jxfear
== jbrfsize
/*unconditional*/
|| ( tag
== JXINACTIVE
/*inactive bumped*/
&& (jumpfrom
->s_jxbump
!= 0)
if (jumpfrom
->s_index
!= dest
->s_index
){
yyerror("Intersegment jxxx");
displ
= dest
->s_value
- jumpfrom
->s_value
;
if (displ
< MINBYTE
|| displ
> MAXBYTE
) {
* This is an immediate lose!
* We first attempt to tunnel
* by finding an intervening jump that
* has the same destination.
* The tunnel is always the first preceeding
* jxxx instruction, so the displacement
* to the tunnel is less than zero, and
* its relative position will be unaffected
* by future jxxx expansions.
* No tunnels if doing jumps...
&& (jumpfrom
->s_jxfear
> jbrfsize
)
&& (tunnel
->s_dest
== jumpfrom
->s_dest
)
&& (tunnel
->s_index
== jumpfrom
->s_index
)
&& (tunnel
->s_value
- jumpfrom
->s_value
>=
jumpfrom
->s_dest
= tunnel
;
* no bumping needed, this
* is now effectively inactive
jumpfrom
->s_tag
= JXTUNNEL
;
printf("Tunnel from %s from line %d\n",
jumpfrom
->s_name
, lineno
);
} else { /*tunneling not possible*/
* since this will be turned
* into a bumped jump, we can
* use the unconditional jump
jumpfrom
->s_tag
= JXNOTYET
;
} /*end of immediate lose*/
* Do a forward search for an intervening jxxx
SEGITERATE(segno
, cojumpfrom
+ 1,0,cointdest
,
if (intdest
->s_value
> dest
->s_value
)
break; /* beyond destination */
if (intdest
->s_tag
<= JXQUESTIONABLE
)
continue; /*frozen solid*/
if (intdest
->s_tag
== JXALIGN
){
jumpfrom
->s_jxoveralign
= 1;
* we assume the worst case
displ
+= intdest
->s_jxfear
;
* the worst possible conditions
* can't hurt us, so forget about
jumpfrom
->s_tag
= JXINACTIVE
;
* backward search for intervening jxxx
SEGITERATE(segno
, cojumpfrom
- 1,1,cointdest
,
if (intdest
->s_value
<= dest
->s_value
)
break; /* beyond destination */
if (intdest
->s_tag
<= JXQUESTIONABLE
)
continue; /*frozen solid*/
if (intdest
->s_tag
== JXALIGN
){
jumpfrom
->s_jxoveralign
= 1;
displ
-= intdest
->s_jxfear
;
jumpfrom
->s_tag
= JXINACTIVE
;
} /*end of backwards search*/
} /*end of iterating through all symbols in this seg*/
* Now, if there are still active jxxx entries,
* we are partially deadlocked. We can leave
* these jxxx entries in their assumed short jump
* form, as all initial displacement calcualtions
* are hanging on unresolved jxxx instructions
* that might explode into a long form, causing
* other jxxxes jumping across the first set of
* jxxxes to explode, etc.
* However, if a jxxx jumps across a .align,
* we assume the worst for the deadlock cycle,
* and resolve all of them towards the long
* Currently, the C compiler does not produce
* jumps across aligns, as aligns are only used
* in data segments, or in text segments to align
SEGITERATE(segno
, 0, 0, cojumpfrom
, jumpfrom
,
if (jumpfrom
->s_tag
== JXACTIVE
){
badjxalign
?JXNOTYET
:JXINACTIVE
;
jxxxbump(segno
, (struct symtab
**)0);
* Handle all of the .align s
SEGITERATE(segno
, 0, 0, cojumpfrom
, jumpfrom
,
if (jumpfrom
->s_tag
== JXALIGN
){
* Predict the true displacement
* needed, irregardless of the
displ
= (jumpfrom
->s_value
- 1) & (unsigned)jumpfrom
->s_jxfear
;
if (displ
== 0){ /*no virtual displacement*/
jumpfrom
->s_jxfear
= (jumpfrom
->s_jxfear
+ 1) - displ
;
* assert jumpfrom->s_jxfear > 0
if (jumpfrom
->s_jxfear
== 1){
/*our prediction was correct*/
* assert jumpfrom->s_jxfear > 1
jumpfrom
->s_jxfear
-= 1; /*correct guess*/
* assert jumpfrom->s_jxfear = -1, +1...2**n-1
jumpfrom
->s_tag
= JXNOTYET
; /*signal*/
jxxxbump(segno
, cojumpfrom
);
jumpfrom
->s_tag
= JXINACTIVE
;
* Assert jxfrom->jxvalue indexes the first
* code byte after the added bytes, and
* has n low order zeroes.
} /*end of walking through each segment*/
else { /*changes, and still have to try another pass*/
jxxxbump(segno
, (struct symtab
**)0);
} /*end of doing the topologic sort*/
} /*end of iterating through all segments*/
* Go through the symbols in a given segment number,
* and see which entries are jxxx entries that have
* been logically "exploded" (expanded), but for which
* the value of textually following symbols has not been
jxxxbump(segno
, starthint
)
struct symtab
**starthint
;
register struct symtab
**cosp
, *sp
;
register struct symtab
*ub
;
register unsigned char tag
;
SEGITERATE(segno
, starthint
, 0, cosp
, sp
, ub
, ++){
printf("Explode jump to %s on line %d\n",
sp
->s_dest
->s_name
, lineno
);
printf("Explode an align!\n");
cum_bump
+= sp
->s_jxfear
;
* Only bump labels and jxxxes. Ignored entries can
* be incremented, as they are thrown away later on.
* Stabds are given their final value in the second
if (tag
>= OKTOBUMP
) /*only bump labels and jxxxes and floating stabs*/
usedot
[segno
].e_xvalue
+= cum_bump
;