* elflink.c (_bfd_elf_link_create_dynamic_sections): Move from
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 9947af855fee8d996ce6ae2cebf4347ccc39a937..64c2839f42170043552f794e0c45071511156e77 100644 (file)
@@ -16,8 +16,9 @@
    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.  */
+   along with this program; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 /* This file is based on a preliminary PowerPC ELF ABI.  The
    information may not match the final PowerPC ELF ABI.  It includes
@@ -147,7 +148,11 @@ static bfd_boolean ppc_elf_grok_psinfo
 #define DTP_OFFSET     0x8000
 
 /* Will references to this symbol always reference the symbol
-   in this object?  */
+   in this object?  STV_PROTECTED is excluded from the visibility test
+   here so that function pointer comparisons work properly.  Since
+   function symbols not defined in an app are set to their .plt entry,
+   it's necessary for shared libs to also reference the .plt even
+   though the symbol is really local to the shared lib.  */
 #define SYMBOL_REFERENCES_LOCAL(INFO, H)                               \
   ((! INFO->shared                                                     \
     || INFO->symbolic                                                  \
@@ -157,7 +162,7 @@ static bfd_boolean ppc_elf_grok_psinfo
    && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
 
 /* Will _calls_ to this symbol always call the version in this object?  */
-#define SYMBOL_CALLS_LOCAL(INFO, H)                            \
+#define SYMBOL_CALLS_LOCAL(INFO, H)                                    \
   ((! INFO->shared                                                     \
     || INFO->symbolic                                                  \
     || H->dynindx == -1                                                        \
@@ -194,7 +199,7 @@ struct ppc_elf_link_hash_entry
   struct ppc_elf_dyn_relocs *dyn_relocs;
 
   /* Contexts in which symbol is used in the GOT (or TOC).
-     TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the
+     TLS_GD .. TLS_TLS bits are or'd into the mask as the
      corresponding relocs are encountered during check_relocs.
      tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to
      indicate the corresponding GOT entry type is not needed.  */
@@ -315,6 +320,12 @@ ppc_elf_link_hash_table_create (abfd)
   return &ret->elf.root;
 }
 
+/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
+   copying dynamic variables from a shared lib into an app's dynbss
+   section, and instead use a dynamic relocation to point into the
+   shared lib.  */
+#define ELIMINATE_COPY_RELOCS 1
+
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
@@ -363,7 +374,18 @@ ppc_elf_copy_indirect_symbol (bed, dir, ind)
 
   edir->tls_mask |= eind->tls_mask;
 
-  _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
+  if (ELIMINATE_COPY_RELOCS
+      && ind->root.type != bfd_link_hash_indirect
+      && (dir->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0)
+    /* If called to transfer flags for a weakdef during processing
+       of elf_adjust_dynamic_symbol, don't copy ELF_LINK_NON_GOT_REF.
+       We clear it ourselves for ELIMINATE_COPY_RELOCS.  */
+    dir->elf_link_hash_flags |=
+      (ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC
+                                  | ELF_LINK_HASH_REF_REGULAR
+                                  | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
+  else
+    _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
 }
 \f
 static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max];
@@ -1609,10 +1631,14 @@ ppc_elf_howto_init ()
 {
   unsigned int i, type;
 
-  for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++)
+  for (i = 0;
+       i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]);
+       i++)
     {
       type = ppc_elf_howto_raw[i].type;
-      BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0]));
+      if (type >= (sizeof (ppc_elf_howto_table)
+                  / sizeof (ppc_elf_howto_table[0])))
+       abort ();
       ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i];
     }
 }
@@ -1626,7 +1652,8 @@ ppc_elf_howto_init ()
    2/ The branch is predicted as not taken.
    3/ The branch is taken.
    4/ The branch is located in the last 5 words of a page.
-      (The EOP limit is 5 by default but may be specified as any value from 1-10.)
+      (The EOP limit is 5 by default but may be specified as any value
+      from 1-10.)
 
    Our software solution is to detect these problematic branches in a
    linker pass and modify them as follows:
@@ -1708,9 +1735,9 @@ ppc_elf_relax_section (abfd, isec, link_info, again)
 
          /* Get a copy of the native relocations.  */
          internal_relocs
-           = _bfd_elf32_link_read_relocs (abfd, isec, (PTR) NULL,
-                                          (Elf_Internal_Rela *) NULL,
-                                          link_info->keep_memory);
+           = _bfd_elf_link_read_relocs (abfd, isec, (PTR) NULL,
+                                        (Elf_Internal_Rela *) NULL,
+                                        link_info->keep_memory);
          if (internal_relocs == NULL)
            goto error_return;
          if (! link_info->keep_memory)
