Disallow copy relocation against protected data symbol
[binutils-gdb.git] / bfd / elf64-x86-64.c
index e5f4681354ab2bb957ee0a3ddaa892da07a29bff..6e4c067732e7f3485c331eec40a08d59d79e7f0a 100644 (file)
@@ -1061,6 +1061,17 @@ static const struct elf_x86_64_backend_data elf_x86_64_arch_bed =
               || (EH)->has_non_got_reloc                       \
               || !(INFO)->dynamic_undefined_weak))))
 
+/* Should copy relocation be generated for a symbol.  Don't generate
+   copy relocation against a protected symbol defined in a shared
+   object with GNU_PROPERTY_NO_COPY_ON_PROTECTED.  */
+#define SYMBOL_NO_COPYRELOC(INFO, EH) \
+  ((EH)->def_protected \
+   && ((EH)->elf.root.type == bfd_link_hash_defined \
+       || (EH)->elf.root.type == bfd_link_hash_defweak) \
+   && elf_has_no_copy_on_protected ((EH)->elf.root.u.def.section->owner) \
+   && ((EH)->elf.root.u.def.section->owner->flags & DYNAMIC) != 0 \
+   && ((EH)->elf.root.u.def.section->flags & SEC_CODE) == 0)
+
 /* x86-64 ELF linker hash entry.  */
 
 struct elf_x86_64_link_hash_entry
@@ -1101,9 +1112,12 @@ struct elf_x86_64_link_hash_entry
   /* Don't call finish_dynamic_symbol on this symbol.  */
   unsigned int no_finish_dynamic_symbol : 1;
 
-  /* TRUE if symbol symbol is __tls_get_addr.  */
+  /* TRUE if symbol is __tls_get_addr.  */
   unsigned int tls_get_addr : 1;
 
+  /* TRUE if symbol is defined as a protected symbol.  */
+  unsigned int def_protected : 1;
+
   /* Reference count of C/C++ function pointer relocations in read-write
      section which can be resolved at run-time.  */
   bfd_signed_vma func_pointer_refcount;
@@ -1880,7 +1894,8 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
 #define check_relocs_failed    sec_flg1
 
 static bfd_boolean
-elf_x86_64_need_pic (bfd *input_bfd, asection *sec,
+elf_x86_64_need_pic (struct bfd_link_info *info,
+                    bfd *input_bfd, asection *sec,
                     struct elf_link_hash_entry *h,
                     Elf_Internal_Shdr *symtab_hdr,
                     Elf_Internal_Sym *isym,
@@ -1889,6 +1904,7 @@ elf_x86_64_need_pic (bfd *input_bfd, asection *sec,
   const char *v = "";
   const char *und = "";
   const char *pic = "";
+  const char *object;
 
   const char *name;
   if (h)
@@ -1906,7 +1922,10 @@ elf_x86_64_need_pic (bfd *input_bfd, asection *sec,
          v = _("protected symbol ");
          break;
        default:
-         v = _("symbol ");
+         if (((struct elf_x86_64_link_hash_entry *) h)->def_protected)
+           v = _("protected symbol ");
+         else
+           v = _("symbol ");
          pic = _("; recompile with -fPIC");
          break;
        }
@@ -1920,10 +1939,18 @@ elf_x86_64_need_pic (bfd *input_bfd, asection *sec,
       pic = _("; recompile with -fPIC");
     }
 
+  if (bfd_link_dll (info))
+    object = _("a shared object");
+  else if (bfd_link_pie (info))
+    object = _("a PIE object");
+  else
+    object = _("a PDE object");
+
   /* xgettext:c-format */
   _bfd_error_handler (_("%B: relocation %s against %s%s`%s' can "
-                       "not be used when making a shared object%s"),
-                     input_bfd, howto->name, und, v, name, pic);
+                       "not be used when making %s%s"),
+                     input_bfd, howto->name, und, v, name,
+                     object, pic);
   bfd_set_error (bfd_error_bad_value);
   sec->check_relocs_failed = 1;
   return FALSE;
@@ -2519,7 +2546,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
        case R_X86_64_TPOFF32:
          if (!bfd_link_executable (info) && ABI_64_P (abfd))
-           return elf_x86_64_need_pic (abfd, sec, h, symtab_hdr, isym,
+           return elf_x86_64_need_pic (info, abfd, sec, h, symtab_hdr, isym,
                                        &x86_64_elf_howto_table[r_type]);
          if (eh != NULL)
            eh->has_got_reloc = 1;
@@ -2685,7 +2712,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                      && !h->def_regular
                      && h->def_dynamic
                      && (sec->flags & SEC_READONLY) == 0)))
