elf: Add GNU_PROPERTY_1_NEEDED check
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 17 Jun 2021 21:11:28 +0000 (14:11 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Fri, 9 Jul 2021 01:14:31 +0000 (18:14 -0700)
If GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS is set on any input
relocatable files:

1. Don't generate copy relocations.
2. Turn off extern_protected_data since it implies
GNU_PROPERTY_NO_COPY_ON_PROTECTED.
3. Treate reference to protected symbols with indirect external access
as local.
4. Set GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS on output.
5. When generating executable, clear this bit when there are non-GOT or
non-PLT relocations in input relocatable files without the bit set.
6. Add -z [no]indirect-extern-access to control indirect external access.

bfd/

* elf-bfd (elf_obj_tdata): Add has_indirect_extern_access.
(elf_has_indirect_extern_access): New.
* elf-properties.c (_bfd_elf_parse_gnu_properties): Set
elf_has_indirect_extern_access and elf_has_no_copy_on_protected
when seeing GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.
(elf_write_gnu_propertie): Add an argument to pass link_info.
Set needed_1_p for GNU_PROPERTY_1_NEEDED in memory.
(_bfd_elf_link_setup_gnu_properties): Handle
GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS for
-z indirect-extern-access.  Set nocopyreloc to true and
extern_protected_data to false for indirect external access.
(_bfd_elf_convert_gnu_properties): Updated.
* elf32-i386.c (elf_i386_check_relocs): Set
non_got_ref_without_indirect_extern_access on legacy non-GOT or
non-PLT references.
* elf64-x86-64.c (elf_x86_64_check_relocs): Likewise.
* elflink.c (_bfd_elf_symbol_refs_local_p): Return true for
STV_PROTECTED symbols with indirect external access.
* elfxx-x86.c (_bfd_x86_elf_adjust_dynamic_symbol): Clear
indirect_extern_access for legacy non-GOT/non-PLT references.
* elfxx-x86.h (elf_x86_link_hash_entry): Add
non_got_ref_without_indirect_extern_access.

include/

* bfdlink.h (bfd_link_info): Add indirect_extern_access and
needed_1_p.  Change nocopyreloc to int.

ld/

* NEWS: Mention -z [no]indirect-extern-access
* ld.texi: Document -z [no]indirect-extern-access
* ldmain.c (main): Initialize link_info.indirect_extern_access
to -1.
* emulparams/extern_protected_data.sh: Support
-z [no]indirect-extern-access.
* testsuite/ld-elf/indirect-extern-access-1.rd: New file
* testsuite/ld-elf/indirect-extern-access-1a.c: Likewise.
* testsuite/ld-elf/indirect-extern-access-1b.c: Likewise.
* testsuite/ld-elf/indirect-extern-access-2.rd: Likewise.
* testsuite/ld-elf/indirect-extern-access-2a.c: Likewise.
* testsuite/ld-elf/indirect-extern-access-2b.c: Likewise.
* testsuite/ld-elf/indirect-extern-access-3.rd: Likewise.
* testsuite/ld-elf/indirect-extern-access.S: Likewise.
* testsuite/ld-elf/property-1_needed-1b.d: Likewise.
* testsuite/ld-elf/property-1_needed-1c.d: Likewise.
* testsuite/ld-x86-64/indirect-extern-access.rd: Likewise.
* testsuite/ld-x86-64/protected-data-1.h: Likewise.
* testsuite/ld-x86-64/protected-data-1a.c: Likewise.
* testsuite/ld-x86-64/protected-data-1b.c: Likewise.
* testsuite/ld-x86-64/protected-data-2a.S: Likewise.
* testsuite/ld-x86-64/protected-data-2b.S: Likewise.
* testsuite/ld-x86-64/protected-func-2a.S: Likewise.
* testsuite/ld-x86-64/protected-func-2b.S: Likewise.
* testsuite/ld-x86-64/protected-func-2c.c: Likewise.
* testsuite/ld-elf/linux-x86.exp: Run test with
GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.
* testsuite/ld-x86-64/x86-64.exp: Run tests for protected
function and data with indirect external access.

33 files changed:
bfd/elf-bfd.h
bfd/elf-properties.c
bfd/elf32-i386.c
bfd/elf64-x86-64.c
bfd/elflink.c
bfd/elfxx-x86.c
bfd/elfxx-x86.h
include/bfdlink.h
ld/NEWS
ld/emulparams/extern_protected_data.sh
ld/ld.texi
ld/ldmain.c
ld/testsuite/ld-elf/indirect-extern-access-1.rd [new file with mode: 0644]
ld/testsuite/ld-elf/indirect-extern-access-1a.c [new file with mode: 0644]
ld/testsuite/ld-elf/indirect-extern-access-1b.c [new file with mode: 0644]
ld/testsuite/ld-elf/indirect-extern-access-2.rd [new file with mode: 0644]
ld/testsuite/ld-elf/indirect-extern-access-2a.c [new file with mode: 0644]
ld/testsuite/ld-elf/indirect-extern-access-2b.c [new file with mode: 0644]
ld/testsuite/ld-elf/indirect-extern-access-3.rd [new file with mode: 0644]
ld/testsuite/ld-elf/indirect-extern-access.S [new file with mode: 0644]
ld/testsuite/ld-elf/linux-x86.exp
ld/testsuite/ld-elf/property-1_needed-1b.d [new file with mode: 0644]
ld/testsuite/ld-elf/property-1_needed-1c.d [new file with mode: 0644]
ld/testsuite/ld-x86-64/indirect-extern-access.rd [new file with mode: 0644]
ld/testsuite/ld-x86-64/protected-data-1.h [new file with mode: 0644]
ld/testsuite/ld-x86-64/protected-data-1a.c [new file with mode: 0644]
ld/testsuite/ld-x86-64/protected-data-1b.c [new file with mode: 0644]
ld/testsuite/ld-x86-64/protected-data-2a.S [new file with mode: 0644]
ld/testsuite/ld-x86-64/protected-data-2b.S [new file with mode: 0644]
ld/testsuite/ld-x86-64/protected-func-2a.S [new file with mode: 0644]
ld/testsuite/ld-x86-64/protected-func-2b.S [new file with mode: 0644]
ld/testsuite/ld-x86-64/protected-func-2c.c [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp

index 65c08ca9d4a6689cf628c5bbfe78f08b2571455f..b3f56b8c2ce055fa666517270a8e4973f0663d7c 100644 (file)
@@ -2073,6 +2073,10 @@ struct elf_obj_tdata
      property.  */
   unsigned int has_no_copy_on_protected : 1;
 
+  /* Whether if the bfd contains the
+     GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS property.  */
+  unsigned int has_indirect_extern_access : 1;
+
   /* Irix 5 often screws up the symbol table, sorting local symbols
      after global symbols.  This flag is set if the symbol table in
      this BFD appears to be screwed up.  If it is, we ignore the
@@ -2138,6 +2142,8 @@ struct elf_obj_tdata
 #define elf_properties(bfd) (elf_tdata (bfd) -> properties)
 #define elf_has_no_copy_on_protected(bfd) \
   (elf_tdata(bfd) -> has_no_copy_on_protected)
+#define elf_has_indirect_extern_access(bfd) \
+  (elf_tdata(bfd) -> has_indirect_extern_access)
 \f
 extern void _bfd_elf_swap_verdef_in
   (bfd *, const Elf_External_Verdef *, Elf_Internal_Verdef *);
index 56ee91d7786b30b5bb435265cbafd991512f8c2f..aae02885c15bb7be21516749dd914ac2a5c7ec70 100644 (file)
@@ -195,6 +195,18 @@ _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note)
                  prop = _bfd_elf_get_property (abfd, type, datasz);
                  prop->u.number |= bfd_h_get_32 (abfd, ptr);
                  prop->pr_kind = property_number;
+                 if ((abfd->flags & DYNAMIC) == 0
+                     && type == GNU_PROPERTY_1_NEEDED
+                     && ((prop->u.number
+                          & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
+                         != 0))
+                   {
+                     /* NB: Skip the shared library since it may not be
+                        the same at run-time.  */
+                     elf_has_indirect_extern_access (abfd) = true;
+                     /* GNU_PROPERTY_NO_COPY_ON_PROTECTED is implied.  */
+                     elf_has_no_copy_on_protected (abfd) = true;
+                   }
                  goto next;
                }
              break;
