PowerPC64 undefined weak visibility vs GOT optimisation
[binutils-gdb.git] / bfd / elf32-bfin.c
index a51a8e8e9f2d9fdf5dc31ca57f3c3654e2ba4063..401683c536792ab1156dd941eca2631b027b8ba2 100644 (file)
@@ -1,5 +1,5 @@
 /* ADI Blackfin BFD support for 32-bit ELF.
-   Copyright (C) 2005-2020 Free Software Foundation, Inc.
+   Copyright (C) 2005-2021 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -1197,6 +1197,9 @@ bfin_check_relocs (bfd * abfd,
       else
        {
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *)h->root.u.i.link;
        }
 
       switch (ELF32_R_TYPE (rel->r_info))
@@ -1668,9 +1671,10 @@ struct bfinfdpic_elf_link_hash_table
 
 /* Get the Blackfin ELF linker hash table from a link_info structure.  */
 
-#define bfinfdpic_hash_table(info) \
-  (elf_hash_table_id ((struct elf_link_hash_table *) ((info)->hash)) \
-  == BFIN_ELF_DATA ? ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash)) : NULL)
+#define bfinfdpic_hash_table(p) \
+  ((is_elf_hash_table ((p)->hash)                                      \
+    && elf_hash_table_id (elf_hash_table (p)) == BFIN_ELF_DATA)                \
+   ? (struct bfinfdpic_elf_link_hash_table *) (p)->hash : NULL)
 
 #define bfinfdpic_got_section(info) \
   (bfinfdpic_hash_table (info)->elf.sgot)