-           return elf_x86_64_need_pic (abfd, sec, h, symtab_hdr, isym,
+           return elf_x86_64_need_pic (info, abfd, sec, h, symtab_hdr, isym,
                                        &x86_64_elf_howto_table[r_type]);
          /* Fall through.  */
 
@@ -3033,6 +3060,8 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
        the link may change h->type.  So fix it now.  */
     h->plt.offset = (bfd_vma) -1;
 
+  eh = (struct elf_x86_64_link_hash_entry *) h;
+
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
      real definition first, and we can just use the same value.         */
@@ -3042,9 +3071,10 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
                  || h->u.weakdef->root.type == bfd_link_hash_defweak);
       h->root.u.def.section = h->u.weakdef->root.u.def.section;
       h->root.u.def.value = h->u.weakdef->root.u.def.value;
-      if (ELIMINATE_COPY_RELOCS || info->nocopyreloc)
+      if (ELIMINATE_COPY_RELOCS
+         || info->nocopyreloc
+         || SYMBOL_NO_COPYRELOC (info, eh))
        {
-         eh = (struct elf_x86_64_link_hash_entry *) h;
          h->non_got_ref = h->u.weakdef->non_got_ref;
          eh->needs_copy = h->u.weakdef->needs_copy;
        }
@@ -3067,7 +3097,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
     return TRUE;
 
   /* If -z nocopyreloc was given, we won't generate them either.  */
-  if (info->nocopyreloc)
+  if (info->nocopyreloc || SYMBOL_NO_COPYRELOC (info, eh))
     {
       h->non_got_ref = 0;
       return TRUE;
@@ -4932,13 +4962,19 @@ do_ifunc_pointer:
        case R_X86_64_PC32:
        case R_X86_64_PC32_BND:
          /* Don't complain about -fPIC if the symbol is undefined when
-            building executable unless it is unresolved weak symbol.  */
+            building executable unless it is unresolved weak symbol or
+            -z nocopyreloc is used.  */
           if ((input_section->flags & SEC_ALLOC) != 0
              && (input_section->flags & SEC_READONLY) != 0
              && h != NULL
              && ((bfd_link_executable (info)
-                  && h->root.type == bfd_link_hash_undefweak
-                  && !resolved_to_zero)
+                  && ((h->root.type == bfd_link_hash_undefweak
+                       && !resolved_to_zero)
+                      || ((info->nocopyreloc
+                           || (eh->def_protected
+                               && elf_has_no_copy_on_protected (h->root.u.def.section->owner)))
+                          && h->def_dynamic
+                          && !(h->root.u.def.section->flags & SEC_CODE))))
                  || bfd_link_dll (info)))
            {
              bfd_boolean fail = FALSE;
@@ -4965,7 +5001,7 @@ do_ifunc_pointer:
                }
 
              if (fail)
-               return elf_x86_64_need_pic (input_bfd, input_section,
+               return elf_x86_64_need_pic (info, input_bfd, input_section,
                                            h, NULL, NULL, howto);
            }
          /* Fall through.  */
@@ -5707,15 +5743,29 @@ direct:
          && _bfd_elf_section_offset (output_bfd, info, input_section,
                                      rel->r_offset) != (bfd_vma) -1)
        {
-         _bfd_error_handler
-           /* xgettext:c-format */
-           (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"),
-            input_bfd,
-            input_section,
-            rel->r_offset,
-            howto->name,
-            h->root.root.string);
-         return FALSE;
+         switch (r_type)
+           {
+           case R_X86_64_32S:
+             sec = h->root.u.def.section;
+             if ((info->nocopyreloc
+                  || (eh->def_protected
+                      && elf_has_no_copy_on_protected (h->root.u.def.section->owner)))
+                 && !(h->root.u.def.section->flags & SEC_CODE))
+               return elf_x86_64_need_pic (info, input_bfd, input_section,
+                                           h, NULL, NULL, howto);
+             /* Fall through.  */
+
+           default:
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"),
+                input_bfd,
+                input_section,
+                rel->r_offset,
+                howto->name,
+                h->root.root.string);
+             return FALSE;
+           }
        }
 
 do_relocation:
