PR 11042
[deliverable/binutils-gdb.git] / bfd / elf-m10300.c
index 9a75b7c76761126d0ac8b44f13a09244df29e4f9..4a9d4b051e0df36505cff1b86747444d82349091 100644 (file)
@@ -1,6 +1,6 @@
 /* Matsushita 10300 specific support for 32-bit ELF
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2006, 2007 Free Software Foundation, Inc.
+   2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -661,6 +661,7 @@ mn10300_elf_check_relocs (bfd *abfd,
 {
   bfd_boolean sym_diff_reloc_seen;
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Sym * isymbuf = NULL;
   struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
@@ -669,6 +670,7 @@ mn10300_elf_check_relocs (bfd *abfd,
   asection * sgot;
   asection * srelgot;
   asection * sreloc;
+  bfd_boolean result = FALSE;
 
   sgot    = NULL;
   srelgot = NULL;
@@ -678,6 +680,7 @@ mn10300_elf_check_relocs (bfd *abfd,
     return TRUE;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
   sym_hashes = elf_sym_hashes (abfd);
 
   dynobj = elf_hash_table (info)->dynobj;
@@ -689,6 +692,7 @@ mn10300_elf_check_relocs (bfd *abfd,
     {
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
+      unsigned int r_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -701,10 +705,12 @@ mn10300_elf_check_relocs (bfd *abfd,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
+      r_type = ELF32_R_TYPE (rel->r_info);
+
       /* Some relocs require a global offset table.  */
       if (dynobj == NULL)
        {
-         switch (ELF32_R_TYPE (rel->r_info))
+         switch (r_type)
            {
            case R_MN10300_GOT32:
            case R_MN10300_GOT24:
@@ -716,7 +722,7 @@ mn10300_elf_check_relocs (bfd *abfd,
            case R_MN10300_GOTPC16:
              elf_hash_table (info)->dynobj = dynobj = abfd;
              if (! _bfd_mn10300_elf_create_got_section (dynobj, info))
-               return FALSE;
+               goto fail;
              break;
 
            default:
@@ -724,13 +730,13 @@ mn10300_elf_check_relocs (bfd *abfd,
            }
        }
 
-      switch (ELF32_R_TYPE (rel->r_info))
+      switch (r_type)
        {
        /* This relocation describes the C++ object vtable hierarchy.
           Reconstruct it for later use during GC.  */
        case R_MN10300_GNU_VTINHERIT:
          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
-           return FALSE;
+           goto fail;
          break;
 
        /* This relocation describes which C++ vtable entries are actually
@@ -739,8 +745,9 @@ mn10300_elf_check_relocs (bfd *abfd,
          BFD_ASSERT (h != NULL);
          if (h != NULL
              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-           return FALSE;
+           goto fail;
          break;
+
        case R_MN10300_GOT32:
        case R_MN10300_GOT24:
        case R_MN10300_GOT16:
@@ -768,7 +775,7 @@ mn10300_elf_check_relocs (bfd *abfd,
                                                          | SEC_READONLY));
                  if (srelgot == NULL
                      || ! bfd_set_section_alignment (dynobj, srelgot, 2))
-                   return FALSE;
+                   goto fail;
                }
            }
 
@@ -784,7 +791,7 @@ mn10300_elf_check_relocs (bfd *abfd,
              if (h->dynindx == -1)
                {
                  if (! bfd_elf_link_record_dynamic_symbol (info, h))
-                   return FALSE;
+                   goto fail;
                }
 
              srelgot->size += sizeof (Elf32_External_Rela);
@@ -802,7 +809,8 @@ mn10300_elf_check_relocs (bfd *abfd,
                  local_got_offsets = bfd_alloc (abfd, size);
 
                  if (local_got_offsets == NULL)
-                   return FALSE;
+                   goto fail;
+
                  elf_local_got_offsets (abfd) = local_got_offsets;
 
                  for (i = 0; i < symtab_hdr->sh_info; i++)
@@ -878,10 +886,8 @@ mn10300_elf_check_relocs (bfd *abfd,
                 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,
@@ -911,32 +917,10 @@ mn10300_elf_check_relocs (bfd *abfd,
                     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;
-
-                     BFD_ASSERT (CONST_STRNEQ (name, ".rela")
-                                 && streq (bfd_get_section_name (abfd, sec), name + 5));
-
-                     sreloc = bfd_get_section_by_name (dynobj, name);
+                     sreloc = _bfd_elf_make_dynamic_reloc_section
+                       (sec, dynobj, 2, abfd, /*rela?*/ TRUE);
                      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;
-                       }
+                       goto fail;
                    }
 
                  sreloc->size += sizeof (Elf32_External_Rela);
