Add MN10300 linker relaxation support for symbol differences
authorNick Clifton <nickc@redhat.com>
Fri, 19 Oct 2007 17:31:31 +0000 (17:31 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 19 Oct 2007 17:31:31 +0000 (17:31 +0000)
32 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/config.bfd
bfd/elf-m10300.c
bfd/libbfd.h
bfd/reloc.c
gas/ChangeLog
gas/config/tc-mn10300.c
gas/config/tc-mn10300.h
gas/doc/internals.texi
gas/expr.c
gas/testsuite/ChangeLog
gas/testsuite/gas/mn10300/basic.exp
gas/testsuite/gas/mn10300/pr997.l [new file with mode: 0644]
gas/testsuite/gas/mn10300/pr997.s [new file with mode: 0644]
include/elf/ChangeLog
include/elf/mn10300.h
ld/ChangeLog
ld/configure.tgt
ld/testsuite/ChangeLog
ld/testsuite/ld-mn10300/i112045-1.d [new file with mode: 0644]
ld/testsuite/ld-mn10300/i112045-1.s [new file with mode: 0644]
ld/testsuite/ld-mn10300/i112045-2.d [new file with mode: 0644]
ld/testsuite/ld-mn10300/i112045-2.s [new file with mode: 0644]
ld/testsuite/ld-mn10300/i126256-1.c [new file with mode: 0644]
ld/testsuite/ld-mn10300/i126256-2.c [new file with mode: 0644]
ld/testsuite/ld-mn10300/i135409.d [new file with mode: 0644]
ld/testsuite/ld-mn10300/i135409.s [new file with mode: 0644]
ld/testsuite/ld-mn10300/i36434-2.s [new file with mode: 0644]
ld/testsuite/ld-mn10300/i36434.d [new file with mode: 0644]
ld/testsuite/ld-mn10300/i36434.s [new file with mode: 0644]
ld/testsuite/ld-mn10300/mn10300.exp [new file with mode: 0644]

index 6d7fa26..55cfb10 100644 (file)
@@ -1,5 +1,24 @@
 2007-10-19  Nick Clifton  <nickc@redhat.com>
 
+       * config.bfd: Recognise am34-linux-gnu target.
+       * reloc.c: Add BFD_RELOC_MN10300_SYM_DIFF relocation.
+       * bfd-in2.h: Regenerate.
+       * libbfd.h: Regenerate.
+       * elf-m10300.c (elf_mn10300_howto): Add R_MN10300_SYM_DIFF.
+       (mn10300_reloc_map): Likewise.
+       (mn10300_elf_check_relocs): Do not create dynamic relocs for
+       symbol differences or relocations against absolute symbols.
+       (mn10300_elf_final_link_relocate): Likewise.
+       Handle R_MN10300_SYM_DIFF relocs. 
+       (mn10300_elf_relocate_section): Fix for creating local copys of
+       dynamic relocs.
+       (mn10300_elf_relax_delete_bytes): Adjust symbols at the end of the
+       region.  Adjust the size of function symbols.
+       (mn10300_elf_relax_section): Ignore symbols that are in discarded
+       sections.
+
+2007-10-19  Nick Clifton  <nickc@redhat.com>
+
        * elf-m10300.c: Convert to ISO C.
 
 2007-10-18  H.J. Lu  <hongjiu.lu@intel.com>
index e425db1..35aad28 100644 (file)
@@ -2774,6 +2774,11 @@ in the instruction.  */
 /* Adjust by program base.  */
   BFD_RELOC_MN10300_RELATIVE,
 
+/* Together with another reloc targeted at the same location,
+allows for a value that is the difference of two symbols
+in the same section.  */
+  BFD_RELOC_MN10300_SYM_DIFF,
+
 
 /* i386/elf relocations  */
   BFD_RELOC_386_GOT32,
index 899e18e..98183fc 100644 (file)
@@ -71,6 +71,7 @@ esac
 targ_cpu=`echo $targ | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
 case "${targ_cpu}" in
 alpha*)                 targ_archs=bfd_alpha_arch ;;
+am34*|am33_2.0*) targ_archs=bfd_mn10300_arch ;;
 arm*)           targ_archs=bfd_arm_arch ;;
 bfin*)          targ_archs=bfd_bfin_arch ;;
 c30*)           targ_archs=bfd_tic30_arch ;;
@@ -107,7 +108,6 @@ xscale*)     targ_archs=bfd_arm_arch ;;
 xtensa*)        targ_archs=bfd_xtensa_arch ;;
 z80|r800)       targ_archs=bfd_z80_arch ;;
 z8k*)           targ_archs=bfd_z8k_arch ;;
-am33_2.0)       targ_archs=bfd_mn10300_arch ;;
 *)              targ_archs=bfd_${targ_cpu}_arch ;;
 esac
 
@@ -197,9 +197,10 @@ case "${targ}" in
     ;;
 #endif /* BFD64 */
 
-  am33_2.0-*-linux*)
+  am34-*-linux* | am33_2.0-*-linux*)
     targ_defvec=bfd_elf32_am33lin_vec
     ;;
+
   arc-*-elf*)
     targ_defvec=bfd_elf32_littlearc_vec
     targ_selvecs=bfd_elf32_bigarc_vec
index 9aedc06..6c688bd 100644 (file)
@@ -446,6 +446,30 @@ static reloc_howto_type elf_mn10300_howto_table[] =
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
+
+  EMPTY_HOWTO (24),
+  EMPTY_HOWTO (25),
+  EMPTY_HOWTO (26),
+  EMPTY_HOWTO (27),
+  EMPTY_HOWTO (28),
+  EMPTY_HOWTO (29),
+  EMPTY_HOWTO (30),
+  EMPTY_HOWTO (31),
+  EMPTY_HOWTO (32),
+  
+  HOWTO (R_MN10300_SYM_DIFF,   /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        NULL,                  /* special handler.  */
+        "R_MN10300_SYM_DIFF",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE)                 /* pcrel_offset */
 };
 
 struct mn10300_reloc_map
@@ -480,6 +504,7 @@ static const struct mn10300_reloc_map mn10300_reloc_map[] =
   { BFD_RELOC_MN10300_GLOB_DAT, R_MN10300_GLOB_DAT },
   { BFD_RELOC_MN10300_JMP_SLOT, R_MN10300_JMP_SLOT },
   { BFD_RELOC_MN10300_RELATIVE, R_MN10300_RELATIVE },
+  { BFD_RELOC_MN10300_SYM_DIFF, R_MN10300_SYM_DIFF }
 };
 
 /* Create the GOT section.  */
@@ -619,6 +644,7 @@ mn10300_elf_check_relocs (bfd *abfd,
                          asection *sec,
                          const Elf_Internal_Rela *relocs)
 {
+  bfd_boolean sym_diff_reloc_seen;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
@@ -642,6 +668,7 @@ mn10300_elf_check_relocs (bfd *abfd,
   dynobj = elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (abfd);
   rel_end = relocs + sec->reloc_count;
+  sym_diff_reloc_seen = FALSE;
 
   for (rel = relocs; rel < rel_end; rel++)
     {
@@ -814,53 +841,98 @@ mn10300_elf_check_relocs (bfd *abfd,
            h->non_got_ref = 1;
          break;
 
+       case R_MN10300_SYM_DIFF:
+         sym_diff_reloc_seen = TRUE;
+         break;
+
        case R_MN10300_32:
          if (h != NULL)
            h->non_got_ref = 1;
 
-         /* If we are creating a shared library, then we need to copy
-            the reloc into the shared library.  */
+         /* If we are creating a shared library, then we
+            need to copy the reloc into the shared library.  */
          if (info->shared
-             && (sec->flags & SEC_ALLOC) != 0)
+             && (sec->flags & SEC_ALLOC) != 0
+             /* Do not generate a dynamic reloc for a
+                reloc associated with a SYM_DIFF operation.  */
+             && ! sym_diff_reloc_seen)
            {
-             /* When creating a shared object, we must copy these
-                reloc types into the output file.  We create a reloc
-                section in dynobj and make room for this reloc.  */
-             if (sreloc == NULL)
-               {
-                 const char * name;
-
-                 name = (bfd_elf_string_from_elf_section
-                         (abfd,
-                          elf_elfheader (abfd)->e_shstrndx,
-                          elf_section_data (sec)->rel_hdr.sh_name));
-                 if (name == NULL)
-                   return FALSE;
+             asection * sym_section = NULL;
 
-                 BFD_ASSERT (CONST_STRNEQ (name, ".rela")
-                             && streq (bfd_get_section_name (abfd, sec), name + 5));
+             /* Find the section containing the
+                symbol involved in the relocation.  */
+             if (h == NULL)
+               {
+                 Elf_Internal_Sym * isymbuf;
+                 Elf_Internal_Sym * isym;
+
+                 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+                 if (isymbuf == NULL)
+                   isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                                   symtab_hdr->sh_info, 0,
+                                                   NULL, NULL, NULL);
+                 if (isymbuf)
+                   {
+                     isym = isymbuf + r_symndx;
+                     /* All we care about is whether this local symbol is absolute.  */
+                     if (isym->st_shndx == SHN_ABS)
+                       sym_section = bfd_abs_section_ptr;
+                   }
+               }
+             else
+               {
+                 if (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak)
+                   sym_section = h->root.u.def.section;
+               }
 
-                 sreloc = bfd_get_section_by_name (dynobj, name);
+             /* If the symbol is absolute then the relocation can
+                be resolved during linking and there is no need for
+                a dynamic reloc.  */
+             if (sym_section != bfd_abs_section_ptr)
+               {
+                 /* When creating a shared object, we must copy these
+                    reloc types into the output file.  We create a reloc
+                    section in dynobj and make room for this reloc.  */
                  if (sreloc == NULL)
                    {
-                     flagword flags;
+                     const char * name;
 
-                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-                     if ((sec->flags & SEC_ALLOC) != 0)
-                       flags |= SEC_ALLOC | SEC_LOAD;
-                     sreloc = bfd_make_section_with_flags (dynobj, name, flags);
-                     if (sreloc == NULL
-                         || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+                     name = (bfd_elf_string_from_elf_section
+                             (abfd,
+                              elf_elfheader (abfd)->e_shstrndx,
+                              elf_section_data (sec)->rel_hdr.sh_name));
+                     if (name == NULL)
                        return FALSE;
+
+                     BFD_ASSERT (CONST_STRNEQ (name, ".rela")
+                                 && streq (bfd_get_section_name (abfd, sec), name + 5));
+
+                     sreloc = bfd_get_section_by_name (dynobj, name);
+                     if (sreloc == NULL)
+                       {
+                         flagword flags;
+
+                         flags = (SEC_HAS_CONTENTS | SEC_READONLY
+                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+                         if ((sec->flags & SEC_ALLOC) != 0)
+                           flags |= SEC_ALLOC | SEC_LOAD;
+                         sreloc = bfd_make_section_with_flags (dynobj, name, flags);
+                         if (sreloc == NULL
+                             || ! bfd_set_section_alignment (dynobj, sreloc, 2))
+                           return FALSE;
+                       }
                    }
-               }
 
-             sreloc->size += sizeof (Elf32_External_Rela);
+                 sreloc->size += sizeof (Elf32_External_Rela);
+               }
            }
 
          break;
        }
+
+      if (ELF32_R_TYPE (rel->r_info) != R_MN10300_SYM_DIFF)
+       sym_diff_reloc_seen = FALSE;
     }
 
   return TRUE;
@@ -904,6 +976,9 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
                                 asection *sym_sec ATTRIBUTE_UNUSED,
                                 int is_local ATTRIBUTE_UNUSED)
 {
+  static asection *  sym_diff_section;
+  static bfd_vma     sym_diff_value;
+  bfd_boolean is_sym_diff_reloc;
   unsigned long r_type = howto->type;
   bfd_byte * hit_data = contents + offset;
   bfd *      dynobj;
@@ -937,13 +1012,54 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
        return bfd_reloc_dangerous;
     }
 
+  is_sym_diff_reloc = FALSE;
+  if (sym_diff_section != NULL)
+    {
+      BFD_ASSERT (sym_diff_section == input_section);
+
+      switch (r_type)
+       {
+       case R_MN10300_32:
+       case R_MN10300_24:
+       case R_MN10300_16:
+       case R_MN10300_8:
+         value -= sym_diff_value;
+         sym_diff_section = NULL;
+         is_sym_diff_reloc = TRUE;
+         break;
+
+       default:
+         sym_diff_section = NULL;
+         break;
+       }
+    }
+
   switch (r_type)
     {
+    case R_MN10300_SYM_DIFF:
+      BFD_ASSERT (addend == 0);
+      /* Cache the input section and value.
+        The offset is unreliable, since relaxation may
+        have reduced the following reloc's offset.  */
+      sym_diff_section = input_section;
+      sym_diff_value = value;
+      return bfd_reloc_ok;
+
     case R_MN10300_NONE:
       return bfd_reloc_ok;
 
     case R_MN10300_32:
       if (info->shared
+         /* Do not generate relocs when an R_MN10300_32 has been used
+            with an R_MN10300_SYM_DIFF to compute a difference of two
+            symbols.  */
+         && is_sym_diff_reloc == FALSE
+         /* Also, do not generate a reloc when the symbol associated
+            with the R_MN10300_32 reloc is absolute - there is no
+            need for a run time computation in this case.  */
+         && sym_sec != bfd_abs_section_ptr
+         /* If the section is not going to be allocated at load time
+            then there is no need to generate relocs for it.  */
          && (input_section->flags & SEC_ALLOC) != 0)
        {
          Elf_Internal_Rela outrel;
@@ -1370,6 +1486,10 @@ mn10300_elf_relocate_section (bfd *output_bfd,
                      && elf_hash_table (info)->dynamic_sections_created
                      && !SYMBOL_REFERENCES_LOCAL (info, hh))
                  || (r_type == R_MN10300_32
+                     /* _32 relocs in executables force _COPY relocs,
+                        such that the address of the symbol ends up
+                        being local.  */
+                     && !info->executable                    
                      && !SYMBOL_REFERENCES_LOCAL (info, hh)
                      && ((input_section->flags & SEC_ALLOC) != 0
                          /* DWARF will emit R_MN10300_32 relocations
@@ -1551,7 +1671,7 @@ static bfd_boolean
 elf32_mn10300_count_hash_table_entries (struct bfd_hash_entry *gen_entry ATTRIBUTE_UNUSED,
                                        void * in_args)
 {
-  int *count = (int *)in_args;
+  int *count = (int *) in_args;
 
   (*count) ++;
   return TRUE;
@@ -1576,9 +1696,9 @@ static int
 sort_by_value (const void *va, const void *vb)
 {
   struct elf32_mn10300_link_hash_entry *a
-    = *(struct elf32_mn10300_link_hash_entry **)va;
+    = *(struct elf32_mn10300_link_hash_entry **) va;
   struct elf32_mn10300_link_hash_entry *b
-    = *(struct elf32_mn10300_link_hash_entry **)vb;
+    = *(struct elf32_mn10300_link_hash_entry **) vb;
 
   return a->value - b->value;
 }
@@ -1735,8 +1855,14 @@ mn10300_elf_relax_delete_bytes (bfd *abfd,
     {
       if (isym->st_shndx == sec_shndx
          && isym->st_value > addr
-         && isym->st_value < toaddr)
+         && isym->st_value <= toaddr)
        isym->st_value -= count;
+      /* Adjust the function symbol's size as well.  */
+      else if (isym->st_shndx == sec_shndx
+              && ELF_ST_TYPE (isym->st_info) == STT_FUNC
+              && isym->st_value + isym->st_size > addr
+              && isym->st_value + isym->st_size <= toaddr)
+       isym->st_size -= count;
     }
 
   /* Now adjust the global symbols defined in this section.  */
@@ -1752,8 +1878,15 @@ mn10300_elf_relax_delete_bytes (bfd *abfd,
           || sym_hash->root.type == bfd_link_hash_defweak)
          && sym_hash->root.u.def.section == sec
          && sym_hash->root.u.def.value > addr
-         && sym_hash->root.u.def.value < toaddr)
+         && sym_hash->root.u.def.value <= toaddr)
        sym_hash->root.u.def.value -= count;
+      /* Adjust the function symbol's size as well.  */
+      else if (sym_hash->root.type == bfd_link_hash_defined
+              && sym_hash->root.u.def.section == sec
+              && sym_hash->type == STT_FUNC
+              && sym_hash->root.u.def.value + sym_hash->size > addr
+              && sym_hash->root.u.def.value + sym_hash->size <= toaddr)
+       sym_hash->size -= count;
     }
 
   return TRUE;
@@ -1981,7 +2114,7 @@ mn10300_elf_relax_section (bfd *abfd,
                             local symbol in the global hash table.  */
                          amt = strlen (sym_name) + 10;
                          new_name = bfd_malloc (amt);
-                         if (new_name == 0)
+                         if (new_name == NULL)
                            goto error_return;
 
                          sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
@@ -2090,7 +2223,7 @@ mn10300_elf_relax_section (bfd *abfd,
                             local symbol in the global hash table.  */
                          amt = strlen (sym_name) + 10;
                          new_name = bfd_malloc (amt);
-                         if (new_name == 0)
+                         if (new_name == NULL)
                            goto error_return;
 
                          sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
@@ -2302,7 +2435,7 @@ mn10300_elf_relax_section (bfd *abfd,
                     local symbol in the global hash table.  */
                  amt = strlen (sym_name) + 10;
                  new_name = bfd_malloc (amt);
-                 if (new_name == 0)
+                 if (new_name == NULL)
                    goto error_return;
                  sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
                  sym_name = new_name;
@@ -2514,7 +2647,6 @@ mn10300_elf_relax_section (bfd *abfd,
          asection *sym_sec = NULL;
          const char *sym_name;
          char *new_name;
-         bfd_vma saved_addend;
 
          /* A local symbol.  */
          isym = isymbuf + ELF32_R_SYM (irel->r_info);
@@ -2535,22 +2667,22 @@ mn10300_elf_relax_section (bfd *abfd,
              && ELF_ST_TYPE (isym->st_info) == STT_SECTION
              && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE)
            {
+             bfd_vma saved_addend;
+
              saved_addend = irel->r_addend;
-             symval = _bfd_elf_rela_local_sym (abfd, isym, &sym_sec, irel);
+             symval = _bfd_elf_rela_local_sym (abfd, isym, & sym_sec, irel);
              symval += irel->r_addend;
              irel->r_addend = saved_addend;
            }
          else
-           {
-             symval = (isym->st_value
-                       + sym_sec->output_section->vma
-                       + sym_sec->output_offset);
-           }
+           symval = (isym->st_value
+                     + sym_sec->output_section->vma
+                     + sym_sec->output_offset);
 
          /* Tack on an ID so we can uniquely identify this
             local symbol in the global hash table.  */
          new_name = bfd_malloc ((bfd_size_type) strlen (sym_name) + 10);
-         if (new_name == 0)
+         if (new_name == NULL)
            goto error_return;
          sprintf (new_name, "%s_%08x", sym_name, sym_sec->id);
          sym_name = new_name;
@@ -2576,6 +2708,10 @@ mn10300_elf_relax_section (bfd *abfd,
               regular reloc processing.  */
            continue;
 
+         /* Check for a reference to a discarded symbol and ignore it.  */
+         if (h->root.root.u.def.section->output_section == NULL)
+           continue;
+
          symval = (h->root.root.u.def.value
                    + h->root.root.u.def.section->output_section->vma
                    + h->root.root.u.def.section->output_offset);
@@ -3284,7 +3420,7 @@ mn10300_elf_relax_section (bfd *abfd,
                  case 0x93:
                    /* sp-based offsets are zero-extended.  */
                    if (code >= 0x90 && code <= 0x93
-                       && (long)value < 0)
+                       && (long) value < 0)
                      continue;
 
                    /* Note that we've changed the relocation contents, etc.  */
@@ -3341,7 +3477,7 @@ mn10300_elf_relax_section (bfd *abfd,
 
                    /* mov imm16, an zero-extends the immediate.  */
                    if (code == 0xdc
-                       && (long)value < 0)
+                       && (long) value < 0)
                      continue;
 
                    /* Note that we've changed the relocation contents, etc.  */
@@ -3422,12 +3558,12 @@ mn10300_elf_relax_section (bfd *abfd,
                  case 0xe3:
                    /* cmp imm16, an zero-extends the immediate.  */
                    if (code == 0xdc
-                       && (long)value < 0)
+                       && (long) value < 0)
                      continue;
 
                    /* So do sp-based offsets.  */
                    if (code >= 0xb0 && code <= 0xb3
-                       && (long)value < 0)
+                       && (long) value < 0)
                      continue;
 
                    /* Note that we've changed the relocation contents, etc.  */
index 7f10f46..18d01ca 100644 (file)
@@ -1046,6 +1046,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_MN10300_GLOB_DAT",
   "BFD_RELOC_MN10300_JMP_SLOT",
   "BFD_RELOC_MN10300_RELATIVE",
+  "BFD_RELOC_MN10300_SYM_DIFF",
 
   "BFD_RELOC_386_GOT32",
   "BFD_RELOC_386_PLT32",
index 525fe35..aa21875 100644 (file)
@@ -2361,6 +2361,12 @@ ENUM
   BFD_RELOC_MN10300_RELATIVE
 ENUMDOC
   Adjust by program base.
+ENUM
+  BFD_RELOC_MN10300_SYM_DIFF
+ENUMDOC
+  Together with another reloc targeted at the same location,
+  allows for a value that is the difference of two symbols
+  in the same section.
 COMMENT
 
 ENUM
index 5911282..f53d2ab 100644 (file)
@@ -1,3 +1,24 @@
+2007-10-19  Nick Clifton  <nickc@redhat.com>
+
+       * expr.c (expr): Test md_allow_local_subtract (if defined) before
+       allowing the evaluation of an expression involving two symbols
+       defined in the same section.
+       * doc/internals.texi (md_allow_local_subtract): Document the new
+       macro.
+       * config/tc-mn10300.h (md_allow_local_subtract): Define.
+       (RELAX_EXPANSION_POSSIBLE): Define.
+       (MAX_RELOC_EXPANSION): Define.
+       (TC_FRAG_TYPE): Define.
+       * config/tc-mn10300.c (md_assemble): Mark fragments as containing code.
+       (tc_gen_reloc): Return an array of relocs.  If necessary generate
+       two relocs to handle an expressions involving the difference of
+       two symbols.
+       (mn10300_fix_adjustable): Do not test TC_FORCE_RELOCATION_LOCAL
+       when then fixup is not pc-relative.
+       (mn10300_allow_local_subtract): New function.  Determine when it
+       is safe to compute the difference between two symbols at assemble
+       time.
+
 2007-10-19  Alan Modra  <amodra@bigpond.net.au>
 
        * config/tc-ppc.c (ppc_parse_name): Skip leading '%'.
index 671c008..5ec58bb 100644 (file)
@@ -2141,15 +2141,21 @@ keep_going:
 
       dwarf2_emit_insn (size);
     }
+
+  /* Label this frag as one that contains instructions.  */
+  frag_now->tc_frag_data = TRUE;
 }
 
 /* If while processing a fixup, a reloc really needs to be created
    then it is done here.  */
 
-arelent *
+arelent **
 tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 {
+  static arelent * no_relocs = NULL;
+  static arelent * relocs[MAX_RELOC_EXPANSION + 1];
   arelent *reloc;
+
   reloc = xmalloc (sizeof (arelent));
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
@@ -2158,9 +2164,13 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
       as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("reloc %d not supported by object file format"),
                    (int) fixp->fx_r_type);
-      return NULL;
+      free (reloc);
+      return & no_relocs;
     }
+
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+  relocs[0] = reloc;
+  relocs[1] = NULL;
 
   if (fixp->fx_subsy
       && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
@@ -2173,44 +2183,33 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
     {
       reloc->sym_ptr_ptr = NULL;
 
-      /* If we got a difference between two symbols, and the
-        subtracted symbol is in the current section, use a
-        PC-relative relocation.  If both symbols are in the same
-        section, the difference would have already been simplified
-        to a constant.  */
+      /* If we have a difference between two (non-absolute) symbols we must
+        generate two relocs (one for each symbol) and allow the linker to
+        resolve them - relaxation may change the distances between symbols,
+        even local symbols defined in the same segment.  */
       if (S_GET_SEGMENT (fixp->fx_subsy) == seg)
        {
-         reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
-         *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-         reloc->addend = (reloc->address - S_GET_VALUE (fixp->fx_subsy)
-                          + fixp->fx_offset);
+         arelent * reloc2 = xmalloc (sizeof * reloc);
 
-         switch (fixp->fx_r_type)
-           {
-           case BFD_RELOC_8:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_8_PCREL);
-             return reloc;
+         relocs[0] = reloc2;
+         relocs[1] = reloc;
 
-           case BFD_RELOC_16:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_16_PCREL);
-             return reloc;
+         reloc2->address = reloc->address;
+         reloc2->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_MN10300_SYM_DIFF);
+         reloc2->addend = - S_GET_VALUE (fixp->fx_subsy);
+         reloc2->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+         *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
 
-           case BFD_RELOC_24:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_24_PCREL);
-             return reloc;
+         reloc->addend = fixp->fx_offset; 
+         if (S_GET_SEGMENT (fixp->fx_addsy) == absolute_section)
+           reloc->addend += S_GET_VALUE (fixp->fx_addsy);
 
-           case BFD_RELOC_32:
-             reloc->howto = bfd_reloc_type_lookup (stdoutput,
-                                                   BFD_RELOC_32_PCREL);
-             return reloc;
+         reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+         *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
 
-           default:
-             /* Try to compute the absolute value below.  */
-             break;
-           }
+         fixp->fx_pcrel = 0;
+         fixp->fx_done = 1;
+         return relocs;
        }
 
       if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
@@ -2247,14 +2246,14 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
            default:
              reloc->sym_ptr_ptr
                = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
-             return reloc;
+             return relocs;
            }
        }
 
       if (reloc->sym_ptr_ptr)
        free (reloc->sym_ptr_ptr);
       free (reloc);
-      return NULL;
+      return & no_relocs;
     }
   else
     {
@@ -2262,7 +2261,7 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
       *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
       reloc->addend = fixp->fx_offset;
     }
-  return reloc;
+  return relocs;
 }
 
 int
@@ -2377,11 +2376,14 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
 bfd_boolean
 mn10300_fix_adjustable (struct fix *fixp)
 {
-  if (TC_FORCE_RELOCATION_LOCAL (fixp))
-    return FALSE;
-
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+  if (fixp->fx_pcrel)
+    {
+      if (TC_FORCE_RELOCATION_LOCAL (fixp))
+       return FALSE;
+    }
+  /* Non-relative relocs can (and must) be adjusted if they do
+     not meet the criteria below, or the generic criteria.  */
+  else if (TC_FORCE_RELOCATION (fixp))
     return FALSE;
 
   /* Do not adjust relocations involving symbols in code sections,
@@ -2395,8 +2397,9 @@ mn10300_fix_adjustable (struct fix *fixp)
      symbols, because they too break relaxation.  We do want to adjust
      other mergable symbols, like .rodata, because code relaxations
      need section-relative symbols to properly relax them.  */
-  if (! (S_GET_SEGMENT(fixp->fx_addsy)->flags & SEC_MERGE))
+  if (! (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE))
     return FALSE;
+
   if (strncmp (S_GET_SEGMENT (fixp->fx_addsy)->name, ".debug", 6) == 0)
     return FALSE;
 
@@ -2502,3 +2505,60 @@ const pseudo_typeS md_pseudo_table[] =
   { "mn10300", set_arch_mach,  MN103 },
   {NULL, 0, 0}
 };
+
+/* Returns FALSE if there is some mn10300 specific reason why the
+   subtraction of two same-section symbols cannot be computed by
+   the assembler.  */
+
+bfd_boolean
+mn10300_allow_local_subtract (expressionS * left, expressionS * right, segT section)
+{
+  bfd_boolean result;
+  fragS * left_frag;
+  fragS * right_frag;
+  fragS * frag;
+
+  /* If we are not performing linker relaxation then we have nothing
+     to worry about.  */
+  if (linkrelax == 0)
+    return TRUE;
+
+  /* If the symbols are not in a code section then they are OK.  */
+  if ((section->flags & SEC_CODE) == 0)
+    return TRUE;
+
+  /* Otherwise we have to scan the fragments between the two symbols.
+     If any instructions are found then we have to assume that linker
+     relaxation may change their size and so we must delay resolving
+     the subtraction until the final link.  */
+  left_frag = symbol_get_frag (left->X_add_symbol);
+  right_frag = symbol_get_frag (right->X_add_symbol);
+
+  if (left_frag == right_frag)
+    return ! left_frag->tc_frag_data;
+
+  result = TRUE;
+  for (frag = left_frag; frag != NULL; frag = frag->fr_next)
+    {
+      if (frag->tc_frag_data)
+       result = FALSE;
+      if (frag == right_frag)
+       break;
+    }
+
+  if (frag == NULL)
+    for (frag = right_frag; frag != NULL; frag = frag->fr_next)
+      {
+       if (frag->tc_frag_data)
+         result = FALSE;
+       if (frag == left_frag)
+         break;
+      }
+
+  if (frag == NULL)
+    /* The two symbols are on disjoint fragment chains
+       - we cannot possibly compute their difference.  */
+    return FALSE;
+
+  return result;
+}
index 20de21c..af7a6e6 100644 (file)
@@ -98,13 +98,21 @@ void mn10300_cons_fix_new PARAMS ((fragS *, int, int, expressionS *));
 
 #define md_number_to_chars number_to_chars_littleendian
 
-/* Don't bother to adjust relocs.  */
-/* #define tc_fix_adjustable(FIX) 0 */
 #define tc_fix_adjustable(FIX) mn10300_fix_adjustable (FIX)
-extern bfd_boolean mn10300_fix_adjustable PARAMS ((struct fix *));
+extern bfd_boolean mn10300_fix_adjustable (struct fix *);
 
 /* We do relaxing in the assembler as well as the linker.  */
 extern const struct relax_type md_relax_table[];
 #define TC_GENERIC_RELAX_TABLE md_relax_table
 
 #define DWARF2_LINE_MIN_INSN_LENGTH 1
+
+/* The difference between same-section symbols may be affected by linker
+   relaxation, so do not resolve such expressions in the assembler.  */
+#define md_allow_local_subtract(l,r,s) mn10300_allow_local_subtract (l, r, s)
+extern bfd_boolean mn10300_allow_local_subtract (expressionS *, expressionS *, segT);
+
+#define RELOC_EXPANSION_POSSIBLE
+#define MAX_RELOC_EXPANSION 2
+
+#define TC_FRAG_TYPE bfd_boolean
index ff1df98..62f16f7 100644 (file)
@@ -1535,6 +1535,18 @@ The function should return the debug format that is preferred by the CPU
 backend.  This format will be used when generating assembler specific debug
 information.
 
+@item md_allow_local_subtract (@var{left}, @var{right}, @var{section})
+If defined, GAS will call this macro when evaluating an expression which is the
+difference of two symbols defined in the same section.  It takes three
+arguments: @code{expressioS * @var{left}} which is the symbolic expression on
+the left hand side of the subtraction operation, @code{expressionS *
+@var{right}} which is the symbolic expression on the right hand side of the
+subtraction, and @code{segT @var{section}} which is the section containing the two
+symbols.  The macro should return a non-zero value if the expression should be
+evaluated.  Targets which implement link time relaxation which may change the
+position of the two symbols relative to each other should ensure that this
+macro returns zero in situations where this can occur.
+
 @end table
 
 @node Object format backend
index 4f4d380..285b438 100644 (file)
@@ -1738,6 +1738,9 @@ expr (int rankarg,                /* Larger # is higher rank.  */
               && right.X_op == O_symbol
               && resultP->X_op == O_symbol
               && retval == rightseg
+#ifdef md_allow_local_subtract
+              && md_allow_local_subtract (resultP, & right, rightseg)
+#endif
               && (SEG_NORMAL (rightseg)
                   || right.X_add_symbol == resultP->X_add_symbol)
               && frag_offset_fixed_p (symbol_get_frag (resultP->X_add_symbol),
index c180bea..953f096 100644 (file)
@@ -1,3 +1,9 @@
+2007-10-19  Nick Clifton  <nickc@redhat.com>
+
+       * gas/mn10300/basic.exp: Run pr997 test.
+       * gas/mn10300/pr997.s: New test.
+       * gas/mn10300/pr887.l: Expected output.
+
 2007-10-17  Nathan Sidwell  <nathan@codesourcery.com>
 
        * gas/m68k/mcf-movsr.s: New.
index 9b1b53b..c74fcf6 100644 (file)
@@ -1801,6 +1801,7 @@ if [istarget mn10300*-*-*] then {
     do_am33_8
 
     run_list_test "movpc" ""
+    run_list_test "pr997" "-a" 
 
     run_dump_test "am33-2"
     run_dump_test "relax"
diff --git a/gas/testsuite/gas/mn10300/pr997.l b/gas/testsuite/gas/mn10300/pr997.l
new file mode 100644 (file)
index 0000000..b122095
--- /dev/null
@@ -0,0 +1,20 @@
+GAS LISTING .*/pr997.s.*page 1
+
+
+   1.*.data
+   2.*
+   3 0000 68656C6C.*msg:.*.asciz  "hello world.\\n"
+   3      6F20776F 
+   3      726C642E 
+   3      0A00
+   4.*msglen = .-msg-1
+   5.*msglen=msglen & 0xff
+
+.*GAS LISTING.*/pr997.s.*page 2
+
+
+DEFINED SYMBOLS
+.*/pr997.s:3.*.data:0+00 msg
+.*/pr997.s:4.*\*ABS\*:0+0d msglen
+
+NO UNDEFINED SYMBOLS
diff --git a/gas/testsuite/gas/mn10300/pr997.s b/gas/testsuite/gas/mn10300/pr997.s
new file mode 100644 (file)
index 0000000..4a54bbc
--- /dev/null
@@ -0,0 +1,5 @@
+        .data
+
+msg:    .asciz  "hello world.\n"
+msglen = .-msg-1
+msglen=msglen & 0xff
index e7ff097..e8e12ac 100644 (file)
@@ -1,3 +1,7 @@
+2007-10-19  Nick Clifton  <nickc@redhat.com>
+
+       * mn10300.h: Add R_MN10300_SYM_DIFF reloc.
+
 2007-10-18  Roland McGrath  <roland@redhat.com>
 
        * common.h (NT_PPC_VMX): New macro.
index d241e9c..74de473 100644 (file)
@@ -50,6 +50,7 @@ START_RELOC_NUMBERS (elf_mn10300_reloc_type)
   RELOC_NUMBER (R_MN10300_GLOB_DAT, 21)
   RELOC_NUMBER (R_MN10300_JMP_SLOT, 22)
   RELOC_NUMBER (R_MN10300_RELATIVE, 23)
+  RELOC_NUMBER (R_MN10300_SYM_DIFF, 33)
 END_RELOC_NUMBERS (R_MN10300_MAX)
 
 /* Machine variant if we know it.  This field was invented at Cygnus,
index 38b0146..1ecce86 100644 (file)
@@ -1,3 +1,7 @@
+2007-10-19  Nick Clifton  <nickc@redhat.com>
+
+       * configure.tgt: Add support for am34-linux-gnu target.
+
 2007-10-17  Zack Weinberg  <zack@codesourcery.com>
 
        * ldlang.c (lang_check_section_addresses): Also report size of
index d4f53ef..e897d1e 100644 (file)
@@ -400,6 +400,7 @@ mips*-*-sysv4*)         targ_emul=elf32btsmip
 mmix-*-*)              targ_emul=mmo
                        targ_extra_emuls=elf64mmix
                        ;;
+am34-*-linux*)         targ_emul=elf32am33lin ;;
 am33_2.0-*-linux*)     targ_emul=elf32am33lin ;;
 mn10200-*-*)           targ_emul=mn10200 ;;
 mn10300-*-*)           targ_emul=mn10300
index ffc2296..db66430 100644 (file)
@@ -1,3 +1,19 @@
+2007-10-19  Nick Clifton  <nickc@redhat.com>
+
+       * ld-mn10300: New test directory.
+       * ld-mn10300/mn10300.exp: Run the new tests.
+       * ld-mn10300/i112045-1.s: Linker relaxation test.
+       * ld-mn10300/i112045-1.d: Expected disassembly.
+       * ld-mn10300/i112045-2.s: Linker relaxation test.
+       * ld-mn10300/i112045-2.d: Expected disassembly.
+       * ld-mn10300/i126256-1.c: Test source.
+       * ld-mn10300/i126256-2.c: Test source.
+       * ld-mn10300/i135409.s: Linker relaxation test.
+       * ld-mn10300/i135409.d: Expected symbol table contents.
+       * ld-mn10300/i136434.s: Linker string section merge test.
+       * ld-mn10300/i136434.d: Expected disassembly.
+       * ld-mn10300/i136434-2.s: Test source file.
+
 2007-10-17  Zack Weinberg  <zack@codesourcery.com>
            Daniel Jacobowitz  <dan@codesourcery.com>
            Mark Shinwell  <shinwell@codesourcery.com>
diff --git a/ld/testsuite/ld-mn10300/i112045-1.d b/ld/testsuite/ld-mn10300/i112045-1.d
new file mode 100644 (file)
index 0000000..dcb5a41
--- /dev/null
@@ -0,0 +1,22 @@
+
+tmpdir/i112045-1.x:     file format elf32-.*
+
+Disassembly of section .text:
+
+0+0 <_start>:
+   0:  fc d0 f8 0f[    ]+add   4088,a0
+   4:  00 00 
+   6:  cb[     ]+nop[  ]+
+   7:  cb[     ]+nop[  ]+
+
+0+08 <L01>:
+   8:  fc d0 2b 01[    ]+add   299,a0
+   c:  00 00 
+   e:  cb[     ]+nop[  ]+
+   f:  cb[     ]+nop[  ]+
+
+0+010 <L02>:
+  10:  fc d0 08 00[    ]+add   8,a0
+  14:  00 00 
+  16:  cb[     ]+nop[  ]+
+  17:  cb[     ]+nop[  ]+
diff --git a/ld/testsuite/ld-mn10300/i112045-1.s b/ld/testsuite/ld-mn10300/i112045-1.s
new file mode 100644 (file)
index 0000000..b9e0346
--- /dev/null
@@ -0,0 +1,14 @@
+       .text
+       .global _start
+_start:
+       add     0x1000 - L01, A0
+       nop
+       nop
+L01:
+       add     L01 + 0x123, A0
+       nop
+       nop
+L02:
+       add     L02 - L01, A0
+       nop
+       nop
diff --git a/ld/testsuite/ld-mn10300/i112045-2.d b/ld/testsuite/ld-mn10300/i112045-2.d
new file mode 100644 (file)
index 0000000..9aa2d82
--- /dev/null
@@ -0,0 +1,6 @@
+
+tmpdir/i112045-2.x:     file format elf32-.*
+
+DYNAMIC RELOCATION RECORDS
+OFFSET   TYPE              VALUE 
+[0-9a-f]+ R_MN10300_RELATIVE  \*ABS\*\+0x[0-9a-f]+
diff --git a/ld/testsuite/ld-mn10300/i112045-2.s b/ld/testsuite/ld-mn10300/i112045-2.s
new file mode 100644 (file)
index 0000000..90e942d
--- /dev/null
@@ -0,0 +1,12 @@
+       .section .data
+L01:
+       .long   L04 - L01
+L02:
+       .long   L04 - L02
+L03:
+       .long   L04 - L03
+L04:
+       .long   L04
+        .long   L00
+        .equ    L00, 0xff
+
diff --git a/ld/testsuite/ld-mn10300/i126256-1.c b/ld/testsuite/ld-mn10300/i126256-1.c
new file mode 100644 (file)
index 0000000..5907d87
--- /dev/null
@@ -0,0 +1,7 @@
+void
+sub0 (int i)
+{
+  extern int sub (int);
+
+  sub (i);
+}
diff --git a/ld/testsuite/ld-mn10300/i126256-2.c b/ld/testsuite/ld-mn10300/i126256-2.c
new file mode 100644 (file)
index 0000000..2948e5b
--- /dev/null
@@ -0,0 +1,5 @@
+int
+sub (int i)
+{
+  return i + 10;
+}
diff --git a/ld/testsuite/ld-mn10300/i135409.d b/ld/testsuite/ld-mn10300/i135409.d
new file mode 100644 (file)
index 0000000..2d64a42
--- /dev/null
@@ -0,0 +1,11 @@
+
+Symbol table '.symtab' contains .. entries:
+   Num:    Value  Size Type    Bind   Vis      Ndx Name
+#...
+    ..: 0[0-9a-f]+[    ]+7 FUNC    LOCAL  DEFAULT    . _func
+#...
+    ..: 0[0-9a-f]+[    ]+0 NOTYPE  LOCAL  DEFAULT    . A
+    ..: 0[0-9a-f]+[    ]+7 FUNC    GLOBAL DEFAULT    . _func2
+#...
+    ..: 0[0-9a-f]+[    ]+0 NOTYPE  GLOBAL DEFAULT    . BOTTOM
+#...
diff --git a/ld/testsuite/ld-mn10300/i135409.s b/ld/testsuite/ld-mn10300/i135409.s
new file mode 100644 (file)
index 0000000..b9faaf4
--- /dev/null
@@ -0,0 +1,29 @@
+       .text
+
+       nop
+
+        .global _start
+_start:
+        .type   _func, @function
+_func:
+        mov     L001,A1
+        nop
+A:
+        mov     L001,A1
+        .size   _func, . - _func
+
+
+        .global _func2
+_func2:
+        .type   _func2, @function
+        mov     L001,A1
+        nop
+        mov     L001,A1
+        .size   _func2, . - _func2
+
+        .global BOTTOM
+BOTTOM:
+       
+        .data
+L001:
+
diff --git a/ld/testsuite/ld-mn10300/i36434-2.s b/ld/testsuite/ld-mn10300/i36434-2.s
new file mode 100644 (file)
index 0000000..cf31ce1
--- /dev/null
@@ -0,0 +1,16 @@
+       .section .text
+       .global _bar
+       .type   _bar,@function
+_bar:
+       mov     .LC1,d0
+       mov     .LC2,d1
+       nop
+
+       .section        .rodata.str1.1,"aMS",@progbits,1
+.LC1:
+       .rept   32768
+       .byte   'a'
+       .endr
+       .byte   0
+.LC2:
+       .string "abc\n"
diff --git a/ld/testsuite/ld-mn10300/i36434.d b/ld/testsuite/ld-mn10300/i36434.d
new file mode 100644 (file)
index 0000000..25cea45
--- /dev/null
@@ -0,0 +1,16 @@
+
+tmpdir/i36434.x:     file format elf32-.*
+
+Disassembly of section .text:
+
+08000000 <_start>:
+ 8000000:      fc cd 18 80     mov     134250520,d1
+ 8000004:      00 08 
+ 8000006:      cb              nop     
+
+08000007 <_bar>:
+ 8000007:      fc cc 14 00     mov     134217748,d0
+ 800000b:      00 08 
+ 800000d:      fc cd 15 80     mov     134250517,d1
+ 8000011:      00 08 
+ 8000013:      cb              nop     
diff --git a/ld/testsuite/ld-mn10300/i36434.s b/ld/testsuite/ld-mn10300/i36434.s
new file mode 100644 (file)
index 0000000..84c1d83
--- /dev/null
@@ -0,0 +1,10 @@
+       .section .text
+       .global _start
+       .type   _start,@function
+_start:
+       mov     .LC2,d1
+       nop
+
+       .section        .rodata.str1.1,"aMS",@progbits,1
+.LC2:
+       .string "\n"
diff --git a/ld/testsuite/ld-mn10300/mn10300.exp b/ld/testsuite/ld-mn10300/mn10300.exp
new file mode 100644 (file)
index 0000000..14ba85b
--- /dev/null
@@ -0,0 +1,94 @@
+# Expect script for ld-mn10300 tests
+#   Copyright (C) 2007 Free Software Foundation
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+if {!([istarget "am3*-*-*"]) && !([istarget "mn10300*-*-*"]) } {
+    return
+}
+
+# Set up a list as described in ld-lib.exp
+
+set am33_tests {
+    {
+       "am33 string merging"
+       "--relax -Ttext 0x8000000"
+       ""
+       { "i36434.s" "i36434-2.s" }
+       { {objdump -dz i36434.d} }
+       "i36434.x"
+    }
+    {
+       "difference of two symbols"
+       "-Ttext 0"
+       ""
+       { "i112045-1.s" }
+       { {objdump -d i112045-1.d} }
+       "i112045-1.x"
+    }
+    {
+       "(shared) difference of two symbols"
+       "-shared"
+       ""
+       { "i112045-2.s" }
+       { {objdump -R i112045-2.d} }
+       "i112045-2.x"
+    }
+    {
+       "adjustment of symbols due to relaxation"
+       "-Tdata 1f -relax"
+       ""
+       { "i135409.s" }
+       { {readelf --syms i135409.d } }
+       "i135409.x"
+    }
+}
+
+run_ld_link_tests $am33_tests
+
+proc i126256-test { } {
+    global CC
+    global ld
+    global srcdir
+    global subdir
+
+    set tmpdir tmpdir
+    set testname "Issue 126256 - seg fault whilst linking one shared library into another when relaxation is enabled."
+
+    if { ![ld_compile "$CC -mrelax -fPIC" $srcdir/$subdir/i126256-1.c $tmpdir/i126256-1.o] } {
+       unresolved $testname
+       return
+    }
+
+    if { ![ld_compile "$CC -mrelax -fPIC" $srcdir/$subdir/i126256-2.c $tmpdir/i126256-2.o] } {
+       unresolved $testname
+       return
+    }
+    
+    if { ![ld_simple_link $ld $tmpdir/i126256-1.so "-shared $tmpdir/i126256-1.o -e 0"]} {
+        unresolved $testname
+       return
+    }
+
+    if { ![ld_simple_link $ld $tmpdir/i126256-2.so "--relax -shared $tmpdir/i126256-2.o $tmpdir/i126256-1.so -e 0"]} {
+        fail $testname
+       return
+    }
+
+    pass $testname
+}
+
+i126256-test