* config/tc-xtensa.c (xg_apply_tentative_value): Rename to
authorBob Wilson <bob.wilson@acm.org>
Thu, 17 Mar 2005 21:49:47 +0000 (21:49 +0000)
committerBob Wilson <bob.wilson@acm.org>
Thu, 17 Mar 2005 21:49:47 +0000 (21:49 +0000)
        xg_apply_fix_value and return a value to indicate success.
        (md_pcrel_from): Skip check of fx_done.  Return 0 if not PC-relative.
        (xtensa_force_relocation): Remove checks for VTABLE relocs.
        (xtensa_validate_fix_sub): New.
        (xtensa_fix_adjustable): Remove check for external or weak symbols.
        (tc_gen_reloc): Move code to handle difference of symbols and code to
        apply tentative fix values to ...
        (md_apply_fix3): ...here.  Enable standard overflow checks for simple
        8, 16, and 32 bit relocations.  Apply fixes for slot-specific
        relocations when linkrelax flag is not set.
        * config/tc-xtensa.h (xtensa_validate_fix_sub): Add prototype.
        (TC_FORCE_RELOCATION_SUB_SAME, TC_VALIDATE_FIX_SUB): Define.

gas/ChangeLog
gas/config/tc-xtensa.c
gas/config/tc-xtensa.h

index 1610ac52983bbf491d25d2220f27baa00f5234c0..46ef21c9b81da15af332636007622a0c11cff92f 100644 (file)
@@ -1,3 +1,19 @@
+2005-03-17  Bob Wilson  <bob.wilson@acm.org>
+
+       * config/tc-xtensa.c (xg_apply_tentative_value): Rename to
+       xg_apply_fix_value and return a value to indicate success.
+       (md_pcrel_from): Skip check of fx_done.  Return 0 if not PC-relative.
+       (xtensa_force_relocation): Remove checks for VTABLE relocs.
+       (xtensa_validate_fix_sub): New.
+       (xtensa_fix_adjustable): Remove check for external or weak symbols.
+       (tc_gen_reloc): Move code to handle difference of symbols and code to
+       apply tentative fix values to ...
+       (md_apply_fix3): ...here.  Enable standard overflow checks for simple
+       8, 16, and 32 bit relocations.  Apply fixes for slot-specific
+       relocations when linkrelax flag is not set.
+       * config/tc-xtensa.h (xtensa_validate_fix_sub): Add prototype.
+       (TC_FORCE_RELOCATION_SUB_SAME, TC_VALIDATE_FIX_SUB): Define.
+
 2005-03-17  Jan Beulich  <jbeulich@novell.com>
 
        * config/tc-i386.c (i386_scale): Beautify error message.
index 9d20a6b048ba141518d7f65db04956b9e617d0a9..1eb6c429fe7eae695c8c9e28617c61f5906ee407 100644 (file)
@@ -4934,8 +4934,8 @@ xtensa_find_unaligned_loops (bfd *abfd ATTRIBUTE_UNUSED,
 }
 
 
-static void
-xg_apply_tentative_value (fixS *fixP, valueT val)
+static int
+xg_apply_fix_value (fixS *fixP, valueT val)
 {
   xtensa_isa isa = xtensa_default_isa;
   static xtensa_insnbuf insnbuf = NULL;
@@ -4967,11 +4967,9 @@ xg_apply_tentative_value (fixS *fixP, valueT val)
 
   /* CONST16 immediates are not PC-relative, despite the fact that we
      reuse the normal PC-relative operand relocations for the low part
-     of a CONST16 operand.  The code in tc_gen_reloc does not decode
-     the opcodes so it is more convenient to detect this special case
-     here.  */
+     of a CONST16 operand.  */
   if (opcode == xtensa_const16_opcode)
-    return;
+    return 0;
 
   xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode,
                              get_relaxable_immed (opcode), val,
@@ -4979,6 +4977,8 @@ xg_apply_tentative_value (fixS *fixP, valueT val)
 
   xtensa_format_set_slot (isa, fmt, slot, insnbuf, slotbuf);
   xtensa_insnbuf_to_chars (isa, insnbuf, fixpos, 0);
+
+  return 1;
 }
 
 \f
@@ -5452,11 +5452,8 @@ md_pcrel_from (fixS *fixP)
   valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
   bfd_boolean alt_reloc;
 
-  if (fixP->fx_done)
-    return addr;
-
   if (fixP->fx_r_type == BFD_RELOC_XTENSA_ASM_EXPAND)