@@ -525,7 +537,8 @@ elf_get_gnu_property_section_size (elf_property_list *list,
 /* Write GNU properties.  */
 
 static void
-elf_write_gnu_properties (bfd *abfd, bfd_byte *contents,
+elf_write_gnu_properties (struct bfd_link_info *info,
+                         bfd *abfd, bfd_byte *contents,
                          elf_property_list *list, unsigned int size,
                          unsigned int align_size)
 {
@@ -570,6 +583,11 @@ elf_write_gnu_properties (bfd *abfd, bfd_byte *contents,
              break;
 
            case 4:
+             /* Save the pointer to GNU_PROPERTY_1_NEEDED so that it
+                can be updated later if needed.  */
+             if (info != NULL
+                 && list->property.pr_type == GNU_PROPERTY_1_NEEDED)
+               info->needed_1_p = contents + size;
              bfd_h_put_32 (abfd, list->property.u.number,
                            contents + size);
              break;
@@ -598,7 +616,7 @@ elf_write_gnu_properties (bfd *abfd, bfd_byte *contents,
 bfd *
 _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
 {
-  bfd *abfd, *first_pbfd = NULL;
+  bfd *abfd, *first_pbfd = NULL, *elf_bfd = NULL;
   elf_property_list *list;
   asection *sec;
   bool has_properties = false;
@@ -606,32 +624,75 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
     = get_elf_backend_data (info->output_bfd);
   unsigned int elfclass = bed->s->elfclass;
   int elf_machine_code = bed->elf_machine_code;
+  elf_property *p;
 
   /* Find the first relocatable ELF input with GNU properties.  */
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
     if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
        && (abfd->flags & DYNAMIC) == 0
-       && elf_properties (abfd) != NULL)
+       && (elf_machine_code
+           == get_elf_backend_data (abfd)->elf_machine_code)
+       && (elfclass == get_elf_backend_data (abfd)->s->elfclass))
       {
-       has_properties = true;
-
        /* Ignore GNU properties from ELF objects with different machine
           code or class.  Also skip objects without a GNU_PROPERTY note
           section.  */
-       if ((elf_machine_code
-            == get_elf_backend_data (abfd)->elf_machine_code)
-           && (elfclass
-               == get_elf_backend_data (abfd)->s->elfclass)
-           && bfd_get_section_by_name (abfd,
-                                       NOTE_GNU_PROPERTY_SECTION_NAME) != NULL
-           )
+       elf_bfd = abfd;
+
+       if (elf_properties (abfd) != NULL)
          {
-           /* Keep .note.gnu.property section in FIRST_PBFD.  */
-           first_pbfd = abfd;
-           break;
+           has_properties = true;
+
+           if (bfd_get_section_by_name (abfd,
+                                        NOTE_GNU_PROPERTY_SECTION_NAME)
+               != NULL)
+             {
+               /* Keep .note.gnu.property section in FIRST_PBFD.  */
+               first_pbfd = abfd;
+               break;
+             }
          }
       }
 
+  if (info->indirect_extern_access > 0 && elf_bfd != NULL)
+    {
+      /* Support -z indirect-extern-access.  */
+      if (first_pbfd == NULL)
+       {
+         sec = bfd_make_section_with_flags (elf_bfd,
+                                            NOTE_GNU_PROPERTY_SECTION_NAME,
+                                            (SEC_ALLOC
+                                             | SEC_LOAD
+                                             | SEC_IN_MEMORY
+                                             | SEC_READONLY
+                                             | SEC_HAS_CONTENTS
+                                             | SEC_DATA));
+         if (sec == NULL)
+           info->callbacks->einfo (_("%F%P: failed to create GNU property section\n"));
+
+         if (!bfd_set_section_alignment (sec,
+                                         elfclass == ELFCLASS64 ? 3 : 2))
+           info->callbacks->einfo (_("%F%pA: failed to align section\n"),
+                                   sec);
+
+         elf_section_type (sec) = SHT_NOTE;
+         first_pbfd = elf_bfd;
+         has_properties = true;
+       }
+
+      p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_1_NEEDED, 4);
+      if (p->pr_kind == property_unknown)
+       {
+         /* Create GNU_PROPERTY_1_NEEDED.  */
+         p->u.number
+           = GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
+         p->pr_kind = property_number;
+       }
+      else
+       p->u.number
+         |= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
+    }
+
   /* Do nothing if there is no .note.gnu.property section.  */
   if (!has_properties)
     return NULL;
@@ -695,7 +756,6 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
         if N > 0.  */
       if (info->stacksize > 0)
        {
-         elf_property *p;
          bfd_vma stacksize = info->stacksize;
 
          p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE,
@@ -737,7 +797,30 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
       sec->size = size;
       contents = (bfd_byte *) bfd_zalloc (first_pbfd, size);
 
-      elf_write_gnu_properties (first_pbfd, contents, list, size,
+      if (info->indirect_extern_access <= 0)
+       {
+         /* Get GNU_PROPERTY_1_NEEDED properties.  */
+         p = elf_find_and_remove_property (&elf_properties (first_pbfd),
+                                           GNU_PROPERTY_1_NEEDED, false);
+         if (p != NULL)
+           {
+             if (info->indirect_extern_access < 0)
+               {
+                 /* Set indirect_extern_access to 1 to indicate that
+                    it is turned on by input properties.  */
+                 if ((p->u.number
+                      & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
+                     != 0)
+                   info->indirect_extern_access = 1;
+               }
+             else
+               /* Turn off indirect external access.  */
+               p->u.number
+                 &= ~GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
+           }
+       }
+
+      elf_write_gnu_properties (info, first_pbfd, contents, list, size,
                                align_size);
 
       /* Cache the section contents for elf_link_input_bfd.  */
@@ -747,6 +830,15 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
         symbol is defined in the shared object.  */
       if (elf_has_no_copy_on_protected (first_pbfd))
        info->extern_protected_data = false;
+
+      if (info->indirect_extern_access > 0)
+       {
+         /* For indirect external access, don't generate copy
+            relocations.  NB: Set to nocopyreloc to 2 to indicate
+            that it is implied by indirect_extern_access.  */
+         info->nocopyreloc = 2;
+         info->extern_protected_data = false;
+       }
     }
 
   return first_pbfd;
@@ -804,7 +896,8 @@ _bfd_elf_convert_gnu_properties (bfd *ibfd, asection *isec,
   *ptr_size = size;
 
   /* Generate the output .note.gnu.property section.  */
-  elf_write_gnu_properties (ibfd, contents, list, size, 1 << align_shift);
+  elf_write_gnu_properties (NULL, ibfd, contents, list, size,
+                           1 << align_shift);
 
   return true;
 }
index 1898ba3e33af3be96817749762b37d385cdd3cf2..9a9e48becdbdaa2a6d282a1031da32adf4bf8844 100644 (file)
@@ -1815,6 +1815,9 @@ elf_i386_check_relocs (bfd *abfd,
                     adjust_dynamic_symbol.  */
                  h->non_got_ref = 1;
 
+                 if (!elf_has_indirect_extern_access (sec->owner))
+                   eh->non_got_ref_without_indirect_extern_access = 1;
+
                  /* We may need a .plt entry if the symbol is a function
                     defined in a shared lib or is a function referenced
                     from the code or read-only section.  */
index 8deb62dba5c7736fddad146708de042891d5520d..dc416a7f7120070f384de0e92a7dd4cff0455ad2 100644 (file)
@@ -1972,6 +1972,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
            break;
          }
 
+      eh = (struct elf_x86_link_hash_entry *) h;
+
       if (h != NULL)
        {
          /* It is referenced by a non-shared object. */
@@ -2008,7 +2010,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
       if (h == htab->elf.hgot)
        htab->got_referenced = true;
 
-      eh = (struct elf_x86_link_hash_entry *) h;
       switch (r_type)
        {
        case R_X86_64_TLSLD:
@@ -2263,6 +2264,9 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                     adjust_dynamic_symbol.  */
                  h->non_got_ref = 1;
 
+                 if (!elf_has_indirect_extern_access (sec->owner))
+                   eh->non_got_ref_without_indirect_extern_access = 1;
+
                  /* We may need a .plt entry if the symbol is a function
                     defined in a shared lib or is a function referenced
                     from the code or read-only section.  */
index 003c9546b034379b46be59364a9d086b2ae8720e..c9d5da2dab4aef2edb35b14870d9a37fe87a44de 100644 (file)
@@ -3353,6 +3353,10 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
   if (!is_elf_hash_table (&hash_table->root))
     return true;
 
+  /* STV_PROTECTED symbols with indirect external access are local. */
+  if (info->indirect_extern_access > 0)
+    return true;
+
   bed = get_elf_backend_data (hash_table->dynobj);
 
   /* If extern_protected_data is false, STV_PROTECTED non-function
index 088f6e5c5366495e77ee5e80a881b67d551765ab..fe4a822041bcaeb970ce2a84af4233608b204708 100644 (file)
@@ -1824,6 +1824,25 @@ _bfd_x86_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   eh = (struct elf_x86_link_hash_entry *) h;
 
+  /* Clear GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS if it is turned
+     on by an input relocatable file and there is a non-GOT/non-PLT
+     reference from another relocatable file without it.
+     NB: There can be non-GOT reference in data sections in input with
+     GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.  */
+  if (eh->non_got_ref_without_indirect_extern_access
+      && info->indirect_extern_access == 1
+      && bfd_link_executable (info))
+    {
+      unsigned int needed_1;
+      info->indirect_extern_access = 0;
+      /* Turn off nocopyreloc if implied by indirect_extern_access.  */
+      if (info->nocopyreloc == 2)
+       info->nocopyreloc = 0;
+      needed_1 = bfd_h_get_32 (info->output_bfd, info->needed_1_p);
+      needed_1 &= ~GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
+      bfd_h_put_32 (info->output_bfd, needed_1, info->needed_1_p);
+    }
+
   /* STT_GNU_IFUNC symbol must go through PLT. */
   if (h->type == STT_GNU_IFUNC)
     {
index db11327e96f403bed1d4f582117fc04493c9735d..8251f641a77b6f1dada208882df4a09b33732df6 100644 (file)
@@ -279,6 +279,10 @@ struct elf_x86_link_hash_entry
   /* TRUE if symbol is defined by linker.  */
   unsigned int linker_def : 1;
 
+  /* TRUE if symbol is referenced by a non-GOT/non-PLT relocation in a
+     relocatable object file without indirect external access marker.  */
+  unsigned int non_got_ref_without_indirect_extern_access : 1;
+
   /* TRUE if symbol is referenced by R_386_GOTOFF relocation.  This is
      only used by i386.  */
   unsigned int gotoff_ref : 1;
index 549685854107707e7a9b2d36b6e677eaa7244108..566529ee64459166f0599f387a9eb339be4d33f0 100644 (file)
@@ -335,10 +335,6 @@ struct bfd_link_info
   /* TRUE if BFD should pre-bind symbols in a shared object.  */
   unsigned int symbolic: 1;
 
-  /* TRUE if executable should not contain copy relocs.
-     Setting this true may result in a non-sharable text segment.  */
-  unsigned int nocopyreloc: 1;
-
   /* TRUE if BFD should export all symbols in the dynamic symbol table
      of an executable, rather than only those used.  */
   unsigned int export_dynamic: 1;
@@ -652,6 +648,25 @@ struct bfd_link_info
   /* How many spare .dynamic DT_NULL entries should be added?  */
   unsigned int spare_dynamic_tags;
 
+  /* GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS control:
+       > 1: Turn on by -z indirect-extern-access or by backend.
+      == 1: Turn on by an input.
+         0: Turn off.
+       < 0: Turn on if it is set on any inputs or let backend to
+           decide.  */
+  int indirect_extern_access;
+
+  /* Non-zero if executable should not contain copy relocs.
+       > 1: Implied by indirect_extern_access.
+      == 1: Turn on by -z nocopyreloc.
+         0: Turn off.
+    Setting this to non-zero may result in a non-sharable text
+    segment.  */
+  int nocopyreloc;
+
+  /* Pointer to the GNU_PROPERTY_1_NEEDED property in memory.  */
+  bfd_byte *needed_1_p;
+
   /* May be used to set DT_FLAGS for ELF. */
   bfd_vma flags;
 
diff --git a/ld/NEWS b/ld/NEWS
index 92dd4fd97cdb3532f14be6b9cdb76d6dba61877e..59d1d3c979d28ac30675354da1a5cd40e69fb620 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add -z indirect-extern-access/-z noindirect-extern-access to control
+  canonical function pointers and copy relocation.
+
 * Add --max-cache-size=SIZE to set the the maximum cache size to SIZE
   bytes.
 
index 30f3d1cdee5c836f13ed6e8034083b01c96e61f8..cb855a65689a79a6ed8f4de653edcf6f2aeaccf5 100644 (file)
@@ -1,11 +1,21 @@
 PARSE_AND_LIST_OPTIONS_NOEXTEN_PROTECTED_DATA='
   fprintf (file, _("\
   -z noextern-protected-data  Do not treat protected data symbol as external\n"));
+  fprintf (file, _("\
+  -z indirect-extern-access   Enable indirect external access\n"));
+  fprintf (file, _("\
+  -z noindirect-extern-access Disable indirect external access (default)\n"));
 '
 
+# Set link_info.indirect_extern_access to 2 to indicate that it is set
+# by "-z indirect-extern-access".
 PARSE_AND_LIST_ARGS_CASE_Z_NOEXTEN_PROTECTED_DATA='
       else if (strcmp (optarg, "noextern-protected-data") == 0)
        link_info.extern_protected_data = false;
+      else if (strcmp (optarg, "indirect-extern-access") == 0)
+       link_info.indirect_extern_access = 2;
+      else if (strcmp (optarg, "noindirect-extern-access") == 0)
+       link_info.indirect_extern_access = 0;
 '
 
 
index 67c50839b37b075d139dbb3d1d03331e4291eba9..b6d8dccea0bc18f8ff44d83fdb7a3ef4bd18821b 100644 (file)
@@ -1293,6 +1293,18 @@ Generate GNU_PROPERTY_X86_FEATURE_1_IBT in .note.gnu.property section
 to indicate compatibility with IBT.  This also implies @option{ibtplt}.
 Supported for Linux/i386 and Linux/x86_64.
 
+@item indirect-extern-access
+@itemx noindirect-extern-access
+Generate GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS in
+.note.gnu.property section to indicate that object file requires
+canonical function pointers and cannot be used with copy relocation.
+This option also implies @option{noextern-protected-data} and
+@option{nocopyreloc}.  Supported for i386 and x86-64.
+
+@option{noindirect-extern-access} removes
+GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS from .note.gnu.property
+section.
+
 @item initfirst
 This option is only meaningful when building a shared object.
 It marks the object so that its runtime initialization will occur
index e4c67740e376ee228d90eea3423b07afedaeaedb..02029237e1ab0afc5b308f19beef3665a5f03ebf 100644 (file)
@@ -347,6 +347,7 @@ main (int argc, char **argv)
   link_info.relax_pass = 1;
   link_info.extern_protected_data = -1;
   link_info.dynamic_undefined_weak = -1;
+  link_info.indirect_extern_access = -1;
   link_info.pei386_auto_import = -1;
   link_info.spare_dynamic_tags = 5;
   link_info.path_separator = ':';
diff --git a/ld/testsuite/ld-elf/indirect-extern-access-1.rd b/ld/testsuite/ld-elf/indirect-extern-access-1.rd
new file mode 100644 (file)
index 0000000..39dc89a
--- /dev/null
@@ -0,0 +1,8 @@
+#...
+[a-f0-9]+ +[0-9a-f]+ +R_.*_COPY +[a-f0-9]+ +indirect_extern_access( \+ 0|)
+#...
+Displaying notes found in: .note.gnu.property
+[      ]+Owner[        ]+Data size[    ]+Description
+  GNU                  0x[0-9a-f]+     NT_GNU_PROPERTY_TYPE_0
+      Properties: 1_needed: 
+#pass
diff --git a/ld/testsuite/ld-elf/indirect-extern-access-1a.c b/ld/testsuite/ld-elf/indirect-extern-access-1a.c
new file mode 100644 (file)
index 0000000..4789810
--- /dev/null
@@ -0,0 +1 @@
+int indirect_extern_access = 1;
diff --git a/ld/testsuite/ld-elf/indirect-extern-access-1b.c b/ld/testsuite/ld-elf/indirect-extern-access-1b.c
new file mode 100644 (file)
index 0000000..68adae5
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern int indirect_extern_access;
+
+int
+main (void)
+{
+  if (indirect_extern_access == 1)
+    puts ("PASS");
+
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/indirect-extern-access-2.rd b/ld/testsuite/ld-elf/indirect-extern-access-2.rd
new file mode 100644 (file)
index 0000000..9c7d72f
--- /dev/null
@@ -0,0 +1,8 @@
+#...
+[a-f0-9]+ +[0-9a-f]+ +R_.*_JUMP_SLO(T|) +[a-f0-9]+ +indirect_extern_access( \+ 0|)
+#...
+Displaying notes found in: .note.gnu.property
+[      ]+Owner[        ]+Data size[    ]+Description
+  GNU                  0x[0-9a-f]+     NT_GNU_PROPERTY_TYPE_0
+      Properties: 1_needed: 
+#pass
diff --git a/ld/testsuite/ld-elf/indirect-extern-access-2a.c b/ld/testsuite/ld-elf/indirect-extern-access-2a.c
new file mode 100644 (file)
index 0000000..cb57068
--- /dev/null
@@ -0,0 +1,10 @@
+void
+indirect_extern_access (void)
+{
+}
+
+void *
+indirect_extern_access_p (void)
+{
+  return indirect_extern_access;
+}
diff --git a/ld/testsuite/ld-elf/indirect-extern-access-2b.c b/ld/testsuite/ld-elf/indirect-extern-access-2b.c
new file mode 100644 (file)
index 0000000..dedfd9b
--- /dev/null
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+extern void indirect_extern_access (void);
+extern void *indirect_extern_access_p (void);
+
+int
+main (void)
+{
+  if (&indirect_extern_access == indirect_extern_access_p ())
+    puts ("PASS");
+
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/indirect-extern-access-3.rd b/ld/testsuite/ld-elf/indirect-extern-access-3.rd
new file mode 100644 (file)
index 0000000..ce777a5
--- /dev/null
@@ -0,0 +1,8 @@
+#...
+[a-f0-9]+ +[0-9a-f]+ +R_.*_GLOB_DAT +[a-f0-9]+ +indirect_extern_access( \+ 0|)
+#...
+Displaying notes found in: .note.gnu.property
+[      ]+Owner[        ]+Data size[    ]+Description
+  GNU                  0x[0-9a-f]+     NT_GNU_PROPERTY_TYPE_0
+      Properties: 1_needed: indirect external access
+#pass
diff --git a/ld/testsuite/ld-elf/indirect-extern-access.S b/ld/testsuite/ld-elf/indirect-extern-access.S
new file mode 100644 (file)
index 0000000..25b88ba
--- /dev/null
@@ -0,0 +1,20 @@
+# ifdef __LP64__
+#  define ALIGN 3
+# else
+#  define ALIGN 2
+# endif
+       .section ".note.gnu.property", "a"
+       .p2align ALIGN
+       .long 1f - 0f           /* name length */
+       .long 5f - 2f           /* data length */
+       .long 5                 /* note type */
+0:     .asciz "GNU"            /* vendor name */
+1:
+       .p2align ALIGN
+2:     .long 0xb0008000        /* pr_type.  */
+       .long 4f - 3f           /* pr_datasz.  */
+3:
+       .long 0x1
+4:
+       .p2align ALIGN
+5:
index 7e3a0b7d84a407a3b94562a1606ed3a36e4ac948..819237415e6404c8ee8034ab5b88b008342118af 100644 (file)
@@ -73,6 +73,103 @@ run_ld_link_tests [list \
     ] \
 ]
 
+run_cc_link_tests [list \
+    [list \
+       "Build indirect-extern-access-1.so" \
+       "-shared" \
+       "-fPIC" \
+       { indirect-extern-access-1a.c } \
+       {} \
+       "indirect-extern-access-1.so" \
+    ] \
+    [list \
+       "Build indirect-extern-access-1a without PIE" \
+       "$NOPIE_LDFLAGS -Wl,--no-as-needed  \
+        tmpdir/indirect-extern-access-1.so" \
+       "$NOPIE_CFLAGS" \
+       { indirect-extern-access.S indirect-extern-access-1b.c } \
+       {{readelf -rn indirect-extern-access-1.rd}} \
+       "indirect-extern-access-1a" \
+    ] \
+    [list \
+       "Build indirect-extern-access-2.so" \
+       "-shared" \
+       "-fPIC" \
+       { indirect-extern-access-2a.c } \
+       {} \
+       "indirect-extern-access-2.so" \
+    ] \
+    [list \
+       "Build indirect-extern-access-2a without PIE" \
+       "$NOPIE_LDFLAGS -Wl,--no-as-needed  \
+        tmpdir/indirect-extern-access-2.so" \
+       "$NOPIE_CFLAGS" \
+       { indirect-extern-access.S indirect-extern-access-1b.c } \
+       {{readelf -rn indirect-extern-access-2.rd}} \
+       "indirect-extern-access-2a" \
+    ] \
+    [list \
+       "Build indirect-extern-access-2b with PIE" \
+       "-pie -Wl,--no-as-needed  \
+        tmpdir/indirect-extern-access-2.so" \
+       "-fpie" \
+       { indirect-extern-access.S indirect-extern-access-2b.c } \
+       {{readelf -rn indirect-extern-access-3.rd}} \
+       "indirect-extern-access-2b" \
+    ] \
+]
+
+run_ld_link_exec_tests [list \
+    [list \
+       "Run indirect-extern-access-1a without PIE" \
+       "$NOPIE_LDFLAGS" \
+       "" \
+       { indirect-extern-access.S indirect-extern-access-1b.c } \
+       "indirect-extern-access-1a" \
+       "pass.out" \
+       "$NOPIE_CFLAGS" \
+       "" \
+       "" \
+       "tmpdir/indirect-extern-access-1.so" \
+    ] \
+    [list \
+       "Run indirect-extern-access-1b with PIE" \
+       "-pie" \
+       "" \
+       { indirect-extern-access.S indirect-extern-access-1b.c } \
+       "indirect-extern-access-1b" \
+       "pass.out" \
+       "-fpie" \
+       "" \
+       "" \
+       "tmpdir/indirect-extern-access-1.so" \
+    ] \
+    [list \
+       "Run indirect-extern-access-2a without PIE" \
+       "$NOPIE_LDFLAGS" \
+       "" \
+       { indirect-extern-access.S indirect-extern-access-2b.c } \
+       "indirect-extern-access-2a" \
+       "pass.out" \
+       "$NOPIE_CFLAGS" \
+       "" \
+       "" \
+       "tmpdir/indirect-extern-access-2.so" \
+    ] \
+    [list \
+       "Run indirect-extern-access-2b with PIE" \
+       "-pie" \
+       "" \
+       { indirect-extern-access.S indirect-extern-access-2b.c } \
+       "indirect-extern-access-2b" \
+       "pass.out" \
+       "-fpie" \
+       "" \
+       "" \
+       "tmpdir/indirect-extern-access-2.so" \
+    ] \
+]
+
 proc elfedit_test { options test output } {
     global ELFEDIT
     global READELF
diff --git a/ld/testsuite/ld-elf/property-1_needed-1b.d b/ld/testsuite/ld-elf/property-1_needed-1b.d
new file mode 100644 (file)
index 0000000..b7a9eea
--- /dev/null
@@ -0,0 +1,16 @@
+#source: empty.s
+#as:
+#ld: -shared -z indirect-extern-access
+#readelf: -n
+#xfail: ![check_shared_lib_support]
+#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-*
+# Assembly source file for the HPPA assembler is renamed and modifed by
+# sed.  mn10300 has relocations in .note.gnu.property section which
+# elf_parse_notes doesn't support.
+
+#...
+Displaying notes found in: .note.gnu.property
+[      ]+Owner[        ]+Data size[    ]+Description
+  GNU                  0x[0-9a-f]+     NT_GNU_PROPERTY_TYPE_0
+      Properties: 1_needed: indirect external access
+#pass
diff --git a/ld/testsuite/ld-elf/property-1_needed-1c.d b/ld/testsuite/ld-elf/property-1_needed-1c.d
new file mode 100644 (file)
index 0000000..21e1d26
--- /dev/null
@@ -0,0 +1,17 @@
+#source: empty.s
+#source: property-1_needed-1.s
+#as:
+#ld: -shared -z noindirect-extern-access
+#readelf: -n
+#xfail: ![check_shared_lib_support]
+#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-*
+# Assembly source file for the HPPA assembler is renamed and modifed by
+# sed.  mn10300 has relocations in .note.gnu.property section which
+# elf_parse_notes doesn't support.
+
+#...
+Displaying notes found in: .note.gnu.property
+[      ]+Owner[        ]+Data size[    ]+Description
+  GNU                  0x[0-9a-f]+     NT_GNU_PROPERTY_TYPE_0
+      Properties: 1_needed: <unknown: 2>
+#pass
diff --git a/ld/testsuite/ld-x86-64/indirect-extern-access.rd b/ld/testsuite/ld-x86-64/indirect-extern-access.rd
new file mode 100644 (file)
index 0000000..696b06f
--- /dev/null
@@ -0,0 +1,6 @@
+#...
+Displaying notes found in: .note.gnu.property
+[      ]+Owner[        ]+Data size[    ]+Description
+  GNU                  0x[0-9a-f]+     NT_GNU_PROPERTY_TYPE_0
+      Properties: 1_needed: indirect external access
+#pass
diff --git a/ld/testsuite/ld-x86-64/protected-data-1.h b/ld/testsuite/ld-x86-64/protected-data-1.h
new file mode 100644 (file)
index 0000000..a80c976
--- /dev/null
@@ -0,0 +1,11 @@
+extern int protected_data_1a;
+extern int protected_data_1b;
+
+extern int *protected_data_1a_p ();
+extern int *protected_data_1b_p ();
+
+extern void set_protected_data_1a (int);
+extern void set_protected_data_1b (int);
+
+extern int check_protected_data_1a (int);
+extern int check_protected_data_1b (int);
diff --git a/ld/testsuite/ld-x86-64/protected-data-1a.c b/ld/testsuite/ld-x86-64/protected-data-1a.c
new file mode 100644 (file)
index 0000000..6942426
--- /dev/null
@@ -0,0 +1,40 @@
+#include "protected-data-1.h"
+
+int protected_data_1a __attribute__ ((visibility("protected"))) = 1;
+int protected_data_1b __attribute__ ((visibility("protected"))) = 2;
+
+int *
+protected_data_1a_p (void)
+{
+  return &protected_data_1a;
+}
+
+int *
+protected_data_1b_p (void)
+{
+  return &protected_data_1b;
+}
+
+void
+set_protected_data_1a (int i)
+{
+  protected_data_1a = i;
+}
+
+void
+set_protected_data_1b (int i)
+{
+  protected_data_1b = i;
+}
+
+int
+check_protected_data_1a (int i)
+{
+  return protected_data_1a == i ? 0 : 1;
+}
+
+int
+check_protected_data_1b (int i)
+{
+  return protected_data_1b == i ? 0 : 1;
+}
diff --git a/ld/testsuite/ld-x86-64/protected-data-1b.c b/ld/testsuite/ld-x86-64/protected-data-1b.c
new file mode 100644 (file)
index 0000000..a4756ee
--- /dev/null
@@ -0,0 +1,59 @@
+#include <stdio.h>
+
+#include "protected-data-1.h"
+
+int protected_data_1b = 3;
+
+int
+main (void)
+{
+  int res = 0;
+
+  /* Check if we get the same address for the protected data symbol.  */
+  if (&protected_data_1a != protected_data_1a_p ())
+    {
+      puts ("'protected_data_1a' in main and shared library doesn't have same address");
+      res = 1;
+    }
+
+  protected_data_1a = -1;
+  if (check_protected_data_1a (-1))
+    {
+      puts ("'protected_data_1a' in main and shared library doesn't have same value");
+      res = 1;
+    }
+
+  set_protected_data_1a (-3);
+  if (protected_data_1a != -3)
+    {
+      puts ("'protected_data_1a' in main and shared library doesn't have same value");
+      res = 1;
+    }
+
+  /* Check if we get the different addresses for the protected data
+     symbol.  */
+  if (&protected_data_1b == protected_data_1b_p ())
+    {
+      puts ("'protected_data_1b' in main and shared library has same address");
+      res = 1;
+    }
+
+  protected_data_1b = -10;
+  if (check_protected_data_1b (2))
+    {
+      puts ("'protected_data_1b' in main and shared library has same address");
+      res = 1;
+    }
+
+  set_protected_data_1b (-30);
+  if (protected_data_1b != -10)
+    {
+      puts ("'protected_data_1b' in main and shared library has same address");
+      res = 1;
+    }
+
+  if (!res)
+    puts ("PASS");
+
+  return res;
+}
diff --git a/ld/testsuite/ld-x86-64/protected-data-2a.S b/ld/testsuite/ld-x86-64/protected-data-2a.S
new file mode 100644 (file)
index 0000000..865c1af
--- /dev/null
@@ -0,0 +1,109 @@
+       .text
+       .p2align 4
+       .protected      protected_data_1a
+       .globl  protected_data_1a_p
+       .type   protected_data_1a_p, @function
+protected_data_1a_p:
+.LFB0:
+       .cfi_startproc
+       leaq    protected_data_1a(%rip), %rax
+       ret
+       .cfi_endproc
+.LFE0:
+       .size   protected_data_1a_p, .-protected_data_1a_p
+       .p2align 4
+       .protected      protected_data_1b
+       .globl  protected_data_1b_p
+       .type   protected_data_1b_p, @function
+protected_data_1b_p:
+.LFB1:
+       .cfi_startproc
+       leaq    protected_data_1b(%rip), %rax
+       ret
+       .cfi_endproc
+.LFE1:
+       .size   protected_data_1b_p, .-protected_data_1b_p
+       .p2align 4
+       .globl  set_protected_data_1a
+       .type   set_protected_data_1a, @function
+set_protected_data_1a:
+.LFB2:
+       .cfi_startproc
+       movl    %edi, protected_data_1a(%rip)
+       ret
+       .cfi_endproc
+.LFE2:
+       .size   set_protected_data_1a, .-set_protected_data_1a
+       .p2align 4
+       .globl  set_protected_data_1b
+       .type   set_protected_data_1b, @function
+set_protected_data_1b:
+.LFB3:
+       .cfi_startproc
+       movl    %edi, protected_data_1b(%rip)
+       ret
+       .cfi_endproc
+.LFE3:
+       .size   set_protected_data_1b, .-set_protected_data_1b
+       .p2align 4
+       .globl  check_protected_data_1a
+       .type   check_protected_data_1a, @function
+check_protected_data_1a:
+.LFB4:
+       .cfi_startproc
+       xorl    %eax, %eax
+       cmpl    %edi, protected_data_1a(%rip)
+       setne   %al
+       ret
+       .cfi_endproc
+.LFE4:
+       .size   check_protected_data_1a, .-check_protected_data_1a
+       .p2align 4
+       .globl  check_protected_data_1b
+       .type   check_protected_data_1b, @function
+check_protected_data_1b:
+.LFB5:
+       .cfi_startproc
+       xorl    %eax, %eax
+       cmpl    %edi, protected_data_1b(%rip)
+       setne   %al
+       ret
+       .cfi_endproc
+.LFE5:
+       .size   check_protected_data_1b, .-check_protected_data_1b
+       .globl  protected_data_1b
+       .data
+       .align 4
+       .type   protected_data_1b, @object
+       .size   protected_data_1b, 4
+protected_data_1b:
+       .long   2
+       .globl  protected_data_1a
+       .align 4
+       .type   protected_data_1a, @object
+       .size   protected_data_1a, 4
+protected_data_1a:
+       .long   1
+       .section        .note.GNU-stack,"",@progbits
+#ifdef USE_GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS
+# ifdef __LP64__
+#  define ALIGN 3
+# else
+#  define ALIGN 2
+# endif
+       .section ".note.gnu.property", "a"
+       .p2align ALIGN
+       .long 1f - 0f           /* name length */
+       .long 5f - 2f           /* data length */
+       .long 5                 /* note type */
+0:     .asciz "GNU"            /* vendor name */
+1:
+       .p2align ALIGN
+2:     .long 0xb0008000        /* pr_type.  */
+       .long 4f - 3f           /* pr_datasz.  */
+3:
+       .long 0x1
+4:
+       .p2align ALIGN
+5:
+#endif
diff --git a/ld/testsuite/ld-x86-64/protected-data-2b.S b/ld/testsuite/ld-x86-64/protected-data-2b.S
new file mode 100644 (file)
index 0000000..da89561
--- /dev/null
@@ -0,0 +1,119 @@
+       .section        .rodata.str1.8,"aMS",@progbits,1
+       .align 8
+.LC0:
+       .string "'protected_data_1a' in main and shared library doesn't have same address"
+       .align 8
+.LC1:
+       .string "'protected_data_1a' in main and shared library doesn't have same value"
+       .align 8
+.LC2:
+       .string "'protected_data_1b' in main and shared library has same address"
+       .section        .rodata.str1.1,"aMS",@progbits,1
+.LC3:
+       .string "PASS"
+       .section        .text.startup,"ax",@progbits
+       .p2align 4,,15
+       .globl  main
+       .type   main, @function
+main:
+.LFB11:
+       .cfi_startproc
+       pushq   %rbp
+       .cfi_def_cfa_offset 16
+       .cfi_offset 6, -16
+       xorl    %eax, %eax
+       pushq   %rbx
+       .cfi_def_cfa_offset 24
+       .cfi_offset 3, -24
+       xorl    %ebx, %ebx
+       subq    $8, %rsp
+       .cfi_def_cfa_offset 32
+       call    protected_data_1a_p
+       movq    protected_data_1a@GOTPCREL(%rip), %rbp
+       cmpq    %rbp, %rax
+       je      .L2
+       leaq    .LC0(%rip), %rdi
+       movb    $1, %bl
+       call    puts
+.L2:
+       movl    $-1, %edi
+       movl    $-1, 0(%rbp)
+       call    check_protected_data_1a
+       testl   %eax, %eax
+       jne     .L17
+.L3:
+       movl    $-3, %edi
+       call    set_protected_data_1a
+       cmpl    $-3, 0(%rbp)
+       je      .L4
+       leaq    .LC1(%rip), %rdi
+       movl    $1, %ebx
+       call    puts
+.L4:
+       xorl    %eax, %eax
+       call    protected_data_1b_p
+       leaq    protected_data_1b(%rip), %rdx
+       cmpq    %rdx, %rax
+       je      .L18
+.L5:
+       movl    $2, %edi
+       movl    $-10, protected_data_1b(%rip)
+       call    check_protected_data_1b
+       testl   %eax, %eax
+       jne     .L19
+       movl    $-30, %edi
+       call    set_protected_data_1b
+       cmpl    $-10, protected_data_1b(%rip)
+       je      .L9
+.L7:
+       leaq    .LC2(%rip), %rdi
+       movl    $1, %ebx
+       call    puts
+.L8:
+       addq    $8, %rsp
+       .cfi_remember_state
+       .cfi_def_cfa_offset 24
+       movl    %ebx, %eax
+       popq    %rbx
+       .cfi_def_cfa_offset 16
+       popq    %rbp
+       .cfi_def_cfa_offset 8
+       ret
+.L9:
+       .cfi_restore_state
+       testl   %ebx, %ebx
+       jne     .L11
+       leaq    .LC3(%rip), %rdi
+       call    puts
+       jmp     .L8
+.L19:
+       leaq    .LC2(%rip), %rdi
+       call    puts
+       movl    $-30, %edi
+       call    set_protected_data_1b
+       cmpl    $-10, protected_data_1b(%rip)
+       jne     .L7
+.L11:
+       movl    $1, %ebx
+       jmp     .L8
+.L17:
+       leaq    .LC1(%rip), %rdi
+       movl    $1, %ebx
+       call    puts
+       jmp     .L3
+.L18:
+       leaq    .LC2(%rip), %rdi
+       movl    $1, %ebx
+       call    puts
+       jmp     .L5
+       .cfi_endproc
+.LFE11:
+       .size   main, .-main
+       .globl  protected_data_1b
+       .data
+       .align 4
+       .type   protected_data_1b, @object
+       .size   protected_data_1b, 4
+protected_data_1b:
+       .long   3
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/protected-func-2a.S b/ld/testsuite/ld-x86-64/protected-func-2a.S
new file mode 100644 (file)
index 0000000..35c9cd1
--- /dev/null
@@ -0,0 +1,68 @@
+       .text
+       .p2align 4
+       .protected      protected_func_1a
+       .globl  protected_func_1a
+       .type   protected_func_1a, @function
+protected_func_1a:
+.LFB0:
+       .cfi_startproc
+       movl    $1, %eax
+       ret
+       .cfi_endproc
+.LFE0:
+       .size   protected_func_1a, .-protected_func_1a
+       .p2align 4
+       .protected      protected_func_1b
+       .globl  protected_func_1b
+       .type   protected_func_1b, @function
+protected_func_1b:
+.LFB1:
+       .cfi_startproc
+       movl    $2, %eax
+       ret
+       .cfi_endproc
+.LFE1:
+       .size   protected_func_1b, .-protected_func_1b
+       .p2align 4
+       .globl  protected_func_1a_p
+       .type   protected_func_1a_p, @function
+protected_func_1a_p:
+.LFB2:
+       .cfi_startproc
+       leaq    protected_func_1a(%rip), %rax
+       ret
+       .cfi_endproc
+.LFE2:
+       .size   protected_func_1a_p, .-protected_func_1a_p
+       .p2align 4
+       .globl  protected_func_1b_p
+       .type   protected_func_1b_p, @function
+protected_func_1b_p:
+.LFB3:
+       .cfi_startproc
+       leaq    protected_func_1b(%rip), %rax
+       ret
+       .cfi_endproc
+.LFE3:
+       .size   protected_func_1b_p, .-protected_func_1b_p
+       .section        .note.GNU-stack,"",@progbits
+#ifdef __LP64__
+# define ALIGN 3
+#else
+# define ALIGN 2
+#endif
+       .section ".note.gnu.property", "a"
+       .p2align ALIGN
+       .long 1f - 0f           /* name length */
+       .long 5f - 2f           /* data length */
+       .long 5                 /* note type */
+0:     .asciz "GNU"            /* vendor name */
+1:
+       .p2align ALIGN
+2:     .long 0xb0008000        /* pr_type.  */
+       .long 4f - 3f           /* pr_datasz.  */
+3:
+       .long 0x1
+4:
+       .p2align ALIGN
+5:
diff --git a/ld/testsuite/ld-x86-64/protected-func-2b.S b/ld/testsuite/ld-x86-64/protected-func-2b.S
new file mode 100644 (file)
index 0000000..8fa4cbf
--- /dev/null
@@ -0,0 +1,83 @@
+       .text
+       .p2align 4
+       .globl  protected_func_1b
+       .type   protected_func_1b, @function
+protected_func_1b:
+.LFB11:
+       .cfi_startproc
+       movl    $3, %eax
+       ret
+       .cfi_endproc
+.LFE11:
+       .size   protected_func_1b, .-protected_func_1b
+       .section        .rodata.str1.8,"aMS",@progbits,1
+       .align 8
+.LC0:
+       .string "'protected_func_1a' in main and shared library doesn't have same address"
+       .align 8
+.LC1:
+       .string "'protected_func_1a' doesn't return the correct value"
+       .align 8
+.LC2:
+       .string "'protected_func_1b' in main and shared library has same address"
+       .section        .rodata.str1.1,"aMS",@progbits,1
+.LC3:
+       .string "PASS"
+       .section        .text.startup,"ax",@progbits
+       .p2align 4
+       .globl  main
+       .type   main, @function
+main:
+.LFB12:
+       .cfi_startproc
+       pushq   %r12
+       .cfi_def_cfa_offset 16
+       .cfi_offset 12, -16
+       xorl    %r12d, %r12d
+       call    protected_func_1a_p
+       cmpq    protected_func_1a@GOTPCREL(%rip), %rax
+       je      .L4
+       leaq    .LC0(%rip), %rdi
+       movl    $1, %r12d
+       call    puts
+.L4:
+       call    protected_func_1a
+       cmpl    $1, %eax
+       jne     .L13
+       call    protected_func_1b_p
+       leaq    protected_func_1b(%rip), %rdx
+       cmpq    %rax, %rdx
+       je      .L6
+       testl   %r12d, %r12d
+       jne     .L12
+       leaq    .LC3(%rip), %rdi
+       call    puts
+       movl    %r12d, %eax
+       popq    %r12
+       .cfi_remember_state
+       .cfi_def_cfa_offset 8
+       ret
+.L13:
+       .cfi_restore_state
+       leaq    .LC1(%rip), %rdi
+       call    puts
+       call    protected_func_1b_p
+       leaq    protected_func_1b(%rip), %rdx
+       cmpq    %rax, %rdx
+       je      .L6
+.L12:
+       movl    $1, %r12d
+       movl    %r12d, %eax
+       popq    %r12
+       .cfi_remember_state
+       .cfi_def_cfa_offset 8
+       ret
+.L6:
+       .cfi_restore_state
+       leaq    .LC2(%rip), %rdi
+       call    puts
+       jmp     .L12
+       .cfi_endproc
+.LFE12:
+       .size   main, .-main
+       .section        .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/protected-func-2c.c b/ld/testsuite/ld-x86-64/protected-func-2c.c
new file mode 100644 (file)
index 0000000..c5ec1ec
--- /dev/null
@@ -0,0 +1,29 @@
+#include "protected-func-1.h"
+
+protected_func_type protected_func_1a_ptr = protected_func_1a;
+
+__attribute__ ((visibility("protected")))
+int
+protected_func_1a (void)
+{
+  return 1;
+}
+
+__attribute__ ((visibility("protected")))
+int
+protected_func_1b (void)
+{
+  return 2;
+}
+
+protected_func_type
+protected_func_1a_p (void)
+{
+  return protected_func_1a;
+}
+
+protected_func_type
+protected_func_1b_p (void)
+{
+  return protected_func_1b;
+}
index 3bf62504cf963b8e3a9f04cfcd87f842cb8db10f..a80f22c2453e955f5f9ee6b106c39411a2c71249 100644 (file)
@@ -1334,6 +1334,63 @@ if { [isnative] && [check_compiler_available] } {
            {} \
            "libprotected-func-1.so" \
        ] \
+       [list \
+           "Build libprotected-func-2a.so" \
+           "-shared" \
+           "-fPIC -Wa,-mx86-used-note=yes" \
+           { protected-func-2a.S } \
+           {{readelf -n indirect-extern-access.rd}}  \
+           "libprotected-func-2a.so" \
+       ] \
+       [list \
+           "Build libprotected-func-2b.so" \
+           "-shared -z indirect-extern-access" \
+           "-fPIC -Wa,-mx86-used-note=yes" \
+           { protected-func-2c.c } \
+           {{readelf -n indirect-extern-access.rd}}  \
+           "libprotected-func-2b.so" \
+       ] \
+       [list \
+           "Build libprotected-data-1a.so" \
+           "-shared -z noindirect-extern-access" \
+           "-fPIC -Wa,-mx86-used-note=yes" \
+           { protected-data-1a.c } \
+           {} \
+           "libprotected-data-1a.so" \
+       ] \
+       [list \
+           "Build libprotected-data-1b.so" \
+           "-shared -z indirect-extern-access" \
+           "-fPIC -Wa,-mx86-used-note=yes" \
+           { protected-data-1a.c } \
+           {} \
+           "libprotected-data-1b.so" \
+       ] \
+       [list \
+           "Build protected-data-1 without PIE" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-1b.so" \
+           "$NOPIE_CFLAGS -Wa,-mx86-used-note=yes" \
+           { protected-data-1b.c } \
+           {} \
+           "protected-data-1" \
+       ] \
+       [list \
+           "Build libprotected-data-2a.so" \
+           "-shared" \
+           "-fPIC -Wa,-mx86-used-note=yes \
+            -DUSE_GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS" \
+           { protected-data-2a.S } \
+           {{readelf -n indirect-extern-access.rd}}  \
+           "libprotected-data-2a.so" \
+       ] \
+       [list \
+           "Build libprotected-data-2b.so" \
+           "-shared -z indirect-extern-access" \
+           "-fPIC -Wa,-mx86-used-note=yes" \
+           { protected-data-2a.S } \
+           {{readelf -n indirect-extern-access.rd}}  \
+           "libprotected-data-2b.so" \
+       ] \
     ]
 
     if  {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -1761,6 +1818,96 @@ if { [isnative] && [check_compiler_available] } {
            "pass.out" \
            "-fPIE" \
        ] \
+       [list \
+           "Run protected-func-2a without PIE" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-func-2a.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-func-2b.S } \
+           "protected-func-2a" \
+           "pass.out" \
+           "$NOPIE_CFLAGS" \
+       ] \
+       [list \
+           "Run protected-func-2b with PIE" \
+           "-Wl,--no-as-needed -pie tmpdir/libprotected-func-2a.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-func-2b.S } \
+           "protected-func-2b" \
+           "pass.out" \
+           "-fPIE" \
+       ] \
+       [list \
+           "Run protected-func-2c without PIE" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-func-2b.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-func-2b.S } \
+           "protected-func-2c" \
+           "pass.out" \
+           "$NOPIE_CFLAGS" \
+       ] \
+       [list \
+           "Run protected-func-2d with PIE" \
+           "-Wl,--no-as-needed -pie tmpdir/libprotected-func-2b.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-func-2b.S } \
+           "protected-func-2d" \
+           "pass.out" \
+           "-fPIE" \
+       ] \
+       [list \
+           "Run protected-data-1a without PIE" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-1a.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-data-1b.c } \
+           "protected-data-1a" \
+           "pass.out" \
+           "$NOPIE_CFLAGS" \
+       ] \
+       [list \
+           "Run protected-data-1b with PIE" \
+           "-Wl,--no-as-needed -pie tmpdir/libprotected-data-1a.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-data-1b.c } \
+           "protected-data-1b" \
+           "pass.out" \
+           "-fPIE" \
+       ] \
+       [list \
+           "Run protected-data-2a without PIE" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-2a.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-data-2b.S } \
+           "protected-data-2a" \
+           "pass.out" \
+           "$NOPIE_CFLAGS" \
+       ] \
+       [list \
+           "Run protected-data-2b with PIE" \
+           "-Wl,--no-as-needed -pie tmpdir/libprotected-data-2a.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-data-2b.S } \
+           "protected-data-2b" \
+           "pass.out" \
+           "-fPIE" \
+       ] \
+       [list \
+           "Run protected-data-2c without PIE" \
+           "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-2b.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-data-2b.S } \
+           "protected-data-2c" \
+           "pass.out" \
+           "$NOPIE_CFLAGS" \
+       ] \
+       [list \
+           "Run protected-data-2d with PIE" \
+           "-Wl,--no-as-needed -pie tmpdir/libprotected-data-2b.so" \
+           "-Wa,-mx86-used-note=yes" \
+           { protected-data-2b.S } \
+           "protected-data-2d" \
+           "pass.out" \
+           "-fPIE" \
+       ] \
     ]
 
     # Run-time tests which require working ifunc attribute support.