Fix sh-elf linker relaxation:
authorJoern Rennecke <joern.rennecke@embecosm.com>
Mon, 3 Mar 2003 21:04:01 +0000 (21:04 +0000)
committerJoern Rennecke <joern.rennecke@embecosm.com>
Mon, 3 Mar 2003 21:04:01 +0000 (21:04 +0000)
gcc:
* config/sh/sh.h (EXTRA_SPECS): Add subtarget_asm_relax_spec and
subtarget_asm_isa_spec.
(SUBTARGET_ASM_RELAX_SPEC, SUBTARGET_ASM_ISA_SPEC): Define.
(ASM_SPEC): Define as SH_ASM_SPEC.
(SH_ASM_SPEC): New; take the role of ASM_SPEC, but safe from svr4.h.
Use subtarget_asm_relax_spec and subtarget_asm_isa_spec.
* config/sh/elf.h (ASM_SPEC): Use SH_ASM_SPEC.
(SUBTARGET_ASM_ISA_SPEC): Undef / define.
gcc/testsuite:
gcc.dg/sh-relax.c: New test.

include/elf:
* sh.h (EF_SH_MERGE_MACH): Make sure SH2E & SH3/SH3E merge to SH3E,
and SH2E & SH4 merge to SH4, not SH2E.

gas:
* config/tc-sh.c (sh_dsp): Replace with preset_target_arch.
(md_begin): Use preset_target_arch.
(md_longopts): Make isa option unconditional.
(md_parse_option): Make OPTION_DSP and OPTION_ISA sh4 / any
set preset_target_arch.
(md_apply_fix3): If BFD_ASSEMBLER, adjust SWITCH_TABLE fixups
by -S_GET_VALUE  (fixP->fx_subsy).
(tc_gen_reloc): For SWITCH_TABLE fixups, the symbol is fixp->fx_subsy,
and the addend is 0.
Adjust addend of R_SH_IND12W relocations by fixp->fx_offset - 4.
* config/tc-sh.h (TC_FORCE_RELOCATION_SUB_LOCAL): Define.

bfd:
elf32-sh.c (sh_elf_howto_tab): Make R_SH_IND12W into an ordinary
relocation (no special function), and make it non-partial_inplace.
(sh_elf_relax_section): When creating a bsr, use a consistent value
no matter if the symbol is extern or not;  set addend to -4.
Don't swap load / non-load instructions for SH4.
(sh_elf_relax_delete_bytes): In R_SH_IND12W case, check the offset
rather than if the symbol is external to determine if adjusting the
offset makes sense.  Adjust the addend too if appropriate.
(sh_elf_relocate_section): In R_SH_IND12W, don't fiddle with the
relocation.

bfd/ChangeLog
bfd/elf32-sh.c
gas/ChangeLog
gas/config/tc-sh.c
gas/config/tc-sh.h
include/elf/ChangeLog
include/elf/sh.h

index 393ab0f..9387ce2 100644 (file)
@@ -1,3 +1,16 @@
+Mon Mar  3 20:48:23 2003  J"orn Rennecke <joern.rennecke@superh.com>
+
+       * elf32-sh.c (sh_elf_howto_tab): Make R_SH_IND12W into an ordinary
+       relocation (no special function), and make it non-partial_inplace.
+       (sh_elf_relax_section): When creating a bsr, use a consistent value
+       no matter if the symbol is extern or not;  set addend to -4.
+       Don't swap load / non-load instructions for SH4.
+       (sh_elf_relax_delete_bytes): In R_SH_IND12W case, check the offset
+       rather than if the symbol is external to determine if adjusting the
+       offset makes sense.  Adjust the addend too if appropriate.
+       (sh_elf_relocate_section): In R_SH_IND12W, don't fiddle with the
+       relocation.
+
 2003-03-03  Nick Clifton  <nickc@redhat.com>
 
        * po/da.po: Installed latest translation.