-    return addr;
+    return 0;
 
   if (!insnbuf)
     {
@@ -5477,14 +5474,15 @@ md_pcrel_from (fixS *fixP)
   xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf);
   opcode = xtensa_opcode_decode (isa, fmt, slot, slotbuf);
 
-  /* Check for "alternate" relocation (operand not specified).  */
+  /* Check for "alternate" relocations (operand not specified).  None
+     of the current uses for these are really PC-relative.  */
   if (alt_reloc || opcode == xtensa_const16_opcode)
     {
       if (opcode != xtensa_l32r_opcode
          && opcode != xtensa_const16_opcode)
        as_fatal (_("invalid relocation for '%s' instruction"),
                  xtensa_opcode_name (isa, opcode));
-      return addr;
+      return 0;
     }
 
   opnum = get_relaxable_immed (opcode);
@@ -5496,7 +5494,7 @@ md_pcrel_from (fixS *fixP)
                    fixP->fx_line,
                    _("invalid relocation for operand %d of '%s'"),
                    opnum, xtensa_opcode_name (isa, opcode));
-      return addr;
+      return 0;
     }
   return 0 - opnd_value;
 }
@@ -5508,7 +5506,8 @@ int
 xtensa_force_relocation (fixS *fix)
 {
   switch (fix->fx_r_type)
-   {
+    {
+    case BFD_RELOC_XTENSA_ASM_EXPAND:
     case BFD_RELOC_XTENSA_SLOT0_ALT:
     case BFD_RELOC_XTENSA_SLOT1_ALT:
     case BFD_RELOC_XTENSA_SLOT2_ALT:
@@ -5524,8 +5523,6 @@ xtensa_force_relocation (fixS *fix)
     case BFD_RELOC_XTENSA_SLOT12_ALT:
     case BFD_RELOC_XTENSA_SLOT13_ALT:
     case BFD_RELOC_XTENSA_SLOT14_ALT:
-    case BFD_RELOC_VTABLE_INHERIT:
-    case BFD_RELOC_VTABLE_ENTRY:
       return 1;
     default:
       break;
@@ -5539,6 +5536,33 @@ xtensa_force_relocation (fixS *fix)
 }
 
 
+/* TC_VALIDATE_FIX_SUB hook */
+
+int
+xtensa_validate_fix_sub (fixS *fix)
+{
+  segT add_symbol_segment, sub_symbol_segment;
+
+  /* The difference of two symbols should be resolved by the assembler when
+     linkrelax is not set.  If the linker may relax the section containing
+     the symbols, then an Xtensa DIFF relocation must be generated so that
+     the linker knows to adjust the difference value.  */
+  if (!linkrelax || fix->fx_addsy == NULL)
+    return 0;
+
+  /* Make sure both symbols are in the same segment, and that segment is
+     "normal" and relaxable.  If the segment is not "normal", then the
+     fix is not valid.  If the segment is not "relaxable", then the fix
+     should have been handled earlier.  */
+  add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy);
+  if (! SEG_NORMAL (add_symbol_segment) ||
+      ! relaxable_section (add_symbol_segment))
+    return 0;
+  sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
+  return (sub_symbol_segment == add_symbol_segment);
+}
+
+
 /* NO_PSEUDO_DOT hook */
 
 /* This function has nothing to do with pseudo dots, but this is the
@@ -5586,49 +5610,134 @@ xtensa_fix_adjustable (fixS *fixP)
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
 
-  if (fixP->fx_addsy
-      && (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy)))
-    return 0;
-
   return 1;
 }
 
 
 void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix3 (fixS *fixP, valueT *valP, segT seg)
 {
-  if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0)
+  char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
+  valueT val;
+
+  switch (fixP->fx_r_type)
     {
-      char *const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
+    case BFD_RELOC_32:
+    case BFD_RELOC_16:
+    case BFD_RELOC_8:
+      if (linkrelax && fixP->fx_subsy)
+       {
+         switch (fixP->fx_r_type)
+           {
+           case BFD_RELOC_8:
+             fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
+             break;
+           case BFD_RELOC_16:
+             fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
+             break;
+           case BFD_RELOC_32:
+             fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
+             break;
+           default:
+             break;
+           }
+
+         /* An offset is only allowed when it results from adjusting a
+            local symbol into a section-relative offset.  If the offset
+            came from the original expression, tc_fix_adjustable will have
+            prevented the fix from being converted to a section-relative
+            form so that we can flag the error here.  */
+         if (fixP->fx_offset != 0 && !symbol_section_p (fixP->fx_addsy))
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("cannot represent subtraction with an offset"));
 
