x86: Update UNDEFINED_WEAK_RESOLVED_TO_ZERO
[deliverable/binutils-gdb.git] / bfd / elf32-i386.c
index ce9cf3a20586ec4ce199a50a1ba84d33bbe0d69e..4337ab0ea0b68d3e60c227cc225b971181730dff 100644 (file)
@@ -1211,9 +1211,9 @@ static
 bfd_boolean
 elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
                             bfd_byte *contents,
+                            unsigned int *r_type_p,
                             Elf_Internal_Rela *irel,
                             struct elf_link_hash_entry *h,
-                            bfd_boolean *converted,
                             struct bfd_link_info *link_info)
 {
   struct elf_x86_link_hash_table *htab;
@@ -1229,6 +1229,8 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   unsigned int r_type;
   unsigned int r_symndx;
   bfd_vma roff = irel->r_offset;
+  bfd_boolean local_ref;
+  struct elf_x86_link_hash_entry *eh;
 
   if (roff < 2)
     return TRUE;
@@ -1241,7 +1243,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   htab = elf_x86_hash_table (link_info, I386_ELF_DATA);
   is_pic = bfd_link_pic (link_info);
 
-  r_type = ELF32_R_TYPE (irel->r_info);
+  r_type = *r_type_p;
   r_symndx = ELF32_R_SYM (irel->r_info);
 
   modrm = bfd_get_8 (abfd, contents + roff - 1);
@@ -1276,6 +1278,8 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
      register.  */
   to_reloc_32 = !is_pic || baseless;
 
+  eh = elf_x86_hash_entry (h);
+
   /* Try to convert R_386_GOT32X.  Get the symbol referred to by the
      reloc.  */
   if (h == NULL)
@@ -1290,10 +1294,14 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
        goto convert_load;
     }
 
+  /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P.  */
+  local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h);
+
   /* Undefined weak symbol is only bound locally in executable
      and its reference is resolved as 0.  */
-  if (UNDEFINED_WEAK_RESOLVED_TO_ZERO (link_info, I386_ELF_DATA, TRUE,
-                                      elf_x86_hash_entry (h)))
+  if (h->root.type == bfd_link_hash_undefweak
+      && !eh->linker_def
+      && local_ref)
     {
       if (opcode == 0xff)
        {
@@ -1316,16 +1324,13 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
       /* We have "call/jmp *foo@GOT[(%reg)]".  */
       if ((h->root.type == bfd_link_hash_defined
           || h->root.type == bfd_link_hash_defweak)
-         && SYMBOL_REFERENCES_LOCAL (link_info, h))
+         && local_ref)
        {
          /* The function is locally defined.   */
 convert_branch:
          /* Convert R_386_GOT32X to R_386_PC32.  */
          if (modrm == 0x15 || (modrm & 0xf8) == 0x90)
            {
-             struct elf_x86_link_hash_entry *eh
-               = (struct elf_x86_link_hash_entry *) h;
-
              /* Convert to "nop call foo".  ADDR_PREFIX_OPCODE
                 is a nop prefix.  */
              modrm = 0xe8;
@@ -1363,8 +1368,7 @@ convert_branch:
             need to adjust addend by -4.  */
          bfd_put_32 (abfd, -4, contents + irel->r_offset);
          irel->r_info = ELF32_R_INFO (r_symndx, R_386_PC32);
-
-         *converted = TRUE;
+         *r_type_p = R_386_PC32;
        }
     }
   else
@@ -1382,10 +1386,11 @@ convert_branch:
         bfd_elf_record_link_assignment.  start_stop is set on
         __start_SECNAME/__stop_SECNAME which mark section SECNAME.  */
       if (h->start_stop
+         || eh->linker_def
          || ((h->def_regular
               || h->root.type == bfd_link_hash_defined
               || h->root.type == bfd_link_hash_defweak)
-             && SYMBOL_REFERENCES_LOCAL (link_info, h)))
+             && local_ref))
        {
 convert_load:
          if (opcode == 0x8b)
@@ -1435,8 +1440,7 @@ convert_load:
 
          bfd_put_8 (abfd, opcode, contents + roff - 2);
          irel->r_info = ELF32_R_INFO (r_symndx, r_type);
-
-         *converted = TRUE;
+         *r_type_p = r_type;
        }
     }
 
@@ -1445,8 +1449,7 @@ convert_load:
 
 /* Rename some of the generic section flags to better document how they
    are used here.  */
-#define need_convert_load      sec_flg0
-#define check_relocs_failed    sec_flg1
+#define check_relocs_failed    sec_flg0
 
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure linkage
@@ -1574,6 +1577,15 @@ elf_i386_check_relocs (bfd *abfd,
              |= elf_gnu_symbol_ifunc;
        }
 