@@ -2552,6 +2556,7 @@ bfinfdpic_relocate_section (bfd * output_bfd,
       h      = NULL;
       sym    = NULL;
       sec    = NULL;
+      picrel = NULL;
 
       if (r_symndx < symtab_hdr->sh_info)
        {
@@ -2614,6 +2619,9 @@ bfinfdpic_relocate_section (bfd * output_bfd,
        case R_BFIN_FUNCDESC_GOTOFFLO:
        case R_BFIN_FUNCDESC:
        case R_BFIN_FUNCDESC_VALUE:
+         if ((input_section->flags & SEC_ALLOC) == 0)
+           break;
+
          if (h != NULL)
            picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info
                                                       (info), input_bfd, h,
@@ -2719,129 +2727,130 @@ bfinfdpic_relocate_section (bfd * output_bfd,
          break;
 
        case R_BFIN_FUNCDESC:
-         {
-           int dynindx;
-           bfd_vma addend = rel->r_addend;
-
-           if (! (h && h->root.type == bfd_link_hash_undefweak
-                  && BFINFDPIC_SYM_LOCAL (info, h)))
-             {
-               /* If the symbol is dynamic and there may be dynamic
-                  symbol resolution because we are or are linked with a
-                  shared library, emit a FUNCDESC relocation such that
-                  the dynamic linker will allocate the function
-                  descriptor.  If the symbol needs a non-local function
-                  descriptor but binds locally (e.g., its visibility is
-                  protected, emit a dynamic relocation decayed to
-                  section+offset.  */
-               if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h)
-                   && BFINFDPIC_SYM_LOCAL (info, h)
-                   && !bfd_link_pde (info))
-                 {
-                   dynindx = elf_section_data (h->root.u.def.section
-                                               ->output_section)->dynindx;
-                   addend += h->root.u.def.section->output_offset
-                     + h->root.u.def.value;
-                 }
-               else if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h))
-                 {
-                   if (addend)
-                     {
-                       info->callbacks->warning
-                         (info, _("R_BFIN_FUNCDESC references dynamic symbol with nonzero addend"),
-                          name, input_bfd, input_section, rel->r_offset);
-                       return FALSE;
-                     }
-                   dynindx = h->dynindx;
-                 }
-               else
-                 {
-                   /* Otherwise, we know we have a private function
-                      descriptor, so reference it directly.  */
-                   BFD_ASSERT (picrel->privfd);
-                   r_type = R_BFIN_BYTE4_DATA;
-                   dynindx = elf_section_data (bfinfdpic_got_section (info)
-                                               ->output_section)->dynindx;
-                   addend = bfinfdpic_got_section (info)->output_offset
-                     + bfinfdpic_got_initial_offset (info)
-                     + picrel->fd_entry;
-                 }
-
-               /* If there is room for dynamic symbol resolution, emit
-                  the dynamic relocation.  However, if we're linking an
-                  executable at a fixed location, we won't have emitted a
-                  dynamic symbol entry for the got section, so idx will
-                  be zero, which means we can and should compute the
-                  address of the private descriptor ourselves.  */
-               if (bfd_link_pde (info)
-                   && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
-                 {
-                   bfd_vma offset;
-
-                   addend += bfinfdpic_got_section (info)->output_section->vma;
-                   if ((bfd_section_flags (input_section->output_section)
-                        & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
-                     {
-                       if (_bfinfdpic_osec_readonly_p (output_bfd,
-                                                      input_section
-                                                      ->output_section))
-                         {
-                           info->callbacks->warning
-                             (info,
-                              _("cannot emit fixups in read-only section"),
-                              name, input_bfd, input_section, rel->r_offset);
-                           return FALSE;
-                         }
+         if ((input_section->flags & SEC_ALLOC) != 0)
+           {
+             int dynindx;
+             bfd_vma addend = rel->r_addend;
 
-                       offset = _bfd_elf_section_offset
-                         (output_bfd, info,
-                          input_section, rel->r_offset);
+             if (! (h && h->root.type == bfd_link_hash_undefweak
+                    && BFINFDPIC_SYM_LOCAL (info, h)))
+               {
+                 /* If the symbol is dynamic and there may be dynamic
+                    symbol resolution because we are or are linked with a
+                    shared library, emit a FUNCDESC relocation such that
+                    the dynamic linker will allocate the function
+                    descriptor.  If the symbol needs a non-local function
+                    descriptor but binds locally (e.g., its visibility is
+                    protected, emit a dynamic relocation decayed to
+                    section+offset.  */
+                 if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h)
+                     && BFINFDPIC_SYM_LOCAL (info, h)
+                     && !bfd_link_pde (info))
+                   {
+                     dynindx = elf_section_data (h->root.u.def.section
+                                                 ->output_section)->dynindx;
+                     addend += h->root.u.def.section->output_offset
+                       + h->root.u.def.value;
+                   }
+                 else if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h))
+                   {
+                     if (addend)
+                       {
+                         info->callbacks->warning
+                           (info, _("R_BFIN_FUNCDESC references dynamic symbol with nonzero addend"),
+                            name, input_bfd, input_section, rel->r_offset);
+                         return FALSE;
+                       }
+                     dynindx = h->dynindx;
+                   }
+                 else
+                   {
+                     /* Otherwise, we know we have a private function
+                        descriptor, so reference it directly.  */
+                     BFD_ASSERT (picrel->privfd);
+                     r_type = R_BFIN_BYTE4_DATA;
+                     dynindx = elf_section_data (bfinfdpic_got_section (info)
+                                                 ->output_section)->dynindx;
+                     addend = bfinfdpic_got_section (info)->output_offset
+                       + bfinfdpic_got_initial_offset (info)
+                       + picrel->fd_entry;
+                   }
 
-                       if (offset != (bfd_vma)-1)
-                         _bfinfdpic_add_rofixup (output_bfd,
-                                                 bfinfdpic_gotfixup_section
-                                                 (info),
+                 /* If there is room for dynamic symbol resolution, emit
+                    the dynamic relocation.  However, if we're linking an
+                    executable at a fixed location, we won't have emitted a
+                    dynamic symbol entry for the got section, so idx will
+                    be zero, which means we can and should compute the
+                    address of the private descriptor ourselves.  */
+                 if (bfd_link_pde (info)
+                     && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
+                   {
+                     bfd_vma offset;
+
+                     addend += bfinfdpic_got_section (info)->output_section->vma;
+                     if ((bfd_section_flags (input_section->output_section)
+                          & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+                       {
+                         if (_bfinfdpic_osec_readonly_p (output_bfd,
+                                                         input_section
+                                                         ->output_section))
+                           {
+                             info->callbacks->warning
+                               (info,
+                                _("cannot emit fixups in read-only section"),
+                                name, input_bfd, input_section, rel->r_offset);
+                             return FALSE;
+                           }
+
+                         offset = _bfd_elf_section_offset
+                           (output_bfd, info,
+                            input_section, rel->r_offset);
+
+                         if (offset != (bfd_vma)-1)
+                           _bfinfdpic_add_rofixup (output_bfd,
+                                                   bfinfdpic_gotfixup_section
+                                                   (info),
+                                                   offset + input_section
+                                                   ->output_section->vma
+                                                   + input_section->output_offset,
+                                                   picrel);
+                       }
+                   }
+                 else if ((bfd_section_flags (input_section->output_section)
+                           & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+                   {
+                     bfd_vma offset;
+
+                     if (_bfinfdpic_osec_readonly_p (output_bfd,
+                                                     input_section
+                                                     ->output_section))
+                       {
+                         info->callbacks->warning
+                           (info,
+                            _("cannot emit dynamic relocations in read-only section"),
+                            name, input_bfd, input_section, rel->r_offset);
+                         return FALSE;
+                       }
+                     offset = _bfd_elf_section_offset (output_bfd, info,
+                                                       input_section, rel->r_offset);
+
+                     if (offset != (bfd_vma)-1)
+                       _bfinfdpic_add_dyn_reloc (output_bfd,
+                                                 bfinfdpic_gotrel_section (info),
                                                  offset + input_section
                                                  ->output_section->vma
                                                  + input_section->output_offset,
-                                                 picrel);
-                     }
-                 }
-               else if ((bfd_section_flags (input_section->output_section)
-                         & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
-                 {
-                   bfd_vma offset;
-
-                   if (_bfinfdpic_osec_readonly_p (output_bfd,
-                                                  input_section
-                                                  ->output_section))
-                     {
-                       info->callbacks->warning
-                         (info,
-                          _("cannot emit dynamic relocations in read-only section"),
-                          name, input_bfd, input_section, rel->r_offset);
-                       return FALSE;
-                     }
-                   offset = _bfd_elf_section_offset (output_bfd, info,
-                                                     input_section, rel->r_offset);
-
-                   if (offset != (bfd_vma)-1)
-                     _bfinfdpic_add_dyn_reloc (output_bfd,
-                                               bfinfdpic_gotrel_section (info),
-                                               offset + input_section
-                                               ->output_section->vma
-                                               + input_section->output_offset,
-                                               r_type,
-                                               dynindx, addend, picrel);
-                 }
-               else
-                 addend += bfinfdpic_got_section (info)->output_section->vma;
-             }
+                                                 r_type,
+                                                 dynindx, addend, picrel);
+                   }
+                 else
+                   addend += bfinfdpic_got_section (info)->output_section->vma;
+               }
 
-           /* We want the addend in-place because dynamic
-              relocations are REL.  Setting relocation to it should
-              arrange for it to be installed.  */
-           relocation = addend - rel->r_addend;
+             /* We want the addend in-place because dynamic
+                relocations are REL.  Setting relocation to it should
+                arrange for it to be installed.  */
+             relocation = addend - rel->r_addend;
          }
          check_segment[0] = check_segment[1] = got_segment;
          break;
@@ -4063,26 +4072,6 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
   if (!_bfinfdpic_size_got_plt (output_bfd, &gpinfo))
       return FALSE;
 
-  if (elf_hash_table (info)->dynamic_sections_created)
-    {
-      if (bfinfdpic_got_section (info)->size)
-       if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0))
-         return FALSE;
-
-      if (bfinfdpic_pltrel_section (info)->size)
-       if (!_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0)
-           || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_REL)
-           || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0))
-         return FALSE;
-
-      if (bfinfdpic_gotrel_section (info)->size)
-       if (!_bfd_elf_add_dynamic_entry (info, DT_REL, 0)
-           || !_bfd_elf_add_dynamic_entry (info, DT_RELSZ, 0)
-           || !_bfd_elf_add_dynamic_entry (info, DT_RELENT,
-                                           sizeof (Elf32_External_Rel)))
-         return FALSE;
-    }
-
   s = bfd_get_linker_section (dynobj, ".dynbss");
   if (s && s->size == 0)
     s->flags |= SEC_EXCLUDE;
@@ -4091,7 +4080,7 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
   if (s && s->size == 0)
     s->flags |= SEC_EXCLUDE;
 
-  return TRUE;
+  return _bfd_elf_add_dynamic_tags (output_bfd, info, TRUE);
 }
 
 static bfd_boolean
@@ -4538,7 +4527,12 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info,
       if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+       }
 
       switch (ELF32_R_TYPE (rel->r_info))
        {
@@ -4807,16 +4801,6 @@ struct bfin_link_hash_entry
   struct bfin_pcrel_relocs_copied *pcrel_relocs_copied;
 };
 
