Redesign and clean up the relaxation mechanism.

This commit is contained in:
Nick Clifton
2000-09-22 17:33:55 +00:00
parent 36bdbeeca5
commit 151337e879
2 changed files with 351 additions and 389 deletions

View File

@ -1,3 +1,9 @@
2000-09-22 Michael Sokolov <msokolov@ivan.Harhan.ORG>
* config/tc-m68k.c (md_relax_table, m68k_ip, md_convert_frag_1,
md_estimate_size_before_relax): Redesign and clean up the
relaxation mechanism.
2000-09-21 Kazu Hirata <kazu@hxi.com> 2000-09-21 Kazu Hirata <kazu@hxi.com>
* config/tc-ns32k.c: Fix formatting. * config/tc-ns32k.c: Fix formatting.

View File

@ -133,35 +133,6 @@ static struct label_line *current_label;
/* See flames below */ /* See flames below */
static struct obstack robyn; static struct obstack robyn;
#define TAB(x,y) (((x)<<2)+(y))
#define TABTYPE(xy) ((xy) >> 2)
#define BYTE 0
#define SHORT 1
#define LONG 2
#define SZ_UNDEF 3
#undef BRANCH
/* Case `g' except when BCC68000 is applicable. */
#define ABRANCH 1
/* Coprocessor branches. */
#define FBRANCH 2
/* Mode 7.2 -- program counter indirect with (16-bit) displacement,
supported on all cpus. Widens to 32-bit absolute. */
#define PCREL 3
/* For inserting an extra jmp instruction with long offset on 68000,
for expanding conditional branches. (Not bsr or bra.) Since the
68000 doesn't support 32-bit displacements for conditional
branches, we fake it by reversing the condition and branching
around a jmp with an absolute long operand. */
#define BCC68000 4
/* For the DBcc "instructions". If the displacement requires 32 bits,
the branch-around-a-jump game is played here too. */
#define DBCC 5
/* Not currently used? */
#define PCLEA 6
/* Mode AINDX (apc-relative) using PC, with variable target, might fit
in 16 or 8 bits. */
#define PCINDEX 7
struct m68k_incant struct m68k_incant
{ {
const char *m_operands; const char *m_operands;
@ -433,11 +404,60 @@ static const struct m68k_cpu archs[] = {
static const int n_archs = sizeof (archs) / sizeof (archs[0]); static const int n_archs = sizeof (archs) / sizeof (archs[0]);
/* BCC68000 is for patching in an extra jmp instruction for long offsets /* This is the assembler relaxation table for m68k. m68k is a rich CISC
on the 68000. The 68000 doesn't support long branches with branchs */ architecture and we have a lot of relaxation modes. */
/* This table desribes how you change sizes for the various types of variable /* Macros used in the relaxation code. */
size expressions. This version only supports two kinds. */ #define TAB(x,y) (((x) << 2) + (y))
#define TABTYPE(x) ((x) >> 2)
/* Relaxation states. */
#define BYTE 0
#define SHORT 1
#define LONG 2
#define SZ_UNDEF 3
/* Here are all the relaxation modes we support. First we can relax ordinary
branches. On 68020 and higher and on CPU32 all branch instructions take
three forms, so on these CPUs all branches always remain as such. When we
have to expand to the LONG form on a 68000, though, we substitute an
absolute jump instead. This is a direct replacement for unconditional
branches and a branch over a jump for conditional branches. However, if the
user requires PIC and disables this with --pcrel, we can only relax between
BYTE and SHORT forms, punting if that isn't enough. This gives us four
different relaxation modes for branches: */
#define BRANCHBWL 1 /* branch byte, word, or long */
#define BRABSJUNC 2 /* absolute jump for LONG, unconditional */
#define BRABSJCOND 3 /* absolute jump for LONG, conditional */
#define BRANCHBW 4 /* branch byte or word */
/* We also relax coprocessor branches and DBcc's. All CPUs that support
coprocessor branches support them in word and long forms, so we have only
one relaxation mode for them. DBcc's are word only on all CPUs. We can
relax them to the LONG form with a branch-around sequence. This sequence
can use a long branch (if available) or an absolute jump (if acceptable).
This gives us two relaxation modes. If long branches are not available and
absolute jumps are not acceptable, we don't relax DBcc's. */
#define FBRANCH 5 /* coprocessor branch */
#define DBCCLBR 6 /* DBcc relaxable with a long branch */
#define DBCCABSJ 7 /* DBcc relaxable with an absolute jump */
/* That's all for instruction relaxation. However, we also relax PC-relative
operands. Specifically, we have three operand relaxation modes. On the
68000 PC-relative operands can only be 16-bit, but on 68020 and higher and
on CPU32 they may be 16-bit or 32-bit. For the latter we relax between the
two. Also PC+displacement+index operands in their simple form (with a non-
suppressed index without memory indirection) are supported on all CPUs, but
on the 68000 the displacement can be 8-bit only, whereas on 68020 and higher
and on CPU32 we relax it to SHORT and LONG forms as well using the extended
form of the PC+displacement+index operand. Finally, some absolute operands
can be relaxed down to 16-bit PC-relative. */
#define PCREL1632 8 /* 16-bit or 32-bit PC-relative */
#define PCINDEX 9 /* PC+displacement+index */
#define ABSTOPCREL 10 /* absolute relax down to 16-bit PC-relative */
/* Note that calls to frag_var need to specify the maximum expansion /* Note that calls to frag_var need to specify the maximum expansion
needed; this is currently 10 bytes for DBCC. */ needed; this is currently 10 bytes for DBCC. */
@ -455,41 +475,55 @@ relax_typeS md_relax_table[] =
{1, 1, 0, 0}, /* that the VAX doesn't either */ {1, 1, 0, 0}, /* that the VAX doesn't either */
{1, 1, 0, 0}, {1, 1, 0, 0},
{(127), (-128), 0, TAB (ABRANCH, SHORT)}, {(127), (-128), 0, TAB (BRANCHBWL, SHORT)},
{(32767), (-32768), 2, TAB (ABRANCH, LONG)}, {(32767), (-32768), 2, TAB (BRANCHBWL, LONG)},
{0, 0, 4, 0}, {0, 0, 4, 0},
{1, 1, 0, 0}, {1, 1, 0, 0},
{(127), (-128), 0, TAB (BRABSJUNC, SHORT)},
{(32767), (-32768), 2, TAB (BRABSJUNC, LONG)},
{0, 0, 4, 0},
{1, 1, 0, 0},
{(127), (-128), 0, TAB (BRABSJCOND, SHORT)},
{(32767), (-32768), 2, TAB (BRABSJCOND, LONG)},
{0, 0, 6, 0},
{1, 1, 0, 0},
{(127), (-128), 0, TAB (BRANCHBW, SHORT)},
{0, 0, 2, 0},
{1, 1, 0, 0},
{1, 1, 0, 0},
{1, 1, 0, 0}, /* FBRANCH doesn't come BYTE */ {1, 1, 0, 0}, /* FBRANCH doesn't come BYTE */
{(32767), (-32768), 2, TAB (FBRANCH, LONG)}, {(32767), (-32768), 2, TAB (FBRANCH, LONG)},
{0, 0, 4, 0}, {0, 0, 4, 0},
{1, 1, 0, 0}, {1, 1, 0, 0},
{1, 1, 0, 0}, /* PCREL doesn't come BYTE */ {1, 1, 0, 0}, /* DBCC doesn't come BYTE */
{(32767), (-32768), 2, TAB (PCREL, LONG)}, {(32767), (-32768), 2, TAB (DBCCLBR, LONG)},
{0, 0, 4, 0}, {0, 0, 10, 0},
{1, 1, 0, 0},
{(127), (-128), 0, TAB (BCC68000, SHORT)},
{(32767), (-32768), 2, TAB (BCC68000, LONG)},
{0, 0, 6, 0}, /* jmp long space */
{1, 1, 0, 0}, {1, 1, 0, 0},
{1, 1, 0, 0}, /* DBCC doesn't come BYTE */ {1, 1, 0, 0}, /* DBCC doesn't come BYTE */
{(32767), (-32768), 2, TAB (DBCC, LONG)}, {(32767), (-32768), 2, TAB (DBCCABSJ, LONG)},
{0, 0, 10, 0}, /* bra/jmp long space */ {0, 0, 10, 0},
{1, 1, 0, 0}, {1, 1, 0, 0},
{1, 1, 0, 0}, /* PCLEA doesn't come BYTE */ {1, 1, 0, 0}, /* PCREL1632 doesn't come BYTE */
{32767, -32768, 2, TAB (PCLEA, LONG)}, {32767, -32768, 2, TAB (PCREL1632, LONG)},
{0, 0, 6, 0}, {0, 0, 6, 0},
{1, 1, 0, 0}, {1, 1, 0, 0},
/* For, e.g., jmp pcrel indexed. */
{125, -130, 0, TAB (PCINDEX, SHORT)}, {125, -130, 0, TAB (PCINDEX, SHORT)},
{32765, -32770, 2, TAB (PCINDEX, LONG)}, {32765, -32770, 2, TAB (PCINDEX, LONG)},
{0, 0, 4, 0}, {0, 0, 4, 0},
{1, 1, 0, 0}, {1, 1, 0, 0},
{1, 1, 0, 0}, /* ABSTOPCREL doesn't come BYTE */
{(32767), (-32768), 2, TAB (ABSTOPCREL, LONG)},
{0, 0, 4, 0},
{1, 1, 0, 0},
}; };
/* These are the machine dependent pseudo-ops. These are included so /* These are the machine dependent pseudo-ops. These are included so
@ -2064,7 +2098,7 @@ m68k_ip (instring)
{ {
add_frag (adds (&opP->disp), add_frag (adds (&opP->disp),
offs (&opP->disp), offs (&opP->disp),
TAB (PCLEA, SZ_UNDEF)); TAB (PCREL1632, SZ_UNDEF));
break; break;
} }
} }
@ -2372,15 +2406,13 @@ m68k_ip (instring)
cannot be relaxed. */ cannot be relaxed. */
&& opP->disp.pic_reloc == pic_none && opP->disp.pic_reloc == pic_none
#endif #endif
&& S_GET_SEGMENT (adds (&opP->disp)) == now_seg
&& relaxable_symbol (adds (&opP->disp))
&& !flag_long_jumps && !flag_long_jumps
&& !strchr ("~%&$?", s[0])) && !strchr ("~%&$?", s[0]))
{ {
tmpreg = 0x3A; /* 7.2 */ tmpreg = 0x3A; /* 7.2 */
add_frag (adds (&opP->disp), add_frag (adds (&opP->disp),
offs (&opP->disp), offs (&opP->disp),
TAB (PCREL, SZ_UNDEF)); TAB (ABSTOPCREL, SZ_UNDEF));
break; break;
} }
/* Fall through into long */ /* Fall through into long */
@ -2512,9 +2544,9 @@ m68k_ip (instring)
break; break;
case 'L': case 'L':
long_branch: long_branch:
if (!HAVE_LONG_BRANCH(current_architecture)) if (! HAVE_LONG_BRANCH (current_architecture))
as_warn (_("Can't use long branches on 68000/68010/5200")); as_warn (_("Can't use long branches on 68000/68010/5200"));
the_ins.opcode[the_ins.numo - 1] |= 0xff; the_ins.opcode[0] |= 0xff;
add_fix ('l', &opP->disp, 1, 0); add_fix ('l', &opP->disp, 1, 0);
addword (0); addword (0);
addword (0); addword (0);
@ -2529,37 +2561,66 @@ m68k_ip (instring)
if (opP->disp.pic_reloc != pic_none) if (opP->disp.pic_reloc != pic_none)
goto long_branch; goto long_branch;
#endif #endif
/* This could either be a symbol, or an absolute /* This could either be a symbol, or an absolute
address. No matter, the frag hacking will finger it address. If it's an absolute address, turn it into
out. Not quite: it can't switch from BRANCH to an absolute jump right here and keep it out of the
BCC68000 for the case where opnd is absolute (it relaxer. */
needs to use the 68000 hack since no conditional abs if (adds (&opP->disp) == 0)
jumps). */ {
if (( !HAVE_LONG_BRANCH(current_architecture) if (the_ins.opcode[0] == 0x6000) /* jbra */
|| (0 == adds (&opP->disp))) the_ins.opcode[0] = 0x4EF1;
&& (the_ins.opcode[0] >= 0x6200) else if (the_ins.opcode[0] == 0x6100) /* jbsr */
&& (the_ins.opcode[0] <= 0x6f00)) the_ins.opcode[0] = 0x4EB1;
else /* jCC */
{
the_ins.opcode[0] ^= 0x0100;
the_ins.opcode[0] |= 0x0006;
addword (0x4EF1);
}
add_fix ('l', &opP->disp, 0, 0);
addword (0);
addword (0);
break;
}
/* Now we know it's going into the relaxer. Now figure
out which mode. We try in this order of preference:
long branch, absolute jump, byte/word branches only. */
if (HAVE_LONG_BRANCH (current_architecture))
add_frag (adds (&opP->disp), offs (&opP->disp), add_frag (adds (&opP->disp), offs (&opP->disp),
TAB (BCC68000, SZ_UNDEF)); TAB (BRANCHBWL, SZ_UNDEF));
else if (! flag_keep_pcrel)
{
if ((the_ins.opcode[0] == 0x6000)
|| (the_ins.opcode[0] == 0x6100))
add_frag (adds (&opP->disp), offs (&opP->disp),
TAB (BRABSJUNC, SZ_UNDEF));
else
add_frag (adds (&opP->disp), offs (&opP->disp),
TAB (BRABSJCOND, SZ_UNDEF));
}
else else
add_frag (adds (&opP->disp), offs (&opP->disp), add_frag (adds (&opP->disp), offs (&opP->disp),
TAB (ABRANCH, SZ_UNDEF)); TAB (BRANCHBW, SZ_UNDEF));
break; break;
case 'w': case 'w':
if (isvar (&opP->disp)) if (isvar (&opP->disp))
{ {
#if 1 /* Check for DBcc instructions. We can relax them,
/* check for DBcc instruction */ but only if we have long branches and/or absolute
if ((the_ins.opcode[0] & 0xf0f8) == 0x50c8) jumps. */
if (((the_ins.opcode[0] & 0xf0f8) == 0x50c8)
&& (HAVE_LONG_BRANCH (current_architecture)
|| (! flag_keep_pcrel)))
{ {
/* size varies if patch */ if (HAVE_LONG_BRANCH (current_architecture))
/* needed for long form */ add_frag (adds (&opP->disp), offs (&opP->disp),
add_frag (adds (&opP->disp), offs (&opP->disp), TAB (DBCCLBR, SZ_UNDEF));
TAB (DBCC, SZ_UNDEF)); else
add_frag (adds (&opP->disp), offs (&opP->disp),
TAB (DBCCABSJ, SZ_UNDEF));
break; break;
} }
#endif
add_fix ('w', &opP->disp, 1, 0); add_fix ('w', &opP->disp, 1, 0);
} }
addword (0); addword (0);
@ -2570,23 +2631,16 @@ m68k_ip (instring)
addword (0); addword (0);
break; break;
case 'c': /* Var size Coprocesssor branches */ case 'c': /* Var size Coprocesssor branches */
if (subs (&opP->disp)) if (subs (&opP->disp) || (adds (&opP->disp) == 0))
{ {
add_fix ('l', &opP->disp, 1, 0);
add_frag ((symbolS *) 0, (offsetT) 0, TAB (FBRANCH, LONG));
}
else if (adds (&opP->disp))
add_frag (adds (&opP->disp), offs (&opP->disp),
TAB (FBRANCH, SZ_UNDEF));
else
{
/* add_frag ((symbolS *) 0, offs (&opP->disp),
TAB(FBRANCH,SHORT)); */
the_ins.opcode[the_ins.numo - 1] |= 0x40; the_ins.opcode[the_ins.numo - 1] |= 0x40;
add_fix ('l', &opP->disp, 1, 0); add_fix ('l', &opP->disp, 1, 0);
addword (0); addword (0);
addword (0); addword (0);
} }
else
add_frag (adds (&opP->disp), offs (&opP->disp),
TAB (FBRANCH, SZ_UNDEF));
break; break;
default: default:
abort (); abort ();
@ -4275,7 +4329,6 @@ md_convert_frag_1 (fragP)
register fragS *fragP; register fragS *fragP;
{ {
long disp; long disp;
long ext = 0;
fixS *fixP; fixS *fixP;
/* Address in object code of the displacement. */ /* Address in object code of the displacement. */
@ -4298,76 +4351,59 @@ md_convert_frag_1 (fragP)
switch (fragP->fr_subtype) switch (fragP->fr_subtype)
{ {
case TAB (BCC68000, BYTE): case TAB (BRANCHBWL, BYTE):
case TAB (ABRANCH, BYTE): case TAB (BRABSJUNC, BYTE):
case TAB (BRABSJCOND, BYTE):
case TAB (BRANCHBW, BYTE):
know (issbyte (disp)); know (issbyte (disp));
if (disp == 0) if (disp == 0)
as_bad (_("short branch with zero offset: use :w")); as_bad (_("short branch with zero offset: use :w"));
fragP->fr_opcode[1] = disp; fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol,
ext = 0; fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
fixP->fx_pcrel_adjust = -1;
break; break;
case TAB (DBCC, SHORT): case TAB (BRANCHBWL, SHORT):
know (issword (disp)); case TAB (BRABSJUNC, SHORT):
ext = 2; case TAB (BRABSJCOND, SHORT):
break; case TAB (BRANCHBW, SHORT):
case TAB (BCC68000, SHORT):
case TAB (ABRANCH, SHORT):
know (issword (disp));
fragP->fr_opcode[1] = 0x00; fragP->fr_opcode[1] = 0x00;
ext = 2; fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, BFD_RELOC_16_PCREL);
fragP->fr_fix += 2;
break; break;
case TAB (ABRANCH, LONG): case TAB (BRANCHBWL, LONG):
if (!HAVE_LONG_BRANCH (current_architecture)) fragP->fr_opcode[1] = (char) 0xFF;
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
1, BFD_RELOC_32_PCREL);
fragP->fr_fix += 4;
break;
case TAB (BRABSJUNC, LONG):
if (fragP->fr_opcode[0] == 0x61) /* jbsr */
{ {
if (flag_keep_pcrel) fragP->fr_opcode[0] = 0x4E;
as_bad (_("long branch not supported")); fragP->fr_opcode[1] = (char) 0xB9; /* JSR with ABSL LONG operand */
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
if (fragP->fr_opcode[0] == 0x61) 0, BFD_RELOC_32);
/* BSR */ fragP->fr_fix += 4;
{ }
fragP->fr_opcode[0] = 0x4E; else if (fragP->fr_opcode[0] == 0x60) /* jbra */
fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */ {
fragP->fr_opcode[0] = 0x4E;
fix_new (fragP, fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG operand */
fragP->fr_fix, fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
4, 0, BFD_RELOC_32);
fragP->fr_symbol, fragP->fr_fix += 4;
fragP->fr_offset,
0,
NO_RELOC);
fragP->fr_fix += 4;
ext = 0;
}
/* BRA */
else if (fragP->fr_opcode[0] == 0x60)
{
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG offset */
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
ext = 0;
}
else
{
/* This should never happen, because if it's a conditional
branch and we are on a 68000, BCC68000 should have been
picked instead of ABRANCH. */
abort ();
}
} }
else else
{ {
fragP->fr_opcode[1] = (char) 0xff; /* This cannot happen, because jbsr and jbra are the only two
ext = 4; unconditional branches. */
abort ();
} }
break; break;
case TAB (BCC68000, LONG): case TAB (BRABSJCOND, LONG):
/* only Bcc 68000 instructions can come here */ /* Only Bcc 68000 instructions can come here. */
/* change bcc into b!cc/jmp absl long */ /* Change bcc into b!cc/jmp absl long. */
if (flag_keep_pcrel)
as_bad (_("long branch not supported"));
fragP->fr_opcode[0] ^= 0x01; /* invert bcc */ fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
fragP->fr_opcode[1] = 0x6;/* branch offset = 6 */ fragP->fr_opcode[1] = 0x6;/* branch offset = 6 */
@ -4379,125 +4415,120 @@ md_convert_frag_1 (fragP)
*buffer_address++ = (char) 0xf9; *buffer_address++ = (char) 0xf9;
fragP->fr_fix += 2; /* account for jmp instruction */ fragP->fr_fix += 2; /* account for jmp instruction */
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC); fragP->fr_offset, 0, BFD_RELOC_32);
fragP->fr_fix += 4; fragP->fr_fix += 4;
ext = 0;
break; break;
case TAB (DBCC, LONG): case TAB (FBRANCH, SHORT):
/* only DBcc 68000 instructions can come here */ know ((fragP->fr_opcode[1] & 0x40) == 0);
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, BFD_RELOC_16_PCREL);
fragP->fr_fix += 2;
break;
case TAB (FBRANCH, LONG):
fragP->fr_opcode[1] |= 0x40; /* Turn on LONG bit */
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
1, BFD_RELOC_32_PCREL);
fragP->fr_fix += 4;
break;
case TAB (DBCCLBR, SHORT):
case TAB (DBCCABSJ, SHORT):
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, BFD_RELOC_16_PCREL);
fragP->fr_fix += 2;
break;
case TAB (DBCCLBR, LONG):
/* only DBcc instructions can come here */
/* Change dbcc into dbcc/bral. */ /* Change dbcc into dbcc/bral. */
if (! HAVE_LONG_BRANCH (current_architecture) && flag_keep_pcrel)
as_bad (_("long branch not supported"));
/* JF: these used to be fr_opcode[2-7], but that's wrong */ /* JF: these used to be fr_opcode[2-7], but that's wrong */
*buffer_address++ = 0x00; /* branch offset = 4 */ *buffer_address++ = 0x00; /* branch offset = 4 */
*buffer_address++ = 0x04; *buffer_address++ = 0x04;
*buffer_address++ = 0x60; /* put in bra pc+6 */ *buffer_address++ = 0x60; /* put in bra pc+6 */
*buffer_address++ = 0x06; *buffer_address++ = 0x06;
if (HAVE_LONG_BRANCH (current_architecture)) *buffer_address++ = 0x60; /* Put in bral (0x60ff). */
{ *buffer_address++ = (char) 0xff;
*buffer_address++ = 0x60; /* Put in bral (0x60ff). */
*buffer_address++ = (char) 0xff;
}
else
{
*buffer_address++ = 0x4e; /* Put in jmp long (0x4ef9). */
*buffer_address++ = (char) 0xf9;
}
fragP->fr_fix += 6; /* account for bra/jmp instructions */ fragP->fr_fix += 6; /* account for bra/jmp instructions */
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 1,
fragP->fr_offset, HAVE_LONG_BRANCH (current_architecture), BFD_RELOC_32_PCREL);
NO_RELOC);
fragP->fr_fix += 4; fragP->fr_fix += 4;
ext = 0;
break; break;
case TAB (FBRANCH, SHORT): case TAB (DBCCABSJ, LONG):
know ((fragP->fr_opcode[1] & 0x40) == 0); /* only DBcc instructions can come here */
ext = 2; /* Change dbcc into dbcc/jmp. */
break;
case TAB (FBRANCH, LONG): /* JF: these used to be fr_opcode[2-7], but that's wrong */
fragP->fr_opcode[1] |= 0x40; /* Turn on LONG bit */ *buffer_address++ = 0x00; /* branch offset = 4 */
ext = 4; *buffer_address++ = 0x04;
break; *buffer_address++ = 0x60; /* put in bra pc+6 */
case TAB (PCREL, SHORT): *buffer_address++ = 0x06;
ext = 2; *buffer_address++ = 0x4e; /* Put in jmp long (0x4ef9). */
break; *buffer_address++ = (char) 0xf9;
case TAB (PCREL, LONG):
/* The thing to do here is force it to ABSOLUTE LONG, since fragP->fr_fix += 6; /* account for bra/jmp instructions */
PCREL is really trying to shorten an ABSOLUTE address anyway */ fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset, 0,
/* JF FOO This code has not been tested */ BFD_RELOC_32);
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
0, NO_RELOC);
if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
as_bad (_("Internal error (long PC-relative operand) for insn 0x%04x at 0x%lx"),
(unsigned) fragP->fr_opcode[0],
(unsigned long) fragP->fr_address);
fragP->fr_opcode[1] &= ~0x3F;
fragP->fr_opcode[1] |= 0x39; /* Mode 7.1 */
fragP->fr_fix += 4; fragP->fr_fix += 4;
ext = 0;
break; break;
case TAB (PCLEA, SHORT): case TAB (PCREL1632, SHORT):
fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
fragP->fr_opcode[1] &= ~0x3F; fragP->fr_opcode[1] &= ~0x3F;
fragP->fr_opcode[1] |= 0x3A; /* 072 - mode 7.2 */ fragP->fr_opcode[1] |= 0x3A; /* 072 - mode 7.2 */
ext = 2; fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
fragP->fr_fix += 2;
break; break;
case TAB (PCLEA, LONG): case TAB (PCREL1632, LONG):
fixP = fix_new (fragP, (int) (fragP->fr_fix) + 2, 4, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
fixP->fx_pcrel_adjust = 2;
/* Already set to mode 7.3; this indicates: PC indirect with /* Already set to mode 7.3; this indicates: PC indirect with
suppressed index, 32-bit displacement. */ suppressed index, 32-bit displacement. */
*buffer_address++ = 0x01; *buffer_address++ = 0x01;
*buffer_address++ = 0x70; *buffer_address++ = 0x70;
fragP->fr_fix += 2; fragP->fr_fix += 2;
ext = 4; fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
fragP->fr_offset, 1, BFD_RELOC_32_PCREL);
fixP->fx_pcrel_adjust = 2;
fragP->fr_fix += 4;
break; break;
case TAB (PCINDEX, BYTE): case TAB (PCINDEX, BYTE):
disp += 2;
if (!issbyte (disp))
{
as_bad (_("displacement doesn't fit in one byte"));
disp = 0;
}
assert (fragP->fr_fix >= 2); assert (fragP->fr_fix >= 2);
buffer_address[-2] &= ~1; buffer_address[-2] &= ~1;
buffer_address[-1] = disp; fixP = fix_new (fragP, fragP->fr_fix - 1, 1, fragP->fr_symbol,
ext = 0; fragP->fr_offset, 1, BFD_RELOC_8_PCREL);
fixP->fx_pcrel_adjust = 1;
break; break;
case TAB (PCINDEX, SHORT): case TAB (PCINDEX, SHORT):
disp += 2;
assert (issword (disp));
assert (fragP->fr_fix >= 2); assert (fragP->fr_fix >= 2);
buffer_address[-2] |= 0x1; buffer_address[-2] |= 0x1;
buffer_address[-1] = 0x20; buffer_address[-1] = 0x20;
fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol, fixP = fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073, fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
NO_RELOC);
fixP->fx_pcrel_adjust = 2; fixP->fx_pcrel_adjust = 2;
ext = 2; fragP->fr_fix += 2;
break; break;
case TAB (PCINDEX, LONG): case TAB (PCINDEX, LONG):
disp += 2;
fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
fragP->fr_offset, (fragP->fr_opcode[1] & 077) == 073,
NO_RELOC);
fixP->fx_pcrel_adjust = 2;
assert (fragP->fr_fix >= 2); assert (fragP->fr_fix >= 2);
buffer_address[-2] |= 0x1; buffer_address[-2] |= 0x1;
buffer_address[-1] = 0x30; buffer_address[-1] = 0x30;
ext = 4; fixP = fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol,
fragP->fr_offset, 1, BFD_RELOC_32_PCREL);
fixP->fx_pcrel_adjust = 2;
fragP->fr_fix += 4;
break;
case TAB (ABSTOPCREL, SHORT):
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, BFD_RELOC_16_PCREL);
fragP->fr_fix += 2;
break;
case TAB (ABSTOPCREL, LONG):
/* The thing to do here is force it to ABSOLUTE LONG, since
ABSTOPCREL is really trying to shorten an ABSOLUTE address anyway */
if ((fragP->fr_opcode[1] & 0x3F) != 0x3A)
abort ();
fragP->fr_opcode[1] &= ~0x3F;
fragP->fr_opcode[1] |= 0x39; /* Mode 7.1 */
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_offset,
0, BFD_RELOC_32);
fragP->fr_fix += 4;
break; break;
}
if (ext)
{
md_number_to_chars (buffer_address, (long) disp, (int) ext);
fragP->fr_fix += ext;
} }
} }
@ -4537,70 +4568,69 @@ md_estimate_size_before_relax (fragP, segment)
old_fix = fragP->fr_fix; old_fix = fragP->fr_fix;
/* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */ /* Handle SZ_UNDEF first, it can be changed to BYTE or SHORT. */
switch (fragP->fr_subtype) switch (fragP->fr_subtype)
{ {
case TAB (BRANCHBWL, SZ_UNDEF):
case TAB (ABRANCH, SZ_UNDEF): case TAB (BRABSJUNC, SZ_UNDEF):
{ {
if ((fragP->fr_symbol != NULL) /* Not absolute */ if (S_GET_SEGMENT (fragP->fr_symbol) == segment
&& S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol)) && relaxable_symbol (fragP->fr_symbol))
{ {
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE); fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
break;
} }
else if ((fragP->fr_symbol != NULL) else if (flag_short_refs)
&& (flag_short_refs || flag_keep_pcrel))
{ /* Symbol is undefined and we want short ref */
fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
fragP->fr_fix += 2;
frag_wane (fragP);
break;
}
else if ((fragP->fr_symbol == 0) || !HAVE_LONG_BRANCH(current_architecture))
{ {
/* On 68000, or for absolute value, switch to abs long */ /* Symbol is undefined and we want short ref. */
/* FIXME, we should check abs val, pick short or long */ fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
if (fragP->fr_opcode[0] == 0x61) fragP->fr_var += 2;
{
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = (char) 0xB9; /* JBSR with ABSL LONG offset */
fix_new (fragP, fragP->fr_fix, 4,
fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
frag_wane (fragP);
}
else if (fragP->fr_opcode[0] == 0x60)
{
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = (char) 0xF9; /* JMP with ABSL LONG offset */
fix_new (fragP, fragP->fr_fix, 4,
fragP->fr_symbol, fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
frag_wane (fragP);
}
else
{
/* This should never happen, because if it's a conditional
branch and we are on a 68000, BCC68000 should have been
picked instead of ABRANCH. */
abort ();
}
} }
else else
{ /* Symbol is still undefined. Make it simple */ {
fix_new (fragP, (int) (fragP->fr_fix), 4, fragP->fr_symbol, /* Symbol is still undefined. Make it LONG. */
fragP->fr_offset, 1, NO_RELOC); fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), LONG);
fragP->fr_fix += 4; fragP->fr_var += 4;
fragP->fr_opcode[1] = (char) 0xff;
frag_wane (fragP);
break;
} }
break; break;
} /* case TAB(ABRANCH,SZ_UNDEF) */ }
case TAB (BRABSJCOND, SZ_UNDEF):
{
if (S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol))
{
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
}
else if (flag_short_refs)
{
/* Symbol is undefined and we want short ref. */
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
fragP->fr_var += 2;
}
else
{
/* Symbol is still undefined. Make it LONG. */
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), LONG);
fragP->fr_var += 6;
}
break;
}
case TAB (BRANCHBW, SZ_UNDEF):
{
if (S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol))
{
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
}
else
{
/* Symbol is undefined and we don't have long branches. */
fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
fragP->fr_var += 2;
}
break;
}
case TAB (FBRANCH, SZ_UNDEF): case TAB (FBRANCH, SZ_UNDEF):
{ {
@ -4613,142 +4643,50 @@ md_estimate_size_before_relax (fragP, segment)
} }
else else
{ {
fix_new (fragP, (int) fragP->fr_fix, 4, fragP->fr_symbol, fragP->fr_subtype = TAB (FBRANCH, LONG);
fragP->fr_offset, 1, NO_RELOC);
fragP->fr_fix += 4;
fragP->fr_opcode[1] |= 0x40; /* Turn on LONG bit */
frag_wane (fragP);
}
break;
} /* TAB(FBRANCH,SZ_UNDEF) */
case TAB (PCREL, SZ_UNDEF):
{
if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol))
|| flag_short_refs)
{
fragP->fr_subtype = TAB (PCREL, SHORT);
fragP->fr_var += 2;
}
else
{
fragP->fr_subtype = TAB (PCREL, LONG);
fragP->fr_var += 4; fragP->fr_var += 4;
} }
break; break;
} /* TAB(PCREL,SZ_UNDEF) */ }
case TAB (BCC68000, SZ_UNDEF): case TAB (DBCCLBR, SZ_UNDEF):
case TAB (DBCCABSJ, SZ_UNDEF):
{ {
if ((fragP->fr_symbol != NULL) if (S_GET_SEGMENT (fragP->fr_symbol) == segment
&& S_GET_SEGMENT (fragP->fr_symbol) == segment && relaxable_symbol (fragP->fr_symbol)
&& relaxable_symbol (fragP->fr_symbol)) || flag_short_refs)
{ {
fragP->fr_subtype = TAB (BCC68000, BYTE); fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
break;
}
/* only Bcc 68000 instructions can come here */
if ((fragP->fr_symbol != NULL) && (flag_short_refs || flag_keep_pcrel))
{
/* the user wants short refs, so emit one */
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
fragP->fr_fix += 2;
}
else
{
/* change bcc into b!cc/jmp absl long */
fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
fragP->fr_opcode[1] = 0x06; /* branch offset = 6 */
/* JF: these were fr_opcode[2,3] */
buffer_address[0] = 0x4e; /* put in jmp long (0x4ef9) */
buffer_address[1] = (char) 0xf9;
fragP->fr_fix += 2; /* account for jmp instruction */
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, 0, NO_RELOC);
fragP->fr_fix += 4;
}
frag_wane (fragP);
break;
} /* case TAB(BCC68000,SZ_UNDEF) */
case TAB (DBCC, SZ_UNDEF):
{
if (fragP->fr_symbol != NULL
&& S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol))
{
fragP->fr_subtype = TAB (DBCC, SHORT);
fragP->fr_var += 2; fragP->fr_var += 2;
break;
}
/* only DBcc 68000 instructions can come here */
if (fragP->fr_symbol != NULL
&& (flag_short_refs
|| (! HAVE_LONG_BRANCH (current_architecture)
&& flag_keep_pcrel)))
{
/* the user wants short refs, so emit one */
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
fragP->fr_offset, 1, NO_RELOC);
fragP->fr_fix += 2;
} }
else else
{ {
/* Change dbcc into dbcc/bral. */ fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), LONG);
/* JF: these used to be fr_opcode[2-4], which is wrong. */ fragP->fr_var += 10;
buffer_address[0] = 0x00; /* branch offset = 4 */
buffer_address[1] = 0x04;
buffer_address[2] = 0x60; /* put in bra pc + ... */
/* JF: these were fr_opcode[5-7] */
buffer_address[3] = 0x06; /* Plus 6 */
if (HAVE_LONG_BRANCH (current_architecture))
{
buffer_address[4] = 0x60; /* Put in bral (0x60ff). */
buffer_address[5] = (char) 0xff;
}
else
{
buffer_address[4] = 0x4e; /* Put in jmp long (0x4ef9). */
buffer_address[5] = (char) 0xf9;
}
fragP->fr_fix += 6; /* account for bra/jmp instruction */
fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol,
fragP->fr_offset, HAVE_LONG_BRANCH (current_architecture),
NO_RELOC);
fragP->fr_fix += 4;
} }
frag_wane (fragP);
break; break;
} /* case TAB(DBCC,SZ_UNDEF) */ }
case TAB (PCLEA, SZ_UNDEF): case TAB (PCREL1632, SZ_UNDEF):
{ {
if (((S_GET_SEGMENT (fragP->fr_symbol)) == segment if (((S_GET_SEGMENT (fragP->fr_symbol)) == segment
&& relaxable_symbol (fragP->fr_symbol)) && relaxable_symbol (fragP->fr_symbol))
|| flag_short_refs || flag_short_refs)
|| cpu_of_arch (current_architecture) < m68020
|| cpu_of_arch (current_architecture) == mcf5200)
{ {
fragP->fr_subtype = TAB (PCLEA, SHORT); fragP->fr_subtype = TAB (PCREL1632, SHORT);
fragP->fr_var += 2; fragP->fr_var += 2;
} }
else else
{ {
fragP->fr_subtype = TAB (PCLEA, LONG); fragP->fr_subtype = TAB (PCREL1632, LONG);
fragP->fr_var += 6; fragP->fr_var += 6;
} }
break; break;
} /* TAB(PCLEA,SZ_UNDEF) */ }
case TAB (PCINDEX, SZ_UNDEF): case TAB (PCINDEX, SZ_UNDEF):
if ((S_GET_SEGMENT (fragP->fr_symbol) == segment if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol)) && relaxable_symbol (fragP->fr_symbol)))
|| cpu_of_arch (current_architecture) < m68020
|| cpu_of_arch (current_architecture) == mcf5200)
{ {
fragP->fr_subtype = TAB (PCINDEX, BYTE); fragP->fr_subtype = TAB (PCINDEX, BYTE);
} }
@ -4759,15 +4697,33 @@ md_estimate_size_before_relax (fragP, segment)
} }
break; break;
case TAB (ABSTOPCREL, SZ_UNDEF):
{
if ((S_GET_SEGMENT (fragP->fr_symbol) == segment
&& relaxable_symbol (fragP->fr_symbol)))
{
fragP->fr_subtype = TAB (ABSTOPCREL, SHORT);
fragP->fr_var += 2;
}
else
{
fragP->fr_subtype = TAB (ABSTOPCREL, LONG);
fragP->fr_var += 4;
}
break;
}
default: default:
break; break;
} }
/* now that SZ_UNDEF are taken care of, check others */ /* Now that SZ_UNDEF are taken care of, check others. */
switch (fragP->fr_subtype) switch (fragP->fr_subtype)
{ {
case TAB (BCC68000, BYTE): case TAB (BRANCHBWL, BYTE):
case TAB (ABRANCH, BYTE): case TAB (BRABSJUNC, BYTE):
case TAB (BRABSJCOND, BYTE):
case TAB (BRANCHBW, BYTE):
/* We can't do a short jump to the next instruction, so in that /* We can't do a short jump to the next instruction, so in that
case we force word mode. At this point S_GET_VALUE should case we force word mode. At this point S_GET_VALUE should
return the offset of the symbol within its frag. If the return the offset of the symbol within its frag. If the