-      switch (fixP->fx_r_type)
+         val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+                - S_GET_VALUE (fixP->fx_subsy));
+
+         /* The difference value gets written out, and the DIFF reloc
+            identifies the address of the subtracted symbol (i.e., the one
+            with the lowest address).  */
+         *valP = val;
+         fixP->fx_offset -= val;
+         fixP->fx_subsy = NULL;
+       }
+      else if (! fixP->fx_addsy)
        {
-       case BFD_RELOC_XTENSA_ASM_EXPAND:
+         val = *valP;
          fixP->fx_done = 1;
-         break;
+       }
+      else
+       break;
+      md_number_to_chars (fixpos, val, fixP->fx_size);
+      fixP->fx_no_overflow = 0; /* Use the standard overflow check.  */
+      break;
 
-       case BFD_RELOC_XTENSA_ASM_SIMPLIFY:
-         as_bad (_("unhandled local relocation fix %s"),
-                 bfd_get_reloc_code_name (fixP->fx_r_type));
-         break;
+    case BFD_RELOC_XTENSA_SLOT0_OP:
+    case BFD_RELOC_XTENSA_SLOT1_OP:
+    case BFD_RELOC_XTENSA_SLOT2_OP:
+    case BFD_RELOC_XTENSA_SLOT3_OP:
+    case BFD_RELOC_XTENSA_SLOT4_OP:
+    case BFD_RELOC_XTENSA_SLOT5_OP:
+    case BFD_RELOC_XTENSA_SLOT6_OP:
+    case BFD_RELOC_XTENSA_SLOT7_OP:
+    case BFD_RELOC_XTENSA_SLOT8_OP:
+    case BFD_RELOC_XTENSA_SLOT9_OP:
+    case BFD_RELOC_XTENSA_SLOT10_OP:
+    case BFD_RELOC_XTENSA_SLOT11_OP:
+    case BFD_RELOC_XTENSA_SLOT12_OP:
+    case BFD_RELOC_XTENSA_SLOT13_OP:
+    case BFD_RELOC_XTENSA_SLOT14_OP:
+      if (linkrelax)
+       {
+         /* Write the tentative value of a PC-relative relocation to a
+            local symbol into the instruction.  The value will be ignored
+            by the linker, and it makes the object file disassembly
+            readable when all branch targets are encoded in relocations.  */
+
+         assert (fixP->fx_addsy);
+         if (S_GET_SEGMENT (fixP->fx_addsy) == seg && !fixP->fx_plt
+             && !S_FORCE_RELOC (fixP->fx_addsy, 1))
+           {
+             val = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+                    - md_pcrel_from (fixP));
+             (void) xg_apply_fix_value (fixP, val);
+           }
+       }
+      else if (! fixP->fx_addsy)
+       {
+         val = *valP;
+         if (xg_apply_fix_value (fixP, val))
+           fixP->fx_done = 1;
+       }
+      break;
 
-       case BFD_RELOC_32:
-       case BFD_RELOC_16:
-       case BFD_RELOC_8:
-         /* The only one we support that isn't an instruction field.  */
-         md_number_to_chars (fixpos, *valP, fixP->fx_size);
-         fixP->fx_done = 1;
-         break;
+    case BFD_RELOC_XTENSA_ASM_EXPAND:
+    case BFD_RELOC_XTENSA_SLOT0_ALT:
+    case BFD_RELOC_XTENSA_SLOT1_ALT:
+    case BFD_RELOC_XTENSA_SLOT2_ALT:
+    case BFD_RELOC_XTENSA_SLOT3_ALT:
+    case BFD_RELOC_XTENSA_SLOT4_ALT:
+    case BFD_RELOC_XTENSA_SLOT5_ALT:
+    case BFD_RELOC_XTENSA_SLOT6_ALT:
+    case BFD_RELOC_XTENSA_SLOT7_ALT:
+    case BFD_RELOC_XTENSA_SLOT8_ALT:
+    case BFD_RELOC_XTENSA_SLOT9_ALT:
+    case BFD_RELOC_XTENSA_SLOT10_ALT:
+    case BFD_RELOC_XTENSA_SLOT11_ALT:
+    case BFD_RELOC_XTENSA_SLOT12_ALT:
+    case BFD_RELOC_XTENSA_SLOT13_ALT:
+    case BFD_RELOC_XTENSA_SLOT14_ALT:
+      /* These all need to be resolved at link-time.  Do nothing now.  */
+      break;
 