@@ -950,7 +934,12 @@ mn10300_elf_check_relocs (bfd *abfd,
        sym_diff_reloc_seen = FALSE;
     }
 
-  return TRUE;
+  result = TRUE;
+ fail:
+  if (isymbuf != NULL)
+    free (isymbuf);
+
+  return result;
 }
 
 /* Return the section that should be marked against GC for a given
@@ -1097,22 +1086,10 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
             time.  */
          if (sreloc == NULL)
            {
-             const char * name;
-
-             name = (bfd_elf_string_from_elf_section
-                     (input_bfd,
-                      elf_elfheader (input_bfd)->e_shstrndx,
-                      elf_section_data (input_section)->rel_hdr.sh_name));
-             if (name == NULL)
+             sreloc = _bfd_elf_get_dynamic_reloc_section
+               (input_bfd, input_section, /*rela?*/ TRUE);
+             if (sreloc == NULL)
                return FALSE;
-
-             BFD_ASSERT (CONST_STRNEQ (name, ".rela")
-                         && streq (bfd_get_section_name (input_bfd,
-                                                         input_section),
-                                   name + 5));
-
-             sreloc = bfd_get_section_by_name (dynobj, name);
-             BFD_ASSERT (sreloc != NULL);
            }
 
          skip = FALSE;
@@ -1201,7 +1178,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xff || (long) value < -0x100)
+      if ((long) value > 0x7f || (long) value < -0x80)
        return bfd_reloc_overflow;
 
       bfd_put_8 (input_bfd, value, hit_data);