@@ -6634,13 +6684,13 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd,
                                 asymbol **dynsyms,
                                 asymbol **ret)
 {
-  long size, count, i, n;
+  long size, count, i, n, len;
   int j;
   unsigned int plt_got_offset, plt_entry_size, plt_got_insn_size;
   asymbol *s;
   bfd_byte *plt_contents;
   long dynrelcount, relsize;
-  arelent **dynrelbuf;
+  arelent **dynrelbuf, *p;
   const struct elf_x86_64_lazy_plt_layout *lazy_plt;
   const struct elf_x86_64_non_lazy_plt_layout *non_lazy_plt;
   const struct elf_x86_64_lazy_plt_layout *lazy_bnd_plt;
@@ -6821,6 +6871,17 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd,
     }
 
   size = count * sizeof (asymbol);
+
+  /* Allocate space for @plt suffixes.  */
+  n = 0;
+  for (i = 0; i < dynrelcount; i++)
+    {
+      p = dynrelbuf[i];
+      size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+      if (p->addend != 0)
+       size += sizeof ("+0x") - 1 + 8 + 8 * ABI_64_P (abfd);
+    }
+
   s = *ret = (asymbol *) bfd_zmalloc (size);
   if (s == NULL)
     {
@@ -6833,6 +6894,7 @@ bad_return:
     }
 
   /* Check for each PLT section.  */
+  names = (char *) (s + count);
   size = 0;
   n = 0;
   for (j = 0; plts[j].name != NULL; j++)
@@ -6865,7 +6927,6 @@ bad_return:
            int off;
            bfd_vma got_vma;
            long min, max, mid;
-           arelent *p;
 
            /* Get the PC-relative offset, a signed 32-bit integer.  */
            off = H_GET_32 (abfd, (plt_contents + offset
@@ -6912,12 +6973,26 @@ bad_return:
                s->section = plt;
                s->the_bfd = plt->owner;
                s->value = offset;
-               /* Store relocation for later use.  */
-               s->udata.p = p;
-               /* Add @plt to function name later.  */
-               size += strlen (s->name) + sizeof ("@plt");
+               s->udata.p = NULL;
+               s->name = names;
+               len = strlen ((*p->sym_ptr_ptr)->name);
+               memcpy (names, (*p->sym_ptr_ptr)->name, len);
+               names += len;
                if (p->addend != 0)
-                 size += sizeof ("+0x") - 1 + 8 + 8 * ABI_64_P (abfd);
+                 {
+                   char buf[30], *a;
+
+                   memcpy (names, "+0x", sizeof ("+0x") - 1);
+                   names += sizeof ("+0x") - 1;
+                   bfd_sprintf_vma (abfd, buf, p->addend);
+                   for (a = buf; *a == '0'; ++a)
+                     ;
+                   size = strlen (a);
+                   memcpy (names, a, size);
+                   names += size;
+                 }
+               memcpy (names, "@plt", sizeof ("@plt"));
+               names += sizeof ("@plt");
                n++;
                s++;
              }
@@ -6931,40 +7006,6 @@ bad_return:
 
   count = n;
 
-  /* Allocate space for @plt suffixes.  */
-  names = (char *) bfd_malloc (size);
-  if (s == NULL)
-    goto bad_return;
-
-  s = *ret;
-  for (i = 0; i < count; i++)
-    {
-      /* Add @plt to function name.  */
-      arelent *p = (arelent *) s->udata.p;
-      /* Clear it now.  */
-      s->udata.p = NULL;
-      size = strlen (s->name);
-      memcpy (names, s->name, size);
-      s->name = names;
-      names += size;
-      if (p->addend != 0)
-       {
-         char buf[30], *a;
-
-         memcpy (names, "+0x", sizeof ("+0x") - 1);
-         names += sizeof ("+0x") - 1;
-         bfd_sprintf_vma (abfd, buf, p->addend);
-         for (a = buf; *a == '0'; ++a)
-           ;
-         size = strlen (a);
-         memcpy (names, a, size);
-         names += size;
-       }
-      memcpy (names, "@plt", sizeof ("@plt"));
-      names += sizeof ("@plt");
-      s++;
-    }
-
   for (j = 0; plts[j].name != NULL; j++)
     if (plts[j].contents != NULL)
       free (plts[j].contents);
@@ -7121,6 +7162,21 @@ elf_x86_64_merge_symbol (struct elf_link_hash_entry *h,
   return TRUE;
 }
 
+static void
+elf_x86_64_merge_symbol_attribute (struct elf_link_hash_entry *h,
+                                  const Elf_Internal_Sym *isym,
+                                  bfd_boolean definition,
+                                  bfd_boolean dynamic ATTRIBUTE_UNUSED)
+{
+  if (definition)
+    {
+      struct elf_x86_64_link_hash_entry *eh
+       = (struct elf_x86_64_link_hash_entry *) h;
+      eh->def_protected = (ELF_ST_VISIBILITY (isym->st_other)
+                          == STV_PROTECTED);
+    }
+}
+
 static int
 elf_x86_64_additional_program_headers (bfd *abfd,
                                       struct bfd_link_info *info ATTRIBUTE_UNUSED)
@@ -7311,50 +7367,41 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info)
   unsigned int plt_alignment, features;
   struct elf_x86_64_link_hash_table *htab;
   bfd *pbfd;