-/* bfin ELF linker hash table.  */
-
-struct bfin_link_hash_table
-{
-  struct elf_link_hash_table root;
-
-  /* Small local sym cache.  */
-  struct sym_cache sym_cache;
-};
-
 #define bfin_hash_entry(ent) ((struct bfin_link_hash_entry *) (ent))
 
 static struct bfd_hash_entry *
@@ -4845,15 +4829,14 @@ bfin_link_hash_newfunc (struct bfd_hash_entry *entry,
 static struct bfd_link_hash_table *
 bfin_link_hash_table_create (bfd * abfd)
 {
-  struct bfin_link_hash_table *ret;
-  size_t amt = sizeof (struct bfin_link_hash_table);
+  struct elf_link_hash_table *ret;
+  size_t amt = sizeof (struct elf_link_hash_table);
 
   ret = bfd_zmalloc (amt);
   if (ret == NULL)
     return NULL;
 
-  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
-                                     bfin_link_hash_newfunc,
+  if (!_bfd_elf_link_hash_table_init (ret, abfd, bfin_link_hash_newfunc,
                                      sizeof (struct elf_link_hash_entry),
                                      BFIN_ELF_DATA))
     {
@@ -4861,9 +4844,7 @@ bfin_link_hash_table_create (bfd * abfd)
       return NULL;
     }
 
-  ret->sym_cache.abfd = NULL;
-
-  return &ret->root.root;
+  return &ret->root;
 }
 
 /* The size in bytes of an entry in the procedure linkage table.  */
@@ -5395,18 +5376,16 @@ bfd_bfin_elf32_create_embedded_relocs (bfd *abfd,
        strncpy ((char *) p + 4, targetsec->output_section->name, 8);
     }
 
-  if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
+  if (symtab_hdr->contents != (unsigned char *) isymbuf)
     free (isymbuf);
-  if (internal_relocs != NULL
-      && elf_section_data (datasec)->relocs != internal_relocs)
+  if (elf_section_data (datasec)->relocs != internal_relocs)
     free (internal_relocs);
   return TRUE;
 
  error_return:
-  if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
+  if (symtab_hdr->contents != (unsigned char *) isymbuf)
     free (isymbuf);
-  if (internal_relocs != NULL
-      && elf_section_data (datasec)->relocs != internal_relocs)
+  if (elf_section_data (datasec)->relocs != internal_relocs)
     free (internal_relocs);
   return FALSE;
 }
@@ -5436,10 +5415,6 @@ struct bfd_elf_special_section const elf32_bfin_special_sections[] =
 
 #define bfd_elf32_bfd_is_local_label_name \
                                        bfin_is_local_label_name
-#define bfin_hash_table(p) \
-  ((struct bfin_link_hash_table *) (p)->hash)
-
-
 
 #define elf_backend_create_dynamic_sections \
                                        _bfd_elf_create_dynamic_sections