aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1994-03-31 21:54:06 +0000
committerIan Lance Taylor <ian@airs.com>1994-03-31 21:54:06 +0000
commit7ab2e983d6756df196336fe44f24316d2821dba2 (patch)
tree4019cc09280f299f54d50ec0a09e482462553b0d /gas
parentf8ee1ebba03386de6d5760f67ae773a3245431c3 (diff)
downloadgdb-7ab2e983d6756df196336fe44f24316d2821dba2.zip
gdb-7ab2e983d6756df196336fe44f24316d2821dba2.tar.gz
gdb-7ab2e983d6756df196336fe44f24316d2821dba2.tar.bz2
* config/tc-sparc.c (tc_gen_reloc): Add a gruesome hack to get
cross section PC relative relocs right for COFF and ELF.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog5
-rw-r--r--gas/config/tc-sparc.c88
2 files changed, 72 insertions, 21 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index e48383f..9255c57 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,8 @@
+Thu Mar 31 16:51:16 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * config/tc-sparc.c (tc_gen_reloc): Add a gruesome hack to get
+ cross section PC relative relocs right for COFF and ELF.
+
Mon Mar 28 14:38:23 1994 Ken Raeburn (raeburn@cujo.cygnus.com)
* config/obj-coff.h (SEPARATE_STAB_SECTIONS): Always define.
diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c
index 2480300..4274ded 100644
--- a/gas/config/tc-sparc.c
+++ b/gas/config/tc-sparc.c
@@ -23,6 +23,7 @@
#include <ctype.h>
#include "as.h"
+#include "subsegs.h"
/* careful, this file includes data *declarations* */
#include "opcode/sparc.h"
@@ -124,6 +125,19 @@ struct sparc_it
struct sparc_it the_insn, set_insn;
+static INLINE int
+in_signed_range (val, max)
+ bfd_signed_vma val, max;
+{
+ if (max <= 0)
+ abort ();
+ if (val > max)
+ return 0;
+ if (val < ~max)
+ return 0;
+ return 1;
+}
+
#if 0
static void print_insn PARAMS ((struct sparc_it *insn));
#endif
@@ -1377,8 +1391,7 @@ sparc_ip (str)
goto immediate;
case 'i': /* 13 bit immediate */
- /* What's the difference between base13 and 13? */
- the_insn.reloc = BFD_RELOC_SPARC_BASE13;
+ the_insn.reloc = BFD_RELOC_SPARC13;
immediate_max = 0x0FFF;
/*FALLTHROUGH */
@@ -1464,6 +1477,10 @@ sparc_ip (str)
{
/* start-sanitize-v9 */
#ifndef NO_V9
+ /* Handle %uhi/%ulo by moving the upper word to the lower
+ one and pretending it's %hi/%lo. We also need to watch
+ for %hi/%lo: the top word needs to be zeroed otherwise
+ fixup_segment will complain the value is too big. */
switch (the_insn.reloc)
{
case BFD_RELOC_SPARC_HH22:
@@ -1476,19 +1493,47 @@ sparc_ip (str)
break;
default:
break;
+ case BFD_RELOC_HI22:
+ case BFD_RELOC_LO10:
+ the_insn.exp.X_add_number &= 0xffffffff;
+ break;
}
#endif
/* end-sanitize-v9 */
+ /* For pc-relative call instructions, we reject
+ constants to get better code. */
+ if (the_insn.pcrel
+ && the_insn.reloc == BFD_RELOC_32_PCREL_S2
+ && in_signed_range (the_insn.exp.X_add_number, 0x3fff)
+ )
+ {
+ error_message = ": PC-relative operand can't be a constant";
+ goto error;
+ }
/* Check for invalid constant values. Don't warn if
constant was inside %hi or %lo, since these
truncate the constant to fit. */
if (immediate_max != 0
&& the_insn.reloc != BFD_RELOC_LO10
&& the_insn.reloc != BFD_RELOC_HI22
- && (the_insn.exp.X_add_number > immediate_max
- || the_insn.exp.X_add_number < ~immediate_max))
- as_bad ("constant value must be between %ld and %ld",
- ~immediate_max, immediate_max);
+ && !in_signed_range (the_insn.exp.X_add_number,
+ immediate_max)
+ )
+ {
+ if (the_insn.pcrel)
+ /* Who knows? After relocation, we may be within
+ range. Let the linker figure it out. */
+ {
+ the_insn.exp.X_op = O_symbol;
+ the_insn.exp.X_add_symbol = section_symbol (absolute_section);
+ }
+ else
+ /* Immediate value is non-pcrel, and out of
+ range. */
+ as_bad ("constant value %ld out of range (%ld .. %ld)",
+ the_insn.exp.X_add_number,
+ ~immediate_max, immediate_max);
+ }
}
/* Reset to prevent extraneous range check. */
@@ -1974,15 +2019,6 @@ md_apply_fix (fixP, value)
buf[3] = val & 0xff;
break;
- case BFD_RELOC_SPARC13:
- if (val & ~0x00001fff)
- {
- as_bad ("relocation overflow");
- } /* on overflow */
- buf[2] |= (val >> 8) & 0x1f;
- buf[3] = val & 0xff;
- break;
-
/* start-sanitize-v9 */
#ifndef NO_V9
case BFD_RELOC_SPARC_HM10:
@@ -2000,12 +2036,11 @@ md_apply_fix (fixP, value)
else
buf[3] = 0;
break;
- case BFD_RELOC_SPARC_BASE13:
- if (((val > 0) && (val & ~(offsetT)0x00001fff))
- || ((val < 0) && (~(val - 1) & ~(offsetT)0x00001fff)))
- {
- as_bad ("relocation overflow");
- }
+
+ case BFD_RELOC_SPARC13:
+ if (! in_signed_range (val, 0x1fff))
+ as_bad ("relocation overflow");
+
buf[2] |= (val >> 8) & 0x1f;
buf[3] = val;
break;
@@ -2025,6 +2060,10 @@ md_apply_fix (fixP, value)
break;
}
+ /* Are we finished with this relocation now? */
+ if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
+ fixP->fx_done = 1;
+
return 1;
}
@@ -2051,6 +2090,7 @@ tc_gen_reloc (section, fixp)
case BFD_RELOC_HI22:
case BFD_RELOC_LO10:
case BFD_RELOC_32_PCREL_S2:
+ case BFD_RELOC_SPARC13:
case BFD_RELOC_SPARC_BASE13:
case BFD_RELOC_SPARC_WDISP22:
/* start-sanitize-v9 */
@@ -2076,6 +2116,12 @@ tc_gen_reloc (section, fixp)
/* @@ Why fx_addnumber sometimes and fx_offset other times? */
if (reloc->howto->pc_relative == 0)
reloc->addend = fixp->fx_addnumber;
+#if defined (OBJ_ELF) || defined (OBJ_COFF)
+ else if ((fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
+ reloc->addend = (section->vma
+ + fixp->fx_addnumber
+ + md_pcrel_from (fixp));
+#endif
else
reloc->addend = fixp->fx_offset - reloc->address;