@@ -2300,7 +2327,7 @@ ppc_elf_create_linker_section (abfd, info, which)
       switch (which)
        {
        default:
-         (*_bfd_error_handler) (_("%s: Unknown special linker type %d"),
+         (*_bfd_error_handler) (_("%s: unknown special linker type %d"),
                                 bfd_get_filename (abfd),
                                 (int) which);
 
@@ -2451,12 +2478,6 @@ ppc_elf_create_dynamic_sections (abfd, info)
   return bfd_set_section_flags (abfd, s, flags);
 }
 
-/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
-   copying dynamic variables from a shared lib into an app's dynbss
-   section, and instead use a dynamic relocation to point into the
-   shared lib.  */
-#define ELIMINATE_COPY_RELOCS 1
-
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -2496,7 +2517,7 @@ ppc_elf_adjust_dynamic_symbol (info, h)
       /* Clear procedure linkage table information for any symbol that
         won't need a .plt entry.  */
       if (! htab->elf.dynamic_sections_created
-         || SYMBOL_CALLS_LOCAL (info, h)
+         || SYMBOL_CALLS_LOCAL (info, h)
          || h->plt.refcount <= 0)
        {
          /* A PLT entry is not required/allowed when:
@@ -2525,6 +2546,10 @@ ppc_elf_adjust_dynamic_symbol (info, h)
                  || h->weakdef->root.type == bfd_link_hash_defweak);
       h->root.u.def.section = h->weakdef->root.u.def.section;
       h->root.u.def.value = h->weakdef->root.u.def.value;
+      if (ELIMINATE_COPY_RELOCS)
+       h->elf_link_hash_flags
+         = ((h->elf_link_hash_flags & ~ELF_LINK_NON_GOT_REF)
+            | (h->weakdef->elf_link_hash_flags & ELF_LINK_NON_GOT_REF));
       return TRUE;
     }
 
@@ -2669,7 +2694,9 @@ allocate_dynrelocs (h, inf)
 
   htab = ppc_elf_hash_table (info);
   if (htab->elf.dynamic_sections_created
-      && h->plt.refcount > 0)
+      && h->plt.refcount > 0
+      && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+         || h->root.type != bfd_link_hash_undefweak))
     {
       /* Make sure this symbol is output as a dynamic symbol.  */
       if (h->dynindx == -1
@@ -2764,8 +2791,10 @@ allocate_dynrelocs (h, inf)
          else
            htab->got->_raw_size += 4;
          dyn = htab->elf.dynamic_sections_created;
-         if (info->shared
-             || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
+         if ((info->shared
+              || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
+             && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
+                 || eh->elf.root.type != bfd_link_hash_undefweak))
            {
              /* All the entries we allocated need relocs.  */
              htab->relgot->_raw_size
@@ -2806,6 +2835,12 @@ allocate_dynrelocs (h, inf)
                pp = &p->next;
            }
        }
+
+      /* Also discard relocs on undefined weak syms with non-default
+        visibility.  */
+      if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+         && h->root.type == bfd_link_hash_undefweak)
+       eh->dyn_relocs = NULL;
     }
   else if (ELIMINATE_COPY_RELOCS)
     {
@@ -3455,8 +3490,7 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
        case R_PPC_REL14_BRNTAKEN:
        case R_PPC_REL32:
          if (h == NULL
-             || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
-             || SYMBOL_REFERENCES_LOCAL (info, h))
+             || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
            break;
          /* fall through */
 
@@ -3741,8 +3775,7 @@ ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
        case R_PPC_REL14_BRNTAKEN:
        case R_PPC_REL32:
          if (h == NULL
-             || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
-             || SYMBOL_REFERENCES_LOCAL (info, h))
+             || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
            break;
          /* Fall thru */
 
@@ -3827,9 +3860,9 @@ ppc_elf_tls_optimize (obfd, info)
            int expecting_tls_get_addr;
 
            /* Read the relocations.  */
-           relstart = _bfd_elf32_link_read_relocs (ibfd, sec, (PTR) NULL,
-                                                   (Elf_Internal_Rela *) NULL,
-                                                   info->keep_memory);
+           relstart = _bfd_elf_link_read_relocs (ibfd, sec, (PTR) NULL,
+                                                 (Elf_Internal_Rela *) NULL,
+                                                 info->keep_memory);
            if (relstart == NULL)
              return FALSE;
 
@@ -4520,7 +4553,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                  enum elf_ppc_reloc_type r_type2;
                  unsigned long r_symndx2;
                  struct elf_link_hash_entry *h2;
-                 bfd_vma insn1, insn2, insn3;
+                 bfd_vma insn1, insn2;
                  bfd_vma offset;
 
                  /* The next instruction should be a call to
@@ -4547,8 +4580,6 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                  offset = rel[1].r_offset;
                  insn1 = bfd_get_32 (output_bfd,
                                      contents + rel->r_offset - 2);
-                 insn3 = bfd_get_32 (output_bfd,
-                                     contents + offset + 4);
                  if ((tls_mask & tls_gd) != 0)
                    {
                      /* IE */
@@ -4578,16 +4609,8 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                                    R_PPC_TPREL16_LO);
                      rel[1].r_offset += 2;
                    }