index 20dc7d1..c9167bc 100644 (file)
@@ -179,6 +179,8 @@ static reloc_howto_type sh_elf_howto_table[] =
         TRUE),                 /* pcrel_offset */
 
   /* 12 bit PC relative branch divided by 2.  */
+  /* This cannot be partial_inplace because relaxation can't know the
+     eventual value of a symbol.  */
   HOWTO (R_SH_IND12W,          /* type */
         1,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -186,10 +188,10 @@ static reloc_howto_type sh_elf_howto_table[] =
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        sh_elf_reloc,          /* special_function */
+        NULL,                  /* special_function */
         "R_SH_IND12W",         /* name */
-        TRUE,                  /* partial_inplace */
-        0xfff,                 /* src_mask */
+        FALSE,                 /* partial_inplace */
+        0x0,                   /* src_mask */
         0xfff,                 /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
@@ -2232,6 +2234,12 @@ sh_elf_relax_section (abfd, sec, link_info, again)
       /* Change the R_SH_USES reloc into an R_SH_IND12W reloc, and
         replace the jsr with a bsr.  */
       irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irelfn->r_info), R_SH_IND12W);
+      /* We used to test (ELF32_R_SYM (irelfn->r_info) < symtab_hdr->sh_info)
+        here, but that only checks if the symbol is an external symbol,
+        not if the symbol is in a different section.  Besides, we need
+        a consistent meaning for the relocation, so we just assume here that
+        the value of the symbol is not available.  */
+#if 0
       if (ELF32_R_SYM (irelfn->r_info) < symtab_hdr->sh_info)
        {
          /* If this needs to be changed because of future relaxing,
@@ -2242,12 +2250,14 @@ sh_elf_relax_section (abfd, sec, link_info, again)
                      contents + irel->r_offset);
        }
       else
+#endif
        {
          /* We can't fully resolve this yet, because the external
             symbol value may be changed by future relaxing.  We let
             the final link phase handle it.  */
          bfd_put_16 (abfd, (bfd_vma) 0xb000, contents + irel->r_offset);
        }
+      irel->r_addend = -4;
 
       /* See if there is another R_SH_USES reloc referring to the same
         register load.  */
@@ -2316,7 +2326,8 @@ sh_elf_relax_section (abfd, sec, link_info, again)
 
   /* Look for load and store instructions that we can align on four
      byte boundaries.  */
-  if (have_code)
+  if ((elf_elfheader (abfd)->e_flags & EF_SH_MACH_MASK) != EF_SH4
+      && have_code)
     {
       bfd_boolean swapped;
 
@@ -2542,14 +2553,28 @@ sh_elf_relax_delete_bytes (abfd, sec, addr, count)
          break;
 
        case R_SH_IND12W:
-         if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info)
-           start = stop = addr;
+         off = insn & 0xfff;
+         if (! off)
+           {
+             /* This has been made by previous relaxation.  Since the
+                relocation will be against an external symbol, the
+                final relocation will just do the right thing.  */
+             start = stop = addr;
+           }
          else
            {
-             off = insn & 0xfff;
              if (off & 0x800)
                off -= 0x1000;
              stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2);
+
+             /* The addend will be against the section symbol, thus
+                for adjusting the addend, the relevant start is the
+                start of the section.
+                N.B. If we want to abandom in-place changes here and
+                test directly using symbol + addend, we have to take into
+                account that the addend has already been adjusted by -4.  */
+             if (stop > addr && stop < toaddr)
+               irel->r_addend -= count;
            }
          break;
 
@@ -4811,7 +4836,6 @@ sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          break;
 
        case R_SH_IND12W:
-         relocation -= 4;
          goto final_link_relocate;
 
        case R_SH_DIR8WPN:
index dc46fb3..e2253a2 100644 (file)
@@ -1,3 +1,17 @@
+Mon Mar  3 20:36:47 2003  J"orn Rennecke <joern.rennecke@superh.com>
+
+       * config/tc-sh.c (sh_dsp): Replace with preset_target_arch.
+       (md_begin): Use preset_target_arch.
+       (md_longopts): Make isa option unconditional.
+       (md_parse_option): Make OPTION_DSP and OPTION_ISA sh4 / any
+       set preset_target_arch.
+       (md_apply_fix3): If BFD_ASSEMBLER, adjust SWITCH_TABLE fixups
+       by -S_GET_VALUE  (fixP->fx_subsy).
+       (tc_gen_reloc): For SWITCH_TABLE fixups, the symbol is fixp->fx_subsy,
+       and the addend is 0.
+       Adjust addend of R_SH_IND12W relocations by fixp->fx_offset - 4.
+       * config/tc-sh.h (TC_FORCE_RELOCATION_SUB_LOCAL): Define.
+
 2003-03-02  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
 
        * config/tc-mips.c (append_insn): Add handling of
index d3a6ac3..c73b81f 100644 (file)
@@ -163,9 +163,9 @@ int sh_relax;               /* set if -relax seen */
 
 int sh_small;
 
-/* Whether -dsp was seen.  */
+/* preset architecture set, if given; zero otherwise.  */
 
-static int sh_dsp;
+static int preset_target_arch;
 
 /* The bit mask of architectures that could
    accomodate the insns seen so far.  */
@@ -867,7 +867,8 @@ md_begin ()
   char *prev_name = "";
   int target_arch;
 
-  target_arch = arch_sh1_up & ~(sh_dsp ? arch_sh3e_up : arch_sh_dsp_up);
+  target_arch
+    = preset_target_arch ? preset_target_arch : arch_sh1_up & ~arch_sh_dsp_up;
   valid_arch = target_arch;
 
 #ifdef HAVE_SH64
@@ -2593,20 +2594,20 @@ struct option md_longopts[] =
 #define OPTION_LITTLE (OPTION_BIG + 1)
 #define OPTION_SMALL (OPTION_LITTLE + 1)
 #define OPTION_DSP (OPTION_SMALL + 1)
+#define OPTION_ISA                    (OPTION_DSP + 1)
 
   {"relax", no_argument, NULL, OPTION_RELAX},
   {"big", no_argument, NULL, OPTION_BIG},
   {"little", no_argument, NULL, OPTION_LITTLE},
   {"small", no_argument, NULL, OPTION_SMALL},
   {"dsp", no_argument, NULL, OPTION_DSP},
+  {"isa",                    required_argument, NULL, OPTION_ISA},
 #ifdef HAVE_SH64
-#define OPTION_ISA                    (OPTION_DSP + 1)
 #define OPTION_ABI                    (OPTION_ISA + 1)
 #define OPTION_NO_MIX                 (OPTION_ABI + 1)
 #define OPTION_SHCOMPACT_CONST_CRANGE (OPTION_NO_MIX + 1)
 #define OPTION_NO_EXPAND              (OPTION_SHCOMPACT_CONST_CRANGE + 1)
 #define OPTION_PT32                   (OPTION_NO_EXPAND + 1)
-  {"isa",                    required_argument, NULL, OPTION_ISA},
   {"abi",                    required_argument, NULL, OPTION_ABI},
   {"no-mix",                 no_argument, NULL, OPTION_NO_MIX},
   {"shcompact-const-crange", no_argument, NULL, OPTION_SHCOMPACT_CONST_CRANGE},
@@ -2642,12 +2643,16 @@ md_parse_option (c, arg)
       break;
 
     case OPTION_DSP:
-      sh_dsp = 1;
+      preset_target_arch = arch_sh1_up & ~arch_sh3e_up;
       break;
 
-#ifdef HAVE_SH64
     case OPTION_ISA:
-      if (strcasecmp (arg, "shmedia") == 0)
+      if (strcasecmp (arg, "sh4") == 0)
+       preset_target_arch = arch_sh4;
+      else if (strcasecmp (arg, "any") == 0)
+       preset_target_arch = arch_sh1_up;
+#ifdef HAVE_SH64
+      else if (strcasecmp (arg, "shmedia") == 0)
        {
          if (sh64_isa_mode == sh64_isa_shcompact)
            as_bad (_("Invalid combination: --isa=SHcompact with --isa=SHmedia"));
@@ -2661,10 +2666,12 @@ md_parse_option (c, arg)
            as_bad (_("Invalid combination: --abi=64 with --isa=SHcompact"));
          sh64_isa_mode = sh64_isa_shcompact;
        }
+#endif /* HAVE_SH64 */
       else
        as_bad ("Invalid argument to --isa option: %s", arg);
       break;
 
+#ifdef HAVE_SH64
     case OPTION_ABI:
       if (strcmp (arg, "32") == 0)
        {
@@ -3381,7 +3388,10 @@ md_apply_fix3 (fixP, valP, seg)
     val -= S_GET_VALUE  (fixP->fx_addsy);
 #endif
 
-#ifndef BFD_ASSEMBLER
+#ifdef BFD_ASSEMBLER
+  if (SWITCH_TABLE (fixP))
+    val -= S_GET_VALUE  (fixP->fx_subsy);
+#else
   if (fixP->fx_r_type == 0)
     {
       if (fixP->fx_size == 2)
@@ -3902,7 +3912,8 @@ tc_gen_reloc (section, fixp)
 
   if (SWITCH_TABLE (fixp))
     {
-      rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy);
+      *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+      rel->addend = 0;
       if (r_type == BFD_RELOC_16)
        r_type = BFD_RELOC_SH_SWITCH16;
       else if (r_type == BFD_RELOC_8)
@@ -3941,6 +3952,8 @@ tc_gen_reloc (section, fixp)
     rel->addend = 0;
 
   rel->howto = bfd_reloc_type_lookup (stdoutput, r_type);
+  if (rel->howto->type == R_SH_IND12W)
+      rel->addend += fixp->fx_offset - 4;
   if (rel->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
index 6537a6d..b1c9bc0 100644 (file)
@@ -235,6 +235,8 @@ extern bfd_boolean sh_fix_adjustable PARAMS ((struct fix *));
    || (FIX)->fx_r_type == BFD_RELOC_SH_GOTPC           \
    || TC_FORCE_RELOCATION (FIX))
 
+#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX) (sh_relax && SWITCH_TABLE (FIX))
+
 /* This keeps the subtracted symbol around, for use by PLT_PCREL
    relocs.  */
 #define TC_FORCE_RELOCATION_SUB_ABS(FIX)               \
index beb85a7..e87cdd2 100644 (file)
@@ -1,3 +1,8 @@
+Mon Mar  3 20:35:58 2003  J"orn Rennecke <joern.rennecke@superh.com>
+
+       * sh.h (EF_SH_MERGE_MACH): Make sure SH2E & SH3/SH3E merge to SH3E,
+       and SH2E & SH4 merge to SH4, not SH2E.
+
 2003-02-21  Ian Wienand  <ianw@gelato.unsw.edu.au>
 
        * ia64.h (SHT_IA_64_LOPSREG, SHT_IA_64_HIPSREG,
index 41bf0bf..00a5f2a 100644 (file)
@@ -56,7 +56,8 @@
    : (((mach1) == EF_SH3E && (mach2) == EF_SH_UNKNOWN) \
       || ((mach2) == EF_SH3E && (mach1) == EF_SH_UNKNOWN)) \
    ? EF_SH4 \
-   : ((mach1) > (mach2) ? (mach1) : (mach2)))
+   : (((mach1) == EF_SH2E ? 7 : (mach1)) > ((mach2) == EF_SH2E ? 7 : (mach2)) \
+      ? (mach1) : (mach2)))
 
 /* Flags for the st_other symbol field.
    Keep away from the STV_ visibility flags (bit 0..1).  */