-       case BFD_RELOC_VTABLE_INHERIT:
-       case BFD_RELOC_VTABLE_ENTRY:
-         fixP->fx_done = 0;
-         break;
+    case BFD_RELOC_VTABLE_INHERIT:
+    case BFD_RELOC_VTABLE_ENTRY:
+      fixP->fx_done = 0;
+      break;
 
-       default:
-         as_bad (_("unhandled local relocation fix %s"),
-                 bfd_get_reloc_code_name (fixP->fx_r_type));
-       }
+    default:
+      as_bad (_("unhandled local relocation fix %s"),
+             bfd_get_reloc_code_name (fixP->fx_r_type));
     }
 }
 
@@ -5687,10 +5796,9 @@ md_estimate_size_before_relax (fragS *fragP, segT seg ATTRIBUTE_UNUSED)
    format.  */
 
 arelent *
-tc_gen_reloc (asection *section, fixS *fixp)
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 {
   arelent *reloc;
-  bfd_boolean apply_tentative_value = FALSE;
 
   reloc = (arelent *) xmalloc (sizeof (arelent));
   reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
@@ -5701,128 +5809,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
      They'd better have been fully resolved by this point.  */
   assert ((int) fixp->fx_r_type > 0);
 
-  if (linkrelax && fixp->fx_subsy
-      && (fixp->fx_r_type == BFD_RELOC_8
-         || fixp->fx_r_type == BFD_RELOC_16
-         || fixp->fx_r_type == BFD_RELOC_32))
-    {
-      int diff_size = 0;
-      bfd_vma diff_value, diff_mask = 0;
-
-      switch (fixp->fx_r_type)
-       {
-       case BFD_RELOC_8:
-         fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
-         diff_size = 1;
-         diff_mask = 0xff;
-         break;
-       case BFD_RELOC_16:
-         fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
-         diff_size = 2;
-         diff_mask = 0xffff;
-         break;
-       case BFD_RELOC_32:
-         fixp->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
-         diff_size = 4;
-         diff_mask = 0xffffffff;
-         break;
-       default:
-         break;
-       }
-
-      /* An offset is only allowed when it results from adjusting a local
-        symbol into a section-relative offset.  If the offset came from the
-        original expression, tc_fix_adjustable will have prevented the fix
-        from being converted to a section-relative form so that we can flag
-        the error here.  */
-      if (fixp->fx_offset != 0 && !symbol_section_p (fixp->fx_addsy))
-       {
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       _("cannot represent subtraction with an offset"));
-         free (reloc->sym_ptr_ptr);
-         free (reloc);
-         return NULL;
-       }
-
-      assert (S_GET_SEGMENT (fixp->fx_addsy)
-             == S_GET_SEGMENT (fixp->fx_subsy));
-
-      diff_value = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset
-                   - S_GET_VALUE (fixp->fx_subsy));
-
-      /* Check for overflow.  */
-      if ((diff_value & ~diff_mask) != 0)
-       {
-         as_bad_where (fixp->fx_file, fixp->fx_line,
-                       _("value of %ld too large"), diff_value);
-         free (reloc->sym_ptr_ptr);
-         free (reloc);
-         return NULL;
-       }
-
-      md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where,
-                         diff_value, diff_size);
-      reloc->addend = fixp->fx_offset - diff_value;
-    }
-  else
-    {
-      reloc->addend = fixp->fx_offset;
-
-      switch (fixp->fx_r_type)
-       {
-       case BFD_RELOC_XTENSA_SLOT0_OP:
-       case BFD_RELOC_XTENSA_SLOT1_OP:
-       case BFD_RELOC_XTENSA_SLOT2_OP:
-       case BFD_RELOC_XTENSA_SLOT3_OP:
-       case BFD_RELOC_XTENSA_SLOT4_OP:
-       case BFD_RELOC_XTENSA_SLOT5_OP:
-       case BFD_RELOC_XTENSA_SLOT6_OP:
-       case BFD_RELOC_XTENSA_SLOT7_OP:
-       case BFD_RELOC_XTENSA_SLOT8_OP:
-       case BFD_RELOC_XTENSA_SLOT9_OP:
-       case BFD_RELOC_XTENSA_SLOT10_OP:
-       case BFD_RELOC_XTENSA_SLOT11_OP:
-       case BFD_RELOC_XTENSA_SLOT12_OP:
-       case BFD_RELOC_XTENSA_SLOT13_OP:
-       case BFD_RELOC_XTENSA_SLOT14_OP:
-         /* As a special case, the immediate value for a CONST16 opcode
-            should not be applied, since this kind of relocation is
-            handled specially for CONST16 and is not really PC-relative.
-            Rather than decode the opcode here, just wait and handle it
-            in xg_apply_tentative_value.  */
-         apply_tentative_value = TRUE;
-         break;
-
-       case BFD_RELOC_XTENSA_SLOT0_ALT:
-       case BFD_RELOC_XTENSA_SLOT1_ALT:
-       case BFD_RELOC_XTENSA_SLOT2_ALT:
-       case BFD_RELOC_XTENSA_SLOT3_ALT:
-       case BFD_RELOC_XTENSA_SLOT4_ALT:
-       case BFD_RELOC_XTENSA_SLOT5_ALT:
-       case BFD_RELOC_XTENSA_SLOT6_ALT:
-       case BFD_RELOC_XTENSA_SLOT7_ALT:
-       case BFD_RELOC_XTENSA_SLOT8_ALT:
-       case BFD_RELOC_XTENSA_SLOT9_ALT:
-       case BFD_RELOC_XTENSA_SLOT10_ALT:
-       case BFD_RELOC_XTENSA_SLOT11_ALT:
-       case BFD_RELOC_XTENSA_SLOT12_ALT:
-       case BFD_RELOC_XTENSA_SLOT13_ALT:
-       case BFD_RELOC_XTENSA_SLOT14_ALT:
-       case BFD_RELOC_XTENSA_ASM_EXPAND:
-       case BFD_RELOC_32:
-       case BFD_RELOC_XTENSA_PLT:
-       case BFD_RELOC_VTABLE_INHERIT:
-       case BFD_RELOC_VTABLE_ENTRY:
-         break;
-
-       case BFD_RELOC_XTENSA_ASM_SIMPLIFY:
-         as_warn (_("emitting simplification relocation"));
-         break;
-
-       default:
-         as_warn (_("emitting unknown relocation"));
-       }
-    }
+  reloc->addend = fixp->fx_offset;
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   if (reloc->howto == NULL)
@@ -5839,24 +5826,6 @@ tc_gen_reloc (asection *section, fixS *fixp)
     as_fatal (_("internal error? cannot generate `%s' relocation"),
              bfd_get_reloc_code_name (fixp->fx_r_type));
 
