* config/tc-sparc.c (tc_gen_reloc): Add a gruesome hack to get
authorIan Lance Taylor <ian@airs.com>
Thu, 31 Mar 1994 21:54:06 +0000 (21:54 +0000)
committerIan Lance Taylor <ian@airs.com>
Thu, 31 Mar 1994 21:54:06 +0000 (21:54 +0000)
cross section PC relative relocs right for COFF and ELF.

gas/ChangeLog
gas/config/tc-sparc.c

index e48383fc4426a4075078e525cff539075565f064..9255c57cc48a00097eb4e3632e1b851a07ce8863 100644 (file)
@@ -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.
index 24803009b0b32b26e902b9c3600400df6101f48f..4274dedbc9745e3b52fa9bf62d51175476dc55c1 100644 (file)
@@ -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;