-                 if (insn3 == NOP
-                     || insn3 == CROR_151515 || insn3 == CROR_313131)
-                   {
-                     insn3 = insn2;
-                     insn2 = NOP;
-                     rel[1].r_offset += 4;
-                   }
                  bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - 2);
                  bfd_put_32 (output_bfd, insn2, contents + offset);
-                 bfd_put_32 (output_bfd, insn3, contents + offset + 4);
                  if (tls_gd == 0)
                    {
                      /* We changed the symbol on an LD reloc.  Start over
@@ -4780,15 +4803,18 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                      }
 
                    /* Generate relocs for the dynamic linker.  */
-                   if (info->shared || indx != 0)
+                   if ((info->shared || indx != 0)
+                       && (h == NULL
+                           || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                           || h->root.type != bfd_link_hash_undefweak))
                      {
                        outrel.r_offset = (htab->got->output_section->vma
                                           + htab->got->output_offset
                                           + off);
+                       outrel.r_addend = 0;
                        if (tls_ty & (TLS_LD | TLS_GD))
                          {
                            outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32);
-                           outrel.r_addend = 0;
                            if (tls_ty == (TLS_TLS | TLS_GD))
                              {
                                loc = htab->relgot->contents;
@@ -4796,9 +4822,9 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                        * sizeof (Elf32_External_Rela));
                                bfd_elf32_swap_reloca_out (output_bfd,
                                                           &outrel, loc);
+                               outrel.r_offset += 4;
                                outrel.r_info
                                  = ELF32_R_INFO (indx, R_PPC_DTPREL32);
-                               outrel.r_offset += 4;
                              }
                          }
                        else if (tls_ty == (TLS_TLS | TLS_DTPREL))
@@ -4809,9 +4835,12 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_RELATIVE);
                        else
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT);
-                       outrel.r_addend = 0;
                        if (indx == 0)
-                         outrel.r_addend += relocation;
+                         {
+                           outrel.r_addend += relocation;
+                           if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
+                             outrel.r_addend -= htab->tls_sec->vma;
+                         }
                        loc = htab->relgot->contents;
                        loc += (htab->relgot->reloc_count++
                                * sizeof (Elf32_External_Rela));
@@ -4824,22 +4853,21 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                      {
                        bfd_vma value = relocation;
 
-                       if ((tls_ty & (TLS_GD | TLS_TPREL | TLS_DTPREL
-                                      | TLS_TPRELGD)) != 0)
+                       if (tls_ty == (TLS_TLS | TLS_LD))
+                         value = 1;
+                       else if (tls_ty != 0)
                          {
                            value -= htab->tls_sec->vma + DTP_OFFSET;
-                           if ((tls_ty & TLS_TPREL) != 0)
+                           if (tls_ty == (TLS_TLS | TLS_TPREL))
                              value += DTP_OFFSET - TP_OFFSET;
-                         }
 
-                       if (tls_ty == (TLS_TLS | TLS_GD))
-                         {
-                           bfd_put_32 (output_bfd, value,
-                                       htab->got->contents + off + 4);
-                           value = 1;
+                           if (tls_ty == (TLS_TLS | TLS_GD))
+                             {
+                               bfd_put_32 (output_bfd, value,
+                                           htab->got->contents + off + 4);
+                               value = 1;
+                             }
                          }
-                       else if (tls_ty == (TLS_TLS | TLS_LD))
-                         value = 1;
                        bfd_put_32 (output_bfd, value,
                                    htab->got->contents + off);
                      }
@@ -4887,10 +4915,11 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
               got at entry m+n bears little relation to the entry m.  */
            if (addend != 0)
              (*_bfd_error_handler)
-               (_("%s(%s+0x%lx): non-zero addend on got reloc against `%s'"),
+               (_("%s(%s+0x%lx): non-zero addend on %s reloc against `%s'"),
                 bfd_archive_filename (input_bfd),
                 bfd_get_section_name (input_bfd, input_section),
                 (long) rel->r_offset,
+                howto->name,
                 sym_name);
          }
        break;
@@ -4899,10 +4928,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_PPC_LOCAL24PC:
          /* It makes no sense to point a local relocation
             at a symbol not in this object.  */