+      if (r_type == R_386_GOT32X
+         && (h == NULL || h->type != STT_GNU_IFUNC))
+       {
+         Elf_Internal_Rela *irel = (Elf_Internal_Rela *) rel;
+         if (!elf_i386_convert_load_reloc (abfd, symtab_hdr, contents,
+                                           &r_type, irel, h, info))
+           goto error_return;
+       }
+
       if (! elf_i386_tls_transition (info, abfd, sec, contents,
                                     symtab_hdr, sym_hashes,
                                     &r_type, GOT_UNKNOWN,
@@ -1921,10 +1933,6 @@ do_size:
        default:
          break;
        }
-
-      if (r_type == R_386_GOT32X
-         && (h == NULL || h->type != STT_GNU_IFUNC))
-       sec->need_convert_load = 1;
     }
 
   if (elf_section_data (sec)->this_hdr.contents != contents)
@@ -1947,136 +1955,6 @@ error_return:
   return FALSE;
 }
 
-/* Convert load via the GOT slot to load immediate.  */
-
-bfd_boolean
-_bfd_i386_elf_convert_load (bfd *abfd, asection *sec,
-                           struct bfd_link_info *link_info)
-{
-  struct elf_x86_link_hash_table *htab;
-  Elf_Internal_Shdr *symtab_hdr;
-  Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *irel, *irelend;
-  bfd_byte *contents;
-  bfd_boolean changed;
-  bfd_signed_vma *local_got_refcounts;
-
-  /* Don't even try to convert non-ELF outputs.  */
-  if (!is_elf_hash_table (link_info->hash))
-    return FALSE;
-
-  /* Nothing to do if there is no need or no output.  */
-  if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC)
-      || sec->need_convert_load == 0
-      || bfd_is_abs_section (sec->output_section))
-    return TRUE;
-
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-
-  /* Load the relocations for this section.  */
-  internal_relocs = (_bfd_elf_link_read_relocs
-                    (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
-                     link_info->keep_memory));
-  if (internal_relocs == NULL)
-    return FALSE;
-
-  changed = FALSE;
-  htab = elf_x86_hash_table (link_info, I386_ELF_DATA);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
-
-  /* Get the section contents.  */
-  if (elf_section_data (sec)->this_hdr.contents != NULL)
-    contents = elf_section_data (sec)->this_hdr.contents;
-  else
-    {
-      if (!bfd_malloc_and_get_section (abfd, sec, &contents))
-       goto error_return;
-    }
-
-  irelend = internal_relocs + sec->reloc_count;
-  for (irel = internal_relocs; irel < irelend; irel++)
-    {
-      unsigned int r_type = ELF32_R_TYPE (irel->r_info);
-      unsigned int r_symndx;
-      struct elf_link_hash_entry *h;
-      bfd_boolean converted;
-
-      /* Don't convert R_386_GOT32 since we can't tell if it is applied
-        to "mov $foo@GOT, %reg" which isn't a load via GOT.  */
-      if (r_type != R_386_GOT32X)
-       continue;
-
-      r_symndx = ELF32_R_SYM (irel->r_info);
-      if (r_symndx < symtab_hdr->sh_info)
-       h = _bfd_elf_x86_get_local_sym_hash (htab, sec->owner,
-                                            (const Elf_Internal_Rela *) irel,
-                                            FALSE);
-      else
-       {
-         h = elf_sym_hashes (abfd)[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;
-       }
-
-      /* STT_GNU_IFUNC must keep GOT32 relocations.  */
-      if (h != NULL && h->type == STT_GNU_IFUNC)
-       continue;
-
-      converted = FALSE;
-      if (!elf_i386_convert_load_reloc (abfd, symtab_hdr, contents,
-                                       irel, h, &converted, link_info))
-       goto error_return;
-
-      if (converted)
-       {
-         changed = converted;
-         if (h)
-           {
-             if (h->got.refcount > 0)
-               h->got.refcount -= 1;
-           }
-         else
-           {
-             if (local_got_refcounts != NULL
-                 && local_got_refcounts[r_symndx] > 0)
-               local_got_refcounts[r_symndx] -= 1;
-           }
-       }
-    }
-
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    {
-      if (!changed && !link_info->keep_memory)
-       free (contents);
-      else
-       {
-         /* Cache the section contents for elf_link_input_bfd.  */
-         elf_section_data (sec)->this_hdr.contents = contents;
-       }
-    }
-
-  if (elf_section_data (sec)->relocs != internal_relocs)
-    {
-      if (!changed)
-       free (internal_relocs);
-      else
-       elf_section_data (sec)->relocs = internal_relocs;
-    }
-
-  return TRUE;
-
- error_return:
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    free (contents);
-  if (internal_relocs != NULL
-      && elf_section_data (sec)->relocs != internal_relocs)
-    free (internal_relocs);
-  return FALSE;
-}
-
 /* Set the correct type for an x86 ELF section.  We do this by the
    section name, which is a hack, but ought to work.  */
 
