]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elf32-i386.c
-Wimplicit-fallthrough warning fixes
[thirdparty/binutils-gdb.git] / bfd / elf32-i386.c
index 686c0682fb0e0f666b2a108e65173b50887cd8d7..c6f2fd6096fa6bcd6aa6e841413767dd06d91aba 100644 (file)
@@ -383,8 +383,8 @@ elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
       && ((indx = r_type - R_386_vt_offset) - R_386_ext2
          >= R_386_vt - R_386_ext2))
     {
-      (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
-                            abfd, (int) r_type);
+      _bfd_error_handler (_("%B: invalid relocation type %d"),
+                         abfd, (int) r_type);
       indx = R_386_NONE;
     }
   /* PR 17512: file: 0f67f69d.  */
@@ -1555,7 +1555,7 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
            }
        }
 
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("%B: TLS transition from %s to %s against `%s' at 0x%lx "
           "in section `%A' failed"),
         abfd, sec, from->name, to->name, name,
@@ -1642,7 +1642,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
       else
        name = h->root.root.string;
 
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("%B: direct GOT relocation R_386_GOT32X against `%s' without base register can not be used when making a shared object"),
         abfd, name);
       return FALSE;
@@ -1846,6 +1846,15 @@ elf_i386_check_relocs (bfd *abfd,
   if (bfd_link_relocatable (info))
     return TRUE;
 
+  /* Don't do anything special with non-loaded, non-alloced sections.
+     In particular, any relocs in such sections should not affect GOT
+     and PLT reference counting (ie. we don't allow them to create GOT
+     or PLT entries), there's no possibility or desire to optimize TLS
+     relocs, and there's not much point in propagating relocs to shared
+     libs that the dynamic linker won't relocate.  */
+  if ((sec->flags & SEC_ALLOC) == 0)
+    return TRUE;
+
   BFD_ASSERT (is_i386_elf (abfd));
 
   htab = elf_i386_hash_table (info);
@@ -1889,9 +1898,8 @@ elf_i386_check_relocs (bfd *abfd,
 
       if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
        {
-         (*_bfd_error_handler) (_("%B: bad symbol index: %d"),
-                                abfd,
-                                r_symndx);
+         _bfd_error_handler (_("%B: bad symbol index: %d"),
+                             abfd, r_symndx);
          goto error_return;
        }
 
@@ -1939,6 +1947,7 @@ elf_i386_check_relocs (bfd *abfd,
 
            case R_386_GOTOFF:
              eh->gotoff_ref = 1;
+             /* Fall through.  */
            case R_386_32:
            case R_386_PC32:
            case R_386_PLT32:
@@ -2089,7 +2098,7 @@ elf_i386_check_relocs (bfd *abfd,
                    else
                      name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
                                             NULL);
-                   (*_bfd_error_handler)
+                   _bfd_error_handler
                      (_("%B: `%s' accessed both as normal and "
                         "thread local symbol"),
                       abfd, name);
@@ -2140,15 +2149,12 @@ elf_i386_check_relocs (bfd *abfd,
          if (eh != NULL && (sec->flags & SEC_CODE) != 0)
            eh->has_non_got_reloc = 1;
 do_relocation:
-         /* STT_GNU_IFUNC symbol must go through PLT even if it is
-            locally defined and undefined symbol may turn out to be
-            a STT_GNU_IFUNC symbol later.  */
+         /* We are called after all symbols have been resolved.  Only
+            relocation against STT_GNU_IFUNC symbol must go through
+            PLT.  */
          if (h != NULL
              && (bfd_link_executable (info)
-                 || ((h->type == STT_GNU_IFUNC
-                      || h->root.type == bfd_link_hash_undefweak
-                      || h->root.type == bfd_link_hash_undefined)
-                     && SYMBOLIC_BIND (info, h))))
+                 || h->type == STT_GNU_IFUNC))
            {
              /* If this reloc is in a read-only section, we might
                 need a copy reloc.  We can't check reliably at this
@@ -2158,9 +2164,13 @@ do_relocation:
                 adjust_dynamic_symbol.  */
              h->non_got_ref = 1;
 
-             /* We may need a .plt entry if the function this reloc
-                refers to is in a shared lib.  */
-             h->plt.refcount += 1;
+             /* We may need a .plt entry if the symbol is a function
+                defined in a shared lib or is a STT_GNU_IFUNC function
+                referenced from the code or read-only section.  */
+             if (!h->def_regular
+                 || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
+               h->plt.refcount += 1;
+
              if (r_type == R_386_PC32)
                {
                  /* Since something like ".long foo - ." may be used
@@ -2168,6 +2178,20 @@ do_relocation:
                     a function defined in a shared library.  */
                  if ((sec->flags & SEC_CODE) == 0)
                    h->pointer_equality_needed = 1;
+                 else if (h->type == STT_GNU_IFUNC
+                          && bfd_link_pic (info))
+                   {
+                   if (isym == NULL)
+                     name = h->root.root.string;
+                   else
+                     name = bfd_elf_sym_name (abfd, symtab_hdr, isym,
+                                              NULL);
+                   _bfd_error_handler
+                     (_("%B: unsupported non-PIC call to IFUNC `%s'"),
+                      abfd, name);
+                     bfd_set_error (bfd_error_bad_value);
+                     goto error_return;
+                   }
                }
              else
                {
@@ -2201,18 +2225,23 @@ do_size:
             If on the other hand, we are creating an executable, we
             may need to keep relocations for symbols satisfied by a
             dynamic library if we manage to avoid copy relocs for the
-            symbol.  */
+            symbol.
+
+            Generate dynamic pointer relocation against STT_GNU_IFUNC
+            symbol in the non-code section.  */
          if ((bfd_link_pic (info)
-              && (sec->flags & SEC_ALLOC) != 0
               && (r_type != R_386_PC32
                   || (h != NULL
                       && (! (bfd_link_pie (info)
                              || SYMBOLIC_BIND (info, h))
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
+             || (h != NULL
+                 && h->type == STT_GNU_IFUNC
+                 && r_type == R_386_32
+                 && (sec->flags & SEC_CODE) == 0)
              || (ELIMINATE_COPY_RELOCS
                  && !bfd_link_pic (info)
-                 && (sec->flags & SEC_ALLOC) != 0
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
@@ -2444,12 +2473,17 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
 
          if (pc_count || count)
            {
-             h->needs_plt = 1;
              h->non_got_ref = 1;
-             if (h->plt.refcount <= 0)
-               h->plt.refcount = 1;
-             else
-               h->plt.refcount += 1;
+             if (pc_count)
+               {
+                 /* Increment PLT reference count only for PC-relative
+                    references.  */
+                 h->needs_plt = 1;
+                 if (h->plt.refcount <= 0)
+                   h->plt.refcount = 1;
+                 else
+                   h->plt.refcount += 1;
+               }
            }
        }
 
@@ -2639,7 +2673,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs,
                                               &htab->readonly_dynrelocs_against_ifunc,
                                               plt_entry_size,
-                                              plt_entry_size, 4);
+                                              plt_entry_size, 4, TRUE);
   /* Don't create the PLT entry if there are only function pointer
      relocations which can be resolved at run-time.  */
   else if (htab->elf.dynamic_sections_created
@@ -3733,7 +3767,7 @@ elf_i386_relocate_section (bfd *output_bfd,
          && ((indx = r_type - R_386_tls_offset) - R_386_ext
              >= R_386_ext2 - R_386_ext))
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
            (_("%B: unrecognized relocation (0x%x) in section `%A'"),
             input_bfd, input_section, r_type);
          bfd_set_error (bfd_error_bad_value);
@@ -3894,8 +3928,6 @@ elf_i386_relocate_section (bfd *output_bfd,
                continue;
              abort ();
            }
-         else if (h->plt.offset == (bfd_vma) -1)
-           abort ();
 
          /* STT_GNU_IFUNC symbol must go through PLT.  */
          if (htab->elf.splt != NULL)
@@ -3909,77 +3941,10 @@ elf_i386_relocate_section (bfd *output_bfd,
              gotplt = htab->elf.igotplt;
            }
 
-         relocation = (plt->output_section->vma
-                       + plt->output_offset + h->plt.offset);
-
          switch (r_type)
            {
            default:
-             if (h->root.root.string)
-               name = h->root.root.string;
-             else
-               name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
-                                        NULL);
-             (*_bfd_error_handler)
-               (_("%B: relocation %s against STT_GNU_IFUNC "
-                  "symbol `%s' isn't handled by %s"), input_bfd,
-                elf_howto_table[r_type].name,
-                name, __FUNCTION__);
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
-
-           case R_386_32:
-             /* Generate dynamic relcoation only when there is a
-                non-GOT reference in a shared object.  */
-             if (bfd_link_pic (info) && h->non_got_ref)
-               {
-                 Elf_Internal_Rela outrel;
-                 asection *sreloc;
-                 bfd_vma offset;
-
-                 /* Need a dynamic relocation to get the real function
-                    adddress.  */
-                 offset = _bfd_elf_section_offset (output_bfd,
-                                                   info,
-                                                   input_section,
-                                                   rel->r_offset);
-                 if (offset == (bfd_vma) -1
-                     || offset == (bfd_vma) -2)
-                   abort ();
-
-                 outrel.r_offset = (input_section->output_section->vma
-                                    + input_section->output_offset
-                                    + offset);
-
-                 if (h->dynindx == -1
-                     || h->forced_local
-                     || bfd_link_executable (info))
-                   {
-                     /* This symbol is resolved locally.  */
-                     outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
-                     bfd_put_32 (output_bfd,
-                                 (h->root.u.def.value
-                                  + h->root.u.def.section->output_section->vma
-                                  + h->root.u.def.section->output_offset),
-                                 contents + offset);
-                   }
-                 else
-                   outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
-
-                 sreloc = htab->elf.irelifunc;
-                 elf_append_rel (output_bfd, sreloc, &outrel);
-
-                 /* If this reloc is against an external symbol, we
-                    do not want to fiddle with the addend.  Otherwise,
-                    we need to include the symbol value so that it
-                    becomes an addend for the dynamic reloc.  For an
-                    internal symbol, we have updated addend.  */
-                 continue;
-               }
-             /* FALLTHROUGH */
-           case R_386_PC32:
-           case R_386_PLT32:
-             goto do_relocation;
+             break;
 
            case R_386_GOT32:
            case R_386_GOT32X:
@@ -3995,6 +3960,9 @@ elf_i386_relocate_section (bfd *output_bfd,
                     even just remember the offset, as finish_dynamic_symbol
                     would use that as offset into .got.  */
 
+                 if (h->plt.offset == (bfd_vma) -1)
+                   abort ();
+
                  if (htab->elf.splt != NULL)
                    {
                      plt_index = h->plt.offset / plt_entry_size - 1;
@@ -4055,6 +4023,99 @@ elf_i386_relocate_section (bfd *output_bfd,
                }
 
              goto do_relocation;
+           }
+
+         if (h->plt.offset == (bfd_vma) -1)
+           {
+             /* Handle static pointers of STT_GNU_IFUNC symbols.  */
+             if (r_type == R_386_32
+                 && (input_section->flags & SEC_CODE) == 0)
+               goto do_ifunc_pointer;
+             goto bad_ifunc_reloc;
+           }
+
+         relocation = (plt->output_section->vma
+                       + plt->output_offset + h->plt.offset);
+
+         switch (r_type)
+           {
+           default:
+bad_ifunc_reloc:
+             if (h->root.root.string)
+               name = h->root.root.string;
+             else
+               name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
+                                        NULL);
+             _bfd_error_handler
+               (_("%B: relocation %s against STT_GNU_IFUNC "
+                  "symbol `%s' isn't supported"), input_bfd,
+                howto->name, name);
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+
+           case R_386_32:
+             /* Generate dynamic relcoation only when there is a
+                non-GOT reference in a shared object.  */
+             if ((bfd_link_pic (info) && h->non_got_ref)
+                 || h->plt.offset == (bfd_vma) -1)
+               {
+                 Elf_Internal_Rela outrel;
+                 asection *sreloc;
+                 bfd_vma offset;
+
+do_ifunc_pointer:
+                 /* Need a dynamic relocation to get the real function
+                    adddress.  */
+                 offset = _bfd_elf_section_offset (output_bfd,
+                                                   info,
+                                                   input_section,
+                                                   rel->r_offset);
+                 if (offset == (bfd_vma) -1
+                     || offset == (bfd_vma) -2)
+                   abort ();
+
+                 outrel.r_offset = (input_section->output_section->vma
+                                    + input_section->output_offset
+                                    + offset);
+
+                 if (h->dynindx == -1
+                     || h->forced_local
+                     || bfd_link_executable (info))
+                   {
+                     /* This symbol is resolved locally.  */
+                     outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
+                     bfd_put_32 (output_bfd,
+                                 (h->root.u.def.value
+                                  + h->root.u.def.section->output_section->vma
+                                  + h->root.u.def.section->output_offset),
+                                 contents + offset);
+                   }
+                 else
+                   outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+
+                 /* Dynamic relocations are stored in
+                    1. .rel.ifunc section in PIC object.
+                    2. .rel.got section in dynamic executable.
+                    3. .rel.iplt section in static executable.  */
+                 if (bfd_link_pic (info))
+                   sreloc = htab->elf.irelifunc;
+                 else if (htab->elf.splt != NULL)
+                   sreloc = htab->elf.srelgot;
+                 else
+                   sreloc = htab->elf.irelplt;
+                 elf_append_rel (output_bfd, sreloc, &outrel);
+
+                 /* If this reloc is against an external symbol, we
+                    do not want to fiddle with the addend.  Otherwise,
+                    we need to include the symbol value so that it
+                    becomes an addend for the dynamic reloc.  For an
+                    internal symbol, we have updated addend.  */
+                 continue;
+               }
+             /* FALLTHROUGH */
+           case R_386_PC32:
+           case R_386_PLT32:
+             goto do_relocation;
 
            case R_386_GOTOFF:
              relocation -= (gotplt->output_section->vma
@@ -4232,7 +4293,7 @@ disallow_got32:
                  else
                    name = h->root.root.string;
 
-                 (*_bfd_error_handler)
+                 _bfd_error_handler
                    (_("%B: direct GOT relocation %s against `%s' without base register can not be used when making a shared object"),
                     input_bfd, howto->name, name);
                  bfd_set_error (bfd_error_bad_value);
@@ -4279,7 +4340,7 @@ disallow_got32:
                      break;
                    }
 
-                 (*_bfd_error_handler)
+                 _bfd_error_handler
                    (_("%B: relocation R_386_GOTOFF against undefined %s `%s' can not be used when making a shared object"),
                     input_bfd, v, h->root.root.string);
                  bfd_set_error (bfd_error_bad_value);
@@ -4290,7 +4351,7 @@ disallow_got32:
                           || h->type == STT_OBJECT)
                       && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
                {
-                 (*_bfd_error_handler)
+                 _bfd_error_handler
                    (_("%B: relocation R_386_GOTOFF against protected %s `%s' can not be used when making a shared object"),
                     input_bfd,
                     h->type == STT_FUNC ? "function" : "data",
@@ -5081,7 +5142,7 @@ disallow_got32:
          && _bfd_elf_section_offset (output_bfd, info, input_section,
                                      rel->r_offset) != (bfd_vma) -1)
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
            (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
             input_bfd,
             input_section,
@@ -5120,7 +5181,7 @@ check_relocation_error:
               (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
          else
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
                (_("%B(%A+0x%lx): reloc against `%s': error %d"),
                 input_bfd, input_section,
                 (long) rel->r_offset, name, (int) r);
@@ -5428,6 +5489,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
       && !local_undefweak)
     {
       Elf_Internal_Rela rel;
+      asection *relgot = htab->elf.srelgot;
 
       /* This symbol has an entry in the global offset table.  Set it
         up.  */
@@ -5447,7 +5509,28 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
       if (h->def_regular
          && h->type == STT_GNU_IFUNC)
        {
-         if (bfd_link_pic (info))
+         if (h->plt.offset == (bfd_vma) -1)
+           {
+             /* STT_GNU_IFUNC is referenced without PLT.  */
+             if (htab->elf.splt == NULL)
+               {
+                 /* use .rel[a].iplt section to store .got relocations
+                    in static executable.  */
+                 relgot = htab->elf.irelplt;
+               }
+             if (SYMBOL_REFERENCES_LOCAL (info, h))
+               {
+                 bfd_put_32 (output_bfd,
+                             (h->root.u.def.value
+                              + h->root.u.def.section->output_section->vma
+                              + h->root.u.def.section->output_offset),
+                             htab->elf.sgot->contents + h->got.offset);
+                 rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE);
+               }
+             else
+               goto do_glob_dat;
+           }
+         else if (bfd_link_pic (info))
            {
              /* Generate R_386_GLOB_DAT.  */
              goto do_glob_dat;
@@ -5485,7 +5568,7 @@ do_glob_dat:
          rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT);
        }
 
-      elf_append_rel (output_bfd, htab->elf.srelgot, &rel);
+      elf_append_rel (output_bfd, relgot, &rel);
     }
 
   if (h->needs_copy)
@@ -5772,7 +5855,7 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd,
     {
       if (bfd_is_abs_section (htab->elf.sgotplt->output_section))
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
            (_("discarded output section: `%A'"), htab->elf.sgotplt);
          return FALSE;
        }
@@ -5822,11 +5905,6 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd,
   if (htab->elf.sgot && htab->elf.sgot->size > 0)
     elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4;
 
-  /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols.  */
-  htab_traverse (htab->loc_hash_table,
-                elf_i386_finish_local_dynamic_symbol,
-                info);
-
   /* Fill PLT entries for undefined weak symbols in PIE.  */
   if (bfd_link_pie (info))
     bfd_hash_traverse (&info->hash->table,
@@ -5836,6 +5914,33 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd,
   return TRUE;
 }
 
+/* Fill PLT/GOT entries and allocate dynamic relocations for local
+   STT_GNU_IFUNC symbols, which aren't in the ELF linker hash table.
+   It has to be done before elf_link_sort_relocs is called so that
+   dynamic relocations are properly sorted.  */
+
+static bfd_boolean
+elf_i386_output_arch_local_syms
+  (bfd *output_bfd ATTRIBUTE_UNUSED,
+   struct bfd_link_info *info,
+   void *flaginfo ATTRIBUTE_UNUSED,
+   int (*func) (void *, const char *,
+               Elf_Internal_Sym *,
+               asection *,
+               struct elf_link_hash_entry *) ATTRIBUTE_UNUSED)
+{
+  struct elf_i386_link_hash_table *htab = elf_i386_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
+  /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols.  */
+  htab_traverse (htab->loc_hash_table,
+                elf_i386_finish_local_dynamic_symbol,
+                info);
+
+  return TRUE;
+}
+
 /* Return an array of PLT entry symbol values.  */
 
 static bfd_vma *
@@ -5978,6 +6083,7 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h)
 #define elf_backend_fake_sections            elf_i386_fake_sections
 #define elf_backend_finish_dynamic_sections   elf_i386_finish_dynamic_sections
 #define elf_backend_finish_dynamic_symbol     elf_i386_finish_dynamic_symbol
+#define elf_backend_output_arch_local_syms     elf_i386_output_arch_local_syms
 #define elf_backend_gc_mark_hook             elf_i386_gc_mark_hook
 #define elf_backend_grok_prstatus            elf_i386_grok_prstatus
 #define elf_backend_grok_psinfo                      elf_i386_grok_psinfo