aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorJoern Rennecke <joern.rennecke@embecosm.com>1998-07-01 20:42:42 +0000
committerJoern Rennecke <joern.rennecke@embecosm.com>1998-07-01 20:42:42 +0000
commitd1a7caf90137bd08d3830d69ca5a455661af0883 (patch)
treee67c40d7386d07203897d56e237e55703b039bd3 /gas
parentf3b86a30f914d3a74e4f167bd4a97170f21a9776 (diff)
downloadgdb-d1a7caf90137bd08d3830d69ca5a455661af0883.zip
gdb-d1a7caf90137bd08d3830d69ca5a455661af0883.tar.gz
gdb-d1a7caf90137bd08d3830d69ca5a455661af0883.tar.bz2
I found that the relax failure for execute/930628-1.c is due to gas
incorrectly relaxing an out-of-range conditional branch with delay slot. It turned: bf.s L6 (slot mov.l r12,@(44,r0)) into: 2c: 8f 01 a0 8b bf.s 32 <_main+32> (slot bra L6) 30: 00 09 nop 32: 10 cb mov.l r12,@(44,r0) * config/tc-sh (COND_JUMP_DELAY, COND12_DELAY_LENGTH): Define. Changed all users of COND12_DELAY.
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-sh.c179
1 files changed, 107 insertions, 72 deletions
diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c
index 563b641..124dc7b 100644
--- a/gas/config/tc-sh.c
+++ b/gas/config/tc-sh.c
@@ -1,5 +1,5 @@
/* tc-sh.c -- Assemble code for the Hitachi Super-H
- Copyright (C) 1993, 94, 95, 96, 1997, 1998 Free Software Foundation.
+ Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation.
This file is part of GAS, the GNU Assembler.
@@ -97,9 +97,11 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
#define ENCODE_RELAX(what,length) (((what) << 4) + (length))
#define GET_WHAT(x) ((x>>4))
-/* These are the two types of relaxable instrction */
+/* These are the three types of relaxable instrction */
#define COND_JUMP 1
-#define UNCOND_JUMP 2
+#define COND_JUMP_DELAY 2
+#define UNCOND_JUMP 3
+#define END 4
#define UNDEF_DISP 0
#define COND8 1
@@ -108,7 +110,6 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
#define UNCOND12 1
#define UNCOND32 2
#define UNDEF_WORD_DISP 4
-#define END 5
#define UNCOND12 1
#define UNCOND32 2
@@ -125,6 +126,8 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
#define COND12_M -4090
#define COND12_LENGTH 6
+#define COND12_DELAY_LENGTH 4
+
/* ??? The minimum and maximum values are wrong, but this does not matter
since this relocation type is not supported yet. */
#define COND32_F (1<<30)
@@ -156,6 +159,16 @@ const relax_typeS md_relax_table[C (END, 0)] = {
{ 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
{ 0 },
+ /* C (COND_JUMP_DELAY, COND8) */
+ { COND8_F, COND8_M, COND8_LENGTH, C (COND_JUMP_DELAY, COND12) },
+ /* C (COND_JUMP_DELAY, COND12) */
+ { COND12_F, COND12_M, COND12_DELAY_LENGTH, C (COND_JUMP_DELAY, COND32), },
+ /* C (COND_JUMP_DELAY, COND32) */
+ { COND32_F, COND32_M, COND32_LENGTH, 0, },
+ { 0 }, { 0 }, { 0 }, { 0 },
+ { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 },
+
+ { 0 },
/* C (UNCOND_JUMP, UNCOND12) */
{ UNCOND12_F, UNCOND12_M, UNCOND12_LENGTH, C (UNCOND_JUMP, UNCOND32), },
/* C (UNCOND_JUMP, UNCOND32) */
@@ -227,7 +240,7 @@ parse_reg (src, mode, reg)
if (src[0] == 'r')
{
if (src[1] >= '0' && src[1] <= '7' && strncmp(&src[2], "_bank", 5) == 0
- && ! isalnum (src[7]))
+ && ! isalnum ((unsigned char) src[7]))
{
*mode = A_REG_B;
*reg = (src[1] - '0');
@@ -239,14 +252,16 @@ parse_reg (src, mode, reg)
{
if (src[1] == '1')
{
- if (src[2] >= '0' && src[2] <= '5' && ! isalnum (src[3]))
+ if (src[2] >= '0' && src[2] <= '5'
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = A_REG_N;
*reg = 10 + src[2] - '0';
return 3;
}
}
- if (src[1] >= '0' && src[1] <= '9' && ! isalnum (src[2]))
+ if (src[1] >= '0' && src[1] <= '9'
+ && ! isalnum ((unsigned char) src[2]))
{
*mode = A_REG_N;
*reg = (src[1] - '0');
@@ -254,65 +269,73 @@ parse_reg (src, mode, reg)
}
}
- if (src[0] == 's' && src[1] == 's' && src[2] == 'r' && ! isalnum (src[3]))
+ if (src[0] == 's'
+ && src[1] == 's'
+ && src[2] == 'r' && ! isalnum ((unsigned char) src[3]))
{
*mode = A_SSR;
return 3;
}
- if (src[0] == 's' && src[1] == 'p' && src[2] == 'c' && ! isalnum (src[3]))
+ if (src[0] == 's' && src[1] == 'p' && src[2] == 'c'
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = A_SPC;
return 3;
}
- if (src[0] == 's' && src[1] == 'g' && src[2] == 'r' && ! isalnum (src[3]))
+ if (src[0] == 's' && src[1] == 'g' && src[2] == 'r'
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = A_SGR;
return 3;
}
- if (src[0] == 'd' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3]))
+ if (src[0] == 'd' && src[1] == 'b' && src[2] == 'r'
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = A_DBR;
return 3;
}
- if (src[0] == 's' && src[1] == 'r' && ! isalnum (src[2]))
+ if (src[0] == 's' && src[1] == 'r' && ! isalnum ((unsigned char) src[2]))
{
*mode = A_SR;
return 2;
}
- if (src[0] == 's' && src[1] == 'p' && ! isalnum (src[2]))
+ if (src[0] == 's' && src[1] == 'p' && ! isalnum ((unsigned char) src[2]))
{
*mode = A_REG_N;
*reg = 15;
return 2;
}
- if (src[0] == 'p' && src[1] == 'r' && ! isalnum (src[2]))
+ if (src[0] == 'p' && src[1] == 'r' && ! isalnum ((unsigned char) src[2]))
{
*mode = A_PR;
return 2;
}
- if (src[0] == 'p' && src[1] == 'c' && ! isalnum (src[2]))
+ if (src[0] == 'p' && src[1] == 'c' && ! isalnum ((unsigned char) src[2]))
{
*mode = A_DISP_PC;
return 2;
}
- if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3]))
+ if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r'
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = A_GBR;
return 3;
}
- if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3]))
+ if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r'
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = A_VBR;
return 3;
}
- if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c' && ! isalnum (src[4]))
+ if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c'
+ && ! isalnum ((unsigned char) src[4]))
{
if (src[3] == 'l')
{
@@ -329,14 +352,16 @@ parse_reg (src, mode, reg)
{
if (src[2] == '1')
{
- if (src[3] >= '0' && src[3] <= '5' && ! isalnum (src[4]))
+ if (src[3] >= '0' && src[3] <= '5'
+ && ! isalnum ((unsigned char) src[4]))
{
*mode = F_REG_N;
*reg = 10 + src[3] - '0';
return 4;
}
}
- if (src[2] >= '0' && src[2] <= '9' && ! isalnum (src[3]))
+ if (src[2] >= '0' && src[2] <= '9'
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = F_REG_N;
*reg = (src[2] - '0');
@@ -348,7 +373,7 @@ parse_reg (src, mode, reg)
if (src[2] == '1')
{
if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1)
- && ! isalnum (src[4]))
+ && ! isalnum ((unsigned char) src[4]))
{
*mode = D_REG_N;
*reg = 10 + src[3] - '0';
@@ -356,7 +381,7 @@ parse_reg (src, mode, reg)
}
}
if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1)
- && ! isalnum (src[3]))
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = D_REG_N;
*reg = (src[2] - '0');
@@ -368,7 +393,7 @@ parse_reg (src, mode, reg)
if (src[2] == '1')
{
if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1)
- && ! isalnum (src[4]))
+ && ! isalnum ((unsigned char) src[4]))
{
*mode = X_REG_N;
*reg = 11 + src[3] - '0';
@@ -376,7 +401,7 @@ parse_reg (src, mode, reg)
}
}
if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1)
- && ! isalnum (src[3]))
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = X_REG_N;
*reg = (src[2] - '0') + 1;
@@ -385,13 +410,14 @@ parse_reg (src, mode, reg)
}
if (src[0] == 'f' && src[1] == 'v')
{
- if (src[2] == '1'&& src[3] == '2' && ! isalnum (src[4]))
+ if (src[2] == '1'&& src[3] == '2' && ! isalnum ((unsigned char) src[4]))
{
*mode = V_REG_N;
*reg = 12;
return 4;
}
- if ((src[2] == '0' || src[2] == '4' || src[2] == '8') && ! isalnum (src[3]))
+ if ((src[2] == '0' || src[2] == '4' || src[2] == '8')
+ && ! isalnum ((unsigned char) src[3]))
{
*mode = V_REG_N;
*reg = (src[2] - '0');
@@ -399,21 +425,21 @@ parse_reg (src, mode, reg)
}
}
if (src[0] == 'f' && src[1] == 'p' && src[2] == 'u' && src[3] == 'l'
- && ! isalnum (src[4]))
+ && ! isalnum ((unsigned char) src[4]))
{
*mode = FPUL_N;
return 4;
}
if (src[0] == 'f' && src[1] == 'p' && src[2] == 's' && src[3] == 'c'
- && src[4] == 'r' && ! isalnum (src[5]))
+ && src[4] == 'r' && ! isalnum ((unsigned char) src[5]))
{
*mode = FPSCR_N;
return 5;
}
if (src[0] == 'x' && src[1] == 'm' && src[2] == 't' && src[3] == 'r'
- && src[4] == 'x' && ! isalnum (src[5]))
+ && src[4] == 'x' && ! isalnum ((unsigned char) src[5]))
{
*mode = XMTRX_M4;
return 5;
@@ -865,10 +891,11 @@ build_relax (opcode)
if (opcode->arg[0] == A_BDISP8)
{
+ int what = (opcode->nibbles[1] & 4) ? COND_JUMP_DELAY : COND_JUMP;
p = frag_var (rs_machine_dependent,
- md_relax_table[C (COND_JUMP, COND32)].rlx_length,
- md_relax_table[C (COND_JUMP, COND8)].rlx_length,
- C (COND_JUMP, 0),
+ md_relax_table[C (what, COND32)].rlx_length,
+ md_relax_table[C (what, COND8)].rlx_length,
+ C (what, 0),
immediate.X_add_symbol,
immediate.X_add_number,
0);
@@ -1259,8 +1286,6 @@ SH options:\n\
-small align sections to 4 byte boundaries, not 16\n"));
}
-int md_short_jump_size;
-
void
tc_Nout_fix_to_chars ()
{
@@ -1268,27 +1293,6 @@ tc_Nout_fix_to_chars ()
abort ();
}
-void
-md_create_short_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
- char *ptr;
- addressT from_Nddr;
- addressT to_Nddr;
- fragS *frag;
- symbolS *to_symbol;
-{
- as_fatal (_("failed sanity check."));
-}
-
-void
-md_create_long_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol)
- char *ptr;
- addressT from_Nddr, to_Nddr;
- fragS *frag;
- symbolS *to_symbol;
-{
- as_fatal (_("failed sanity check."));
-}
-
/* This struct is used to pass arguments to sh_count_relocs through
bfd_map_over_sections. */
@@ -1490,6 +1494,7 @@ md_convert_frag (headers, seg, fragP)
switch (fragP->fr_subtype)
{
case C (COND_JUMP, COND8):
+ case C (COND_JUMP_DELAY, COND8):
subseg_change (seg, 0);
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset,
1, BFD_RELOC_SH_PCDISP8BY2);
@@ -1510,7 +1515,7 @@ md_convert_frag (headers, seg, fragP)
if (fragP->fr_symbol == NULL)
as_bad (_("at 0x%lx, displacement overflows 12-bit field"),
(unsigned long) fragP->fr_address);
- else if (S_IS_DEFINED (fragP->fr_address))
+ else if (S_IS_DEFINED (fragP->fr_symbol))
as_bad (_("at 0x%lx, displacement to defined symbol %s overflows 12-bit field"),
(unsigned long) fragP->fr_address,
S_GET_NAME (fragP->fr_symbol));
@@ -1562,17 +1567,25 @@ md_convert_frag (headers, seg, fragP)
break;
case C (COND_JUMP, COND12):
+ case C (COND_JUMP_DELAY, COND12):
/* A bcond won't fit, so turn it into a b!cond; bra disp; nop */
{
unsigned char *buffer =
(unsigned char *) (fragP->fr_fix + fragP->fr_literal);
int highbyte = target_big_endian ? 0 : 1;
int lowbyte = target_big_endian ? 1 : 0;
+ int delay = fragP->fr_subtype == C (COND_JUMP_DELAY, COND12);
/* Toggle the true/false bit of the bcond. */
buffer[highbyte] ^= 0x2;
- /* Build a relocation to six bytes farther on. */
+ /* If this is a dalayed branch, we may not put the the bra in the
+ slot. So we change it to a non-delayed branch, like that:
+ b! cond slot_label; bra disp; slot_label: slot_insn
+ ??? We should try if swapping the conditional branch and
+ its delay-slot insn already makes the branch reach. */
+
+ /* Build a relocation to six / four bytes farther on. */
subseg_change (seg, 0);
fix_new (fragP, fragP->fr_fix, 2,
#ifdef BFD_ASSEMBLER
@@ -1580,7 +1593,7 @@ md_convert_frag (headers, seg, fragP)
#else
seg_info (seg)->dot,
#endif
- fragP->fr_address + fragP->fr_fix + 6,
+ fragP->fr_address + fragP->fr_fix + (delay ? 4 : 6),
1, BFD_RELOC_SH_PCDISP8BY2);
/* Set up a jump instruction. */
@@ -1589,18 +1602,28 @@ md_convert_frag (headers, seg, fragP)
fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2);
- /* Fill in a NOP instruction. */
- buffer[highbyte + 4] = 0x0;
- buffer[lowbyte + 4] = 0x9;
-
- fragP->fr_fix += 6;
+ if (delay)
+ {
+ buffer[highbyte] &= ~0x4; /* Removes delay slot from branch. */
+ fragP->fr_fix += 4;
+ }
+ else
+ {
+ /* Fill in a NOP instruction. */
+ buffer[highbyte + 4] = 0x0;
+ buffer[lowbyte + 4] = 0x9;
+
+ fragP->fr_fix += 6;
+ }
fragP->fr_var = 0;
donerelax = 1;
}
break;
case C (COND_JUMP, COND32):
+ case C (COND_JUMP_DELAY, COND32):
case C (COND_JUMP, UNDEF_WORD_DISP):
+ case C (COND_JUMP_DELAY, UNDEF_WORD_DISP):
if (fragP->fr_symbol == NULL)
as_bad (_("at 0x%lx, displacement overflows 8-bit field"),
(unsigned long) fragP->fr_address);
@@ -1836,6 +1859,16 @@ md_apply_fix (fixP, val)
long max, min;
int shift;
+#ifdef BFD_ASSEMBLER
+ /* adjust_reloc_syms won't convert a reloc against a weak symbol
+ into a reloc against a section, but bfd_install_relocation will
+ screw up if the symbol is defined, so we have to adjust val here
+ to avoid the screw up later. */
+ if (fixP->fx_addsy != NULL
+ && S_IS_WEAK (fixP->fx_addsy))
+ val -= S_GET_VALUE (fixP->fx_addsy);
+#endif
+
#ifndef BFD_ASSEMBLER
if (fixP->fx_r_type == 0)
{
@@ -2001,8 +2034,6 @@ md_apply_fix (fixP, val)
#endif
}
-int md_long_jump_size;
-
/* Called just before address relaxation. Return the length
by which a fragment must grow to reach it's destination. */
@@ -2036,27 +2067,31 @@ md_estimate_size_before_relax (fragP, segment_type)
default:
abort ();
case C (COND_JUMP, UNDEF_DISP):
+ case C (COND_JUMP_DELAY, UNDEF_DISP):
/* used to be a branch to somewhere which was unknown */
if (fragP->fr_symbol
&& S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
{
+ int what = GET_WHAT (fragP->fr_subtype);
/* Got a symbol and it's defined in this segment, become byte
sized - maybe it will fix up */
- fragP->fr_subtype = C (COND_JUMP, COND8);
- fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length;
+ fragP->fr_subtype = C (what, COND8);
+ fragP->fr_var = md_relax_table[C (what, COND8)].rlx_length;
}
else if (fragP->fr_symbol)
{
+ int what = GET_WHAT (fragP->fr_subtype);
/* Its got a segment, but its not ours, so it will always be long */
- fragP->fr_subtype = C (COND_JUMP, UNDEF_WORD_DISP);
- fragP->fr_var = md_relax_table[C (COND_JUMP, COND32)].rlx_length;
- return md_relax_table[C (COND_JUMP, COND32)].rlx_length;
+ fragP->fr_subtype = C (what, UNDEF_WORD_DISP);
+ fragP->fr_var = md_relax_table[C (what, COND32)].rlx_length;
+ return md_relax_table[C (what, COND32)].rlx_length;
}
else
{
+ int what = GET_WHAT (fragP->fr_subtype);
/* We know the abs value */
- fragP->fr_subtype = C (COND_JUMP, COND8);
- fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length;
+ fragP->fr_subtype = C (what, COND8);
+ fragP->fr_var = md_relax_table[C (what, COND8)].rlx_length;
}
break;