+  bfd *ebfd = NULL;
+  elf_property *prop;
 
   features = 0;
   if (info->ibt)
     features = GNU_PROPERTY_X86_FEATURE_1_IBT;
   if (info->shstk)
     features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
-  if (features)
+
+  /* Find a normal input file with GNU property note.  */
+  for (pbfd = info->input_bfds;
+       pbfd != NULL;
+       pbfd = pbfd->link.next)
+    if (bfd_get_flavour (pbfd) == bfd_target_elf_flavour
+       && bfd_count_sections (pbfd) != 0)
+      {
+       ebfd = pbfd;
+
+       if (elf_properties (pbfd) != NULL)
+         break;
+      }
+
+  if (ebfd != NULL && features)
     {
-      /* Turn on GNU_PROPERTY_X86_FEATURE_1_IBT and
+      /* If features is set, add GNU_PROPERTY_X86_FEATURE_1_IBT and
         GNU_PROPERTY_X86_FEATURE_1_SHSTK.  */
-      bfd *ebfd = NULL;
-      elf_property *prop;
-
-      for (pbfd = info->input_bfds;
-          pbfd != NULL;
-          pbfd = pbfd->link.next)
-       if (bfd_get_flavour (pbfd) == bfd_target_elf_flavour
-           && bfd_count_sections (pbfd) != 0)
-         {
-           ebfd = pbfd;
-
-           if (elf_properties (pbfd) != NULL)
-             {
-               /* Find a normal input file with GNU property note.  */
-               prop = _bfd_elf_get_property (pbfd,
-                                             GNU_PROPERTY_X86_FEATURE_1_AND,
-                                             4);
-               /* Add GNU_PROPERTY_X86_FEATURE_1_IBT and
-                  GNU_PROPERTY_X86_FEATURE_1_SHSTK.  */
-               prop->u.number |= features;
-               prop->pr_kind = property_number;
-               break;
-             }
-         }
+      prop = _bfd_elf_get_property (ebfd,
+                                   GNU_PROPERTY_X86_FEATURE_1_AND,
+                                   4);
+      prop->u.number |= features;
+      prop->pr_kind = property_number;
 
-      if (pbfd == NULL && ebfd != NULL)
+      /* Create the GNU property note section if needed.  */
+      if (pbfd == NULL)
        {
-         /* Create GNU_PROPERTY_X86_FEATURE_1_IBT if needed.  */
-         prop = _bfd_elf_get_property (ebfd,
-                                       GNU_PROPERTY_X86_FEATURE_1_AND,
-                                       4);
-         prop->u.number = features;
-         prop->pr_kind = property_number;
-
          sec = bfd_make_section_with_flags (ebfd,
                                             NOTE_GNU_PROPERTY_SECTION_NAME,
                                             (SEC_ALLOC
@@ -7427,8 +7474,9 @@ error_alignment:
          for (abfd = info->input_bfds;
               abfd != NULL;
               abfd = abfd->link.next)
-           if ((abfd->flags
-                & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
+           if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+               && (abfd->flags
+                   & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0)
              {
                htab->elf.dynobj = abfd;
                dynobj = abfd;
@@ -7793,6 +7841,8 @@ elf_x86_64_special_sections[]=
   elf_x86_64_common_definition
 #define elf_backend_merge_symbol \
   elf_x86_64_merge_symbol
+#define elf_backend_merge_symbol_attribute \
+  elf_x86_64_merge_symbol_attribute
 #define elf_backend_special_sections \
   elf_x86_64_special_sections
 #define elf_backend_additional_program_headers \