@@ -2182,7 +2060,7 @@ elf_i386_relocate_section (bfd *output_bfd,
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; wrel++, rel++)
     {
-      unsigned int r_type;
+      unsigned int r_type, r_type_tls;
       reloc_howto_type *howto;
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
@@ -2588,10 +2466,7 @@ do_ifunc_pointer:
        }
 
       resolved_to_zero = (eh != NULL
-                         && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
-                                                             I386_ELF_DATA,
-                                                             eh->has_got_reloc,
-                                                             eh));
+                         && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh));
 
       switch (r_type)
        {
@@ -2672,7 +2547,7 @@ r_386_got32:
                                                     bfd_link_pic (info),
                                                     h)
                  || (bfd_link_pic (info)
-                     && SYMBOL_REFERENCES_LOCAL (info, h))
+                     && SYMBOL_REFERENCES_LOCAL_P (info, h))
                  || (ELF_ST_VISIBILITY (h->other)
                      && h->root.type == bfd_link_hash_undefweak))
                {
@@ -2831,7 +2706,7 @@ disallow_got32:
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
                }
-             else if (!SYMBOL_REFERENCES_LOCAL (info, h)
+             else if (!SYMBOL_REFERENCES_LOCAL_P (info, h)
                       && (h->type == STT_FUNC
                           || h->type == STT_OBJECT)
                       && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
@@ -3029,17 +2904,18 @@ disallow_got32:
          if (tls_type == GOT_TLS_IE)
            tls_type = GOT_TLS_IE_NEG;
 
+          r_type_tls = r_type;
          if (! elf_i386_tls_transition (info, input_bfd,
                                         input_section, contents,
                                         symtab_hdr, sym_hashes,
-                                        &r_type, tls_type, rel,
+                                        &r_type_tls, tls_type, rel,
                                         relend, h, r_symndx, TRUE))
            return FALSE;
 
-         if (r_type == R_386_TLS_LE_32)
+         if (r_type_tls == R_386_TLS_LE_32)
            {
              BFD_ASSERT (! unresolved_reloc);
-             if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
+             if (r_type == R_386_TLS_GD)
                {
                  unsigned int type;
                  bfd_vma roff;
@@ -3082,7 +2958,7 @@ disallow_got32:
                  wrel++;
                  continue;
                }
-             else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC)
+             else if (r_type == R_386_TLS_GOTDESC)
                {
                  /* GDesc -> LE transition.
                     It's originally something like:
@@ -3107,7 +2983,7 @@ disallow_got32:
                              contents + roff);
                  continue;
                }
-             else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL)
+             else if (r_type == R_386_TLS_DESC_CALL)
                {
                  /* GDesc -> LE transition.
                     It's originally:
@@ -3122,7 +2998,7 @@ disallow_got32:
                  bfd_put_8 (output_bfd, 0x90, contents + roff + 1);
                  continue;
                }
-             else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE)
+             else if (r_type == R_386_TLS_IE)
                {
                  unsigned int val;
 
@@ -3216,7 +3092,7 @@ disallow_got32:
                    }
                  else
                    BFD_FAIL ();
-                 if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTIE)
+                 if (r_type == R_386_TLS_GOTIE)
                    bfd_put_32 (output_bfd, -elf_i386_tpoff (info, relocation),
                                contents + rel->r_offset);
                  else
@@ -3359,13 +3235,13 @@ disallow_got32:
          if (off >= (bfd_vma) -2
              && ! GOT_TLS_GDESC_P (tls_type))
            abort ();
-         if (r_type == R_386_TLS_GOTDESC
-             || r_type == R_386_TLS_DESC_CALL)
+         if (r_type_tls == R_386_TLS_GOTDESC
+             || r_type_tls == R_386_TLS_DESC_CALL)
            {
              relocation = htab->sgotplt_jump_table_size + offplt;
              unresolved_reloc = FALSE;
            }
-         else if (r_type == ELF32_R_TYPE (rel->r_info))
+         else if (r_type_tls == r_type)
            {
              bfd_vma g_o_t = htab->elf.sgotplt->output_section->vma
                              + htab->elf.sgotplt->output_offset;
@@ -3378,7 +3254,7 @@ disallow_got32:
                relocation += g_o_t;
              unresolved_reloc = FALSE;
            }
-         else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
+         else if (r_type == R_386_TLS_GD)
            {
              unsigned int val, type;
              bfd_vma roff;
@@ -3434,7 +3310,7 @@ disallow_got32:
              wrel++;
              continue;
            }
-         else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC)
+         else if (r_type == R_386_TLS_GOTDESC)
            {
              /* GDesc -> IE transition.
                 It's originally something like:
@@ -3473,7 +3349,7 @@ disallow_got32:
                          contents + roff);
              continue;
            }
-         else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL)
+         else if (r_type == R_386_TLS_DESC_CALL)
            {
              /* GDesc -> IE transition.
                 It's originally:
@@ -3744,9 +3620,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
   /* We keep PLT/GOT entries without dynamic PLT/GOT relocations for
      resolved undefined weak symbols in executable so that their
      references have value 0 at run-time.  */
-  local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, I386_ELF_DATA,
-                                                    eh->has_got_reloc,
-                                                    eh);
+  local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
 
   if (h->plt.offset != (bfd_vma) -1)
     {
@@ -4044,7 +3918,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
                     in static executable.  */
                  relgot = htab->elf.irelplt;
                }
-             if (SYMBOL_REFERENCES_LOCAL (info, h))
+             if (SYMBOL_REFERENCES_LOCAL_P (info, h))
                {
                  info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"),
                                          h->root.root.string,
@@ -4094,7 +3968,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
            }
        }
       else if (bfd_link_pic (info)
-              && SYMBOL_REFERENCES_LOCAL (info, h))
+              && SYMBOL_REFERENCES_LOCAL_P (info, h))
        {
          BFD_ASSERT((h->got.offset & 1) != 0);
          rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
@@ -4727,35 +4601,38 @@ elf_i386_get_synthetic_symtab (bfd *abfd,
 static bfd *
 elf_i386_link_setup_gnu_properties (struct bfd_link_info *info)
 {
-  struct elf_x86_plt_layout_table plt_layout;
+  struct elf_x86_init_table init_table;
 
-  plt_layout.normal_target = FALSE;
-  plt_layout.is_vxworks = FALSE;
+  init_table.normal_target = FALSE;
+  init_table.is_vxworks = FALSE;
   switch (get_elf_i386_backend_data (info->output_bfd)->os)
     {
     case is_normal:
-      plt_layout.lazy_plt = &elf_i386_lazy_plt;
-      plt_layout.non_lazy_plt = &elf_i386_non_lazy_plt;
-      plt_layout.lazy_ibt_plt = &elf_i386_lazy_ibt_plt;
-      plt_layout.non_lazy_ibt_plt = &elf_i386_non_lazy_ibt_plt;
-      plt_layout.normal_target = TRUE;
+      init_table.lazy_plt = &elf_i386_lazy_plt;
+      init_table.non_lazy_plt = &elf_i386_non_lazy_plt;
+      init_table.lazy_ibt_plt = &elf_i386_lazy_ibt_plt;
+      init_table.non_lazy_ibt_plt = &elf_i386_non_lazy_ibt_plt;
+      init_table.normal_target = TRUE;
       break;
     case is_vxworks:
-      plt_layout.lazy_plt = &elf_i386_lazy_plt;
-      plt_layout.non_lazy_plt = NULL;
-      plt_layout.lazy_ibt_plt = NULL;
-      plt_layout.non_lazy_ibt_plt = NULL;
-      plt_layout.is_vxworks = TRUE;
+      init_table.lazy_plt = &elf_i386_lazy_plt;
+      init_table.non_lazy_plt = NULL;
+      init_table.lazy_ibt_plt = NULL;
+      init_table.non_lazy_ibt_plt = NULL;
+      init_table.is_vxworks = TRUE;
       break;
     case is_nacl:
-      plt_layout.lazy_plt = &elf_i386_nacl_plt;
-      plt_layout.non_lazy_plt = NULL;
-      plt_layout.lazy_ibt_plt = NULL;
-      plt_layout.non_lazy_ibt_plt = NULL;
+      init_table.lazy_plt = &elf_i386_nacl_plt;
+      init_table.non_lazy_plt = NULL;
+      init_table.lazy_ibt_plt = NULL;
+      init_table.non_lazy_ibt_plt = NULL;
       break;
     }
 
-  return _bfd_x86_elf_link_setup_gnu_properties (info, &plt_layout);
+  init_table.r_info = elf32_r_info;
+  init_table.r_sym = elf32_r_sym;
+
+  return _bfd_x86_elf_link_setup_gnu_properties (info, &init_table);
 }
 
 #define TARGET_LITTLE_SYM              i386_elf32_vec
This page took 0.032524 seconds and 4 git commands to generate.