@@ -1213,7 +1190,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1253,7 +1230,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1285,7 +1262,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
                                        ".got")->output_section->vma;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1297,8 +1274,6 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
          && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
          && h->plt.offset != (bfd_vma) -1)
        {
-         asection * splt;
-
          splt = bfd_get_section_by_name (dynobj, ".plt");
 
          value = (splt->output_section->vma
@@ -1320,8 +1295,6 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
          && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN
          && h->plt.offset != (bfd_vma) -1)
        {
-         asection * splt;
-
          splt = bfd_get_section_by_name (dynobj, ".plt");
 
          value = (splt->output_section->vma
@@ -1334,7 +1307,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
       value -= offset;
       value += addend;
 
-      if ((long) value > 0xffff || (long) value < -0x10000)
+      if ((long) value > 0x7fff || (long) value < -0x8000)
        return bfd_reloc_overflow;
 
       bfd_put_16 (input_bfd, value, hit_data);
@@ -1344,8 +1317,6 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
     case R_MN10300_GOT24:
     case R_MN10300_GOT16:
       {
-       asection * sgot;
-
        sgot = bfd_get_section_by_name (dynobj, ".got");
 
          if (h != NULL)
@@ -1422,7 +1393,7 @@ mn10300_elf_final_link_relocate (reloc_howto_type *howto,
        }
       else if (r_type == R_MN10300_GOT16)
        {
-         if ((long) value > 0xffff || (long) value < -0x10000)
+         if ((long) value > 0x7fff || (long) value < -0x8000)
            return bfd_reloc_overflow;
 
          bfd_put_16 (input_bfd, value, hit_data);
@@ -1516,7 +1487,7 @@ mn10300_elf_relocate_section (bfd *output_bfd,
                      /* _32 relocs in executables force _COPY relocs,
                         such that the address of the symbol ends up
                         being local.  */
-                     && !info->executable                    
+                     && !info->executable
                      && !SYMBOL_REFERENCES_LOCAL (info, hh)
                      && ((input_section->flags & SEC_ALLOC) != 0
                          /* DWARF will emit R_MN10300_32 relocations
@@ -2094,6 +2065,11 @@ mn10300_elf_relax_section (bfd *abfd,
   Elf_Internal_Sym *isymbuf = NULL;
   struct elf32_mn10300_link_hash_table *hash_table;
   asection *section = sec;
+  bfd_vma align_gap_adjustment;
+
+  if (link_info->relocatable)
+    (*link_info->callbacks->einfo)
+      (_("%P%F: --relax and -r may not be used together\n"));
 
   /* Assume nothing changes.  */
   *again = FALSE;
@@ -2707,11 +2683,40 @@ mn10300_elf_relax_section (bfd *abfd,
   if (internal_relocs == NULL)
     goto error_return;
 
+  /* Scan for worst case alignment gap changes.  Note that this logic
+     is not ideal; what we should do is run this scan for every
+     opcode/address range and adjust accordingly, but that's
+     expensive.  Worst case is that for an alignment of N bytes, we
+     move by 2*N-N-1 bytes, assuming we have aligns of 1, 2, 4, 8, etc
+     all before it.  Plus, this still doesn't cover cross-section
+     jumps with section alignment.  */
+  irelend = internal_relocs + sec->reloc_count;
+  align_gap_adjustment = 0;
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN)
+       {
+         bfd_vma adj = 1 << irel->r_addend;
+         bfd_vma aend = irel->r_offset;
+
+         aend = BFD_ALIGN (aend, 1 << irel->r_addend);
+         adj = 2 * adj - adj - 1;
+
+         /* Record the biggest adjustmnet.  Skip any alignment at the
+            end of our section.  */
+         if (align_gap_adjustment < adj
+             && aend < sec->output_section->vma + sec->output_offset + sec->size)
+           align_gap_adjustment = adj;
+       }
+    }
+
   /* Walk through them looking for relaxing opportunities.  */
   irelend = internal_relocs + sec->reloc_count;
   for (irel = internal_relocs; irel < irelend; irel++)
     {
       bfd_vma symval;
+      bfd_signed_vma jump_offset;
+      asection *sym_sec = NULL;
       struct elf32_mn10300_link_hash_entry *h = NULL;
 
       /* If this isn't something that can be relaxed, then ignore
@@ -2751,7 +2756,6 @@ mn10300_elf_relax_section (bfd *abfd,
       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
          Elf_Internal_Sym *isym;
-         asection *sym_sec = NULL;
          const char *sym_name;
          char *new_name;
 
@@ -2771,15 +2775,32 @@ mn10300_elf_relax_section (bfd *abfd,
                                                      isym->st_name);
 
          if ((sym_sec->flags & SEC_MERGE)
-             && 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 += irel->r_addend;
-             irel->r_addend = saved_addend;
+             symval = isym->st_value;
+
+             /* GAS may reduce relocations against symbols in SEC_MERGE
+                sections to a relocation against the section symbol when
+                the original addend was zero.  When the reloc is against
+                a section symbol we should include the addend in the
+                offset passed to _bfd_merged_section_offset, since the
+                location of interest is the original symbol.  On the
+                other hand, an access to "sym+addend" where "sym" is not
+                a section symbol should not include the addend;  Such an
+                access is presumed to be an offset from "sym";  The
+                location of interest is just "sym".  */
+             if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+               symval += irel->r_addend;
+
+             symval = _bfd_merged_section_offset (abfd, & sym_sec,
+                                                  elf_section_data (sym_sec)->sec_info,
+                                                  symval);
+
+             if (ELF_ST_TYPE (isym->st_info) != STT_SECTION)
+               symval += irel->r_addend;
+
+             symval += sym_sec->output_section->vma
+               + sym_sec->output_offset - irel->r_addend;
            }
          else
            symval = (isym->st_value
@@ -2819,6 +2840,8 @@ mn10300_elf_relax_section (bfd *abfd,
          if (h->root.root.u.def.section->output_section == NULL)
            continue;
 
+         sym_sec = h->root.root.u.def.section->output_section;
+
          symval = (h->root.root.u.def.value
                    + h->root.root.u.def.section->output_section->vma
                    + h->root.root.u.def.section->output_offset);
@@ -2921,8 +2944,16 @@ mn10300_elf_relax_section (bfd *abfd,
 
          /* See if the value will fit in 16 bits, note the high value is
             0x7fff + 2 as the target will be two bytes closer if we are
-            able to relax.  */
-         if ((long) value < 0x8001 && (long) value > -0x8000)
+            able to relax, if it's in the same section.  */
+         if (sec->output_section == sym_sec->output_section)
+           jump_offset = 0x8001;
+         else
+           jump_offset = 0x7fff;
+
+         /* Account for jumps across alignment boundaries using
+            align_gap_adjustment.  */
+         if ((bfd_signed_vma) value < jump_offset - (bfd_signed_vma) align_gap_adjustment
+             && ((bfd_signed_vma) value > -0x8000 + (bfd_signed_vma) align_gap_adjustment))
            {
              unsigned char code;
 
This page took 0.028911 seconds and 4 git commands to generate.