-  /* Write the tentative value of a PC-relative relocation to a local symbol
-     into the instruction.  The value will be ignored by the linker, and it
-     makes the object file disassembly readable when the linkrelax flag is
-     set and all branch targets are encoded in relocations.  */
-
-  if (linkrelax && apply_tentative_value && fixp->fx_pcrel)
-    {
-      valueT val;
-      assert (fixp->fx_addsy);
-      if (S_GET_SEGMENT (fixp->fx_addsy) == section && !fixp->fx_plt
-         && !S_FORCE_RELOC (fixp->fx_addsy, 1))
-       {
-         val = (S_GET_VALUE (fixp->fx_addsy) + fixp->fx_offset
-                - md_pcrel_from (fixp));
-         xg_apply_tentative_value (fixp, val);
-       }
-    }
-
   return reloc;
 }
 
index 47436176f83956c634f50a67555b6e00bf7cd636..e38fa6ce7d64ef80c6f45b5919b5f622cc217691 100644 (file)
@@ -291,6 +291,7 @@ extern const char *xtensa_target_format (void);
 extern void xtensa_init_fix_data (struct fix *);
 extern void xtensa_frag_init (fragS *);
 extern int xtensa_force_relocation (struct fix *);
+extern int xtensa_validate_fix_sub (struct fix *);
 extern void xtensa_frob_label (struct symbol *);
 extern void xtensa_end (void);
 extern void xtensa_post_relax_hook (void);
@@ -314,6 +315,9 @@ extern char *xtensa_section_rename (char *);
 #define TC_FRAG_TYPE                   struct xtensa_frag_type
 #define TC_FRAG_INIT(frag)             xtensa_frag_init (frag)
 #define TC_FORCE_RELOCATION(fix)       xtensa_force_relocation (fix)
+#define TC_FORCE_RELOCATION_SUB_SAME(fix, seg) \
+  (! SEG_NORMAL (seg) || xtensa_force_relocation (fix))
+#define        TC_VALIDATE_FIX_SUB(fix)        xtensa_validate_fix_sub (fix)
 #define NO_PSEUDO_DOT                  xtensa_check_inside_bundle ()
 #define tc_canonicalize_symbol_name(s) xtensa_section_rename (s)
 #define tc_canonicalize_section_name(s)        xtensa_section_rename (s)