]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Call elf_i386_convert_load_reloc from elf_i386_check_relocs
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 27 Apr 2016 11:23:28 +0000 (04:23 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Tue, 3 May 2016 17:37:16 +0000 (10:37 -0700)
bfd/elf32-i386.c

index 483146b1a5a962c8207ecd9084f90ad2afbf0564..22b0b6af93b776dd18ae0818fb1e7b1a023ef2d8 100644 (file)
@@ -1531,7 +1531,6 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   unsigned int opcode;
   unsigned int modrm;
   bfd_boolean baseless;
-  Elf_Internal_Sym *isym;
   unsigned int addend;
   unsigned int nop;
   bfd_vma nop_offset;
@@ -1560,23 +1559,24 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
 
   if (r_type == R_386_GOT32X && baseless && is_pic)
     {
-      /* For PIC, disallow R_386_GOT32X without a base register
-        since we don't know what the GOT base is.   Allow
-        R_386_GOT32 for existing object files.  */
       const char *name;
 
       if (h == NULL)
        {
-         isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd,
-                                       r_symndx);
+         Elf_Internal_Sym *isym
+           = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx);
          name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
        }
       else
        name = h->root.root.string;
 
+      /* For PIC, disallow R_386_GOT32X without a base register since
+        we don't know what the GOT base is.  Allow R_386_GOT32 for
+        existing object files.  */
       (*_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);
+      bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
 
@@ -1750,8 +1750,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
@@ -1771,6 +1770,7 @@ elf_i386_check_relocs (bfd *abfd,
   asection *sreloc;
   bfd_byte *contents;
   bfd_boolean use_plt_got;
+  bfd_boolean changed;
 
   if (bfd_link_relocatable (info))
     return TRUE;
@@ -1800,6 +1800,7 @@ elf_i386_check_relocs (bfd *abfd,
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
 
+  changed = FALSE;
   sreloc = NULL;
 
   rel_end = relocs + sec->reloc_count;
@@ -1926,6 +1927,40 @@ elf_i386_check_relocs (bfd *abfd,
          size_reloc = TRUE;
          goto do_size;
 
+       case R_386_GOT32:
+       case R_386_GOT32X:
+         if (h == NULL || h->type != STT_GNU_IFUNC)
+           {
+             bfd_boolean converted = FALSE;
+
+             if (!elf_i386_convert_load_reloc (abfd, symtab_hdr,
+                                               contents,
+                                               (Elf_Internal_Rela *) rel,
+                                               h, &converted, info))
+               goto error_return;
+
+             if (converted)
+               {
+                 changed = TRUE;
+                 r_type = ELF32_R_TYPE (rel->r_info);
+                 switch (r_type)
+                   {
+                   default:
+                     abort ();
+                     break;
+                   case R_386_32:
+                   case R_386_PC32:
+                     break;
+                   case R_386_GOTOFF:
+                     if (eh != NULL)
+                       eh->gotoff_ref = 1;
+                     goto create_got;
+                   }
+                 break;
+               }
+           }
+         goto do_reloc_got32;
+
        case R_386_TLS_IE_32:
        case R_386_TLS_IE:
        case R_386_TLS_GOTIE:
@@ -1933,11 +1968,10 @@ elf_i386_check_relocs (bfd *abfd,
            info->flags |= DF_STATIC_TLS;
          /* Fall through */
 
-       case R_386_GOT32:
-       case R_386_GOT32X:
        case R_386_TLS_GD:
        case R_386_TLS_GOTDESC:
        case R_386_TLS_DESC_CALL:
+do_reloc_got32:
          /* This symbol requires a global offset table entry.  */
          {
            int tls_type, old_tls_type;
@@ -2266,15 +2300,11 @@ do_size:
                                             plt_got_align))
            goto error_return;
        }
-
-      if ((r_type == R_386_GOT32 || 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)
     {
-      if (!info->keep_memory)
+      if (!changed && !info->keep_memory)
        free (contents);
       else
        {
@@ -2283,6 +2313,14 @@ do_size:
        }
     }
 
+  if (elf_section_data (sec)->relocs != relocs && changed)
+    {
+      /* Must cache relocations if they are changed.  */
+      if (elf_section_data (sec)->relocs != NULL)
+       abort ();
+      elf_section_data (sec)->relocs = (Elf_Internal_Rela *) relocs;
+    }
+
   return TRUE;
 
 error_return:
@@ -2967,134 +3005,6 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
-/* Convert load via the GOT slot to load immediate.  */
-
-static bfd_boolean
-elf_i386_convert_load (bfd *abfd, asection *sec,
-                      struct bfd_link_info *link_info)
-{
-  struct elf_i386_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_i386_hash_table (link_info);
-  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;
-
-      if (r_type != R_386_GOT32 && r_type != R_386_GOT32X)
-       continue;
-
-      r_symndx = ELF32_R_SYM (irel->r_info);
-      if (r_symndx < symtab_hdr->sh_info)
-       h = elf_i386_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 sizes of the dynamic sections.  */
 
 static bfd_boolean
@@ -3132,9 +3042,6 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
        {
          struct elf_dyn_relocs *p;
 
-         if (!elf_i386_convert_load (ibfd, s, info))
-           return FALSE;
-
          for (p = ((struct elf_dyn_relocs *)
                     elf_section_data (s)->local_dynrel);
               p != NULL;