-         if (h != NULL
-             && (h->root.type == bfd_link_hash_defined
-                 || h->root.type == bfd_link_hash_defweak)
-             && sec->output_section == NULL)
+         if (unresolved_reloc)
            {
              if (! (*info->callbacks->undefined_symbol) (info,
                                                          h->root.root.string,
@@ -4942,6 +4968,11 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          addend -= htab->tls_sec->vma + DTP_OFFSET;
          goto dodyn;
 
+       case R_PPC_DTPMOD32:
+         relocation = 1;
+         addend = 0;
+         goto dodyn;
+
        case R_PPC_REL24:
        case R_PPC_REL32:
        case R_PPC_REL14:
@@ -4968,7 +4999,6 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_UADDR32:
        case R_PPC_UADDR16:
-       case R_PPC_DTPMOD32:
          /* r_symndx will be zero only for relocs against symbols
             from removed linkonce sections, or sections discarded by
             a linker script.  */
@@ -4978,6 +5008,9 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          /* Fall thru.  */
 
          if ((info->shared
+              && (h == NULL
+                  || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                  || h->root.type != bfd_link_hash_undefweak)
               && (MUST_BE_DYN_RELOC (r_type)
                   || (h != NULL
                       && h->dynindx != -1
@@ -5037,8 +5070,6 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
-             /* h->dynindx may be -1 if this symbol was marked to
-                become local.  */
              else if (h != NULL
                       && !SYMBOL_REFERENCES_LOCAL (info, h))
                {
@@ -5175,7 +5206,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                   || (strncmp (name, ".sbss", 5) == 0
                       && (name[5] == 0 || name[5] == '.'))))
              {
-               (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+               (*_bfd_error_handler) (_("%s: the target (%s) of a %s relocation is in the wrong output section (%s)"),
                                       bfd_archive_filename (input_bfd),
                                       sym_name,
                                       howto->name,
@@ -5199,7 +5230,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            if (! (strncmp (name, ".sdata2", 7) == 0
                   || strncmp (name, ".sbss2", 6) == 0))
              {
-               (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+               (*_bfd_error_handler) (_("%s: the target (%s) of a %s relocation is in the wrong output section (%s)"),
                                       bfd_archive_filename (input_bfd),
                                       sym_name,
                                       howto->name,
@@ -5256,7 +5287,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
            else
              {
-               (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+               (*_bfd_error_handler) (_("%s: the target (%s) of a %s relocation is in the wrong output section (%s)"),
                                       bfd_archive_filename (input_bfd),
                                       sym_name,
                                       howto->name,
@@ -5310,7 +5341,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_PPC_EMB_RELST_HA:
        case R_PPC_EMB_BIT_FLD:
          (*_bfd_error_handler)
-           (_("%s: Relocation %s is not yet supported for symbol %s."),
+           (_("%s: relocation %s is not yet supported for symbol %s."),
             bfd_archive_filename (input_bfd),
             howto->name,
             sym_name);
@@ -5339,12 +5370,13 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_PPC_EMB_NADDR16_HA:
        case R_PPC_EMB_RELST_HA:
          /* It's just possible that this symbol is a weak symbol
-            that's not actually defined anywhere. In that case,
+            that's not actually defined anywhere.  In that case,
             'sec' would be NULL, and we should leave the symbol
             alone (it will be set to zero elsewhere in the link).  */
          if (sec != NULL)
-           /* Add 0x10000 if sign bit in 0:15 is set.  */
-           addend += ((relocation + addend) & 0x8000) << 1;
+           /* Add 0x10000 if sign bit in 0:15 is set.
+              Bits 0:15 are not used.  */
+           addend += 0x8000;
          break;
        }
 
@@ -5363,10 +5395,11 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
               && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
        {
          (*_bfd_error_handler)
-           (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
+           (_("%s(%s+0x%lx): unresolvable %s relocation against symbol `%s'"),
             bfd_archive_filename (input_bfd),
             bfd_get_section_name (input_bfd, input_section),
             (long) rel->r_offset,
+            howto->name,
             sym_name);
          ret = FALSE;
        }
@@ -5412,10 +5445,10 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          else
            {
              (*_bfd_error_handler)
-               (_("%s(%s+0x%lx): reloc against `%s': error %d"),
+               (_("%s(%s+0x%lx): %s reloc against `%s': error %d"),
                 bfd_archive_filename (input_bfd),
                 bfd_get_section_name (input_bfd, input_section),
-                (long) rel->r_offset, sym_name, (int) r);
+                (long) rel->r_offset, howto->name, sym_name, (int) r);
              ret = FALSE;
            }
        }
This page took 0.033622 seconds and 4 git commands to generate.