[PATCH 2/2] elf: Add GNU_PROPERTY_1_NEEDED check

H.J. Lu hjl.tools@gmail.com
Sun Jun 20 22:50:29 GMT 2021


If GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION is set on any input
relocatable files:

1. Don't generate copy relocations.
2. Turn off extern_protected_data.
3. Treate reference to protected symbols with single global definition
as local.
4. Set GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION on output.
5. Add -z [no]single-global-definition to control single global definition.

bfd/

	* elf-properties.c (_bfd_elf_link_setup_gnu_properties): Handle
	GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION for
	-z single-global-definition.  Set nocopyreloc to true and
	extern_protected_data to false for single global definiton.
	* elflink.c (_bfd_elf_symbol_refs_local_p): Return true for
	STV_PROTECTED symbols with single global definition.

include/

	* bfdlink.h (bfd_link_info): Add single_global_definition.

ld/

	* NEWS: Mention -z [no]single-global-definition.
	* ld.texi: Document -z [no]single-global-definition.
	* ldmain.c (main): Initialize link_info.single_global_definition
	to -1.
	* lexsup.c (elf_shlib_list_options): Add
	-z [no]single-global-definition.
	* emultempl/elf.em (gld${EMULATION_NAME}_handle_optio): Handle
	-z [no]single-global-definition.
	* testsuite/ld-elf/property-1_needed-1b.d: New file.
	* testsuite/ld-elf/property-1_needed-1c.d: 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-x86-64/single-global-definition.rd: Likewise.
	* testsuite/ld-x86-64/x86-64.exp: Run tests for protected
	function and data with single global definition.
---
 bfd/elf-properties.c                          | 103 ++++++++++++--
 bfd/elflink.c                                 |   4 +
 include/bfdlink.h                             |   6 +
 ld/NEWS                                       |   3 +
 ld/emultempl/elf.em                           |   4 +
 ld/ld.texi                                    |  12 ++
 ld/ldmain.c                                   |   1 +
 ld/lexsup.c                                   |   5 +
 ld/testsuite/ld-elf/property-1_needed-1b.d    |  16 +++
 ld/testsuite/ld-elf/property-1_needed-1c.d    |  17 +++
 ld/testsuite/ld-x86-64/protected-data-1.h     |  11 ++
 ld/testsuite/ld-x86-64/protected-data-1a.c    |  40 ++++++
 ld/testsuite/ld-x86-64/protected-data-1b.c    |  59 ++++++++
 ld/testsuite/ld-x86-64/protected-data-2a.S    | 109 +++++++++++++++
 ld/testsuite/ld-x86-64/protected-data-2b.S    | 119 ++++++++++++++++
 ld/testsuite/ld-x86-64/protected-func-2a.S    |  68 +++++++++
 ld/testsuite/ld-x86-64/protected-func-2b.S    |  83 +++++++++++
 ld/testsuite/ld-x86-64/protected-func-2c.c    |  29 ++++
 .../ld-x86-64/single-global-definition.rd     |   6 +
 ld/testsuite/ld-x86-64/x86-64.exp             | 131 ++++++++++++++++++
 20 files changed, 811 insertions(+), 15 deletions(-)
 create mode 100644 ld/testsuite/ld-elf/property-1_needed-1b.d
 create mode 100644 ld/testsuite/ld-elf/property-1_needed-1c.d
 create mode 100644 ld/testsuite/ld-x86-64/protected-data-1.h
 create mode 100644 ld/testsuite/ld-x86-64/protected-data-1a.c
 create mode 100644 ld/testsuite/ld-x86-64/protected-data-1b.c
 create mode 100644 ld/testsuite/ld-x86-64/protected-data-2a.S
 create mode 100644 ld/testsuite/ld-x86-64/protected-data-2b.S
 create mode 100644 ld/testsuite/ld-x86-64/protected-func-2a.S
 create mode 100644 ld/testsuite/ld-x86-64/protected-func-2b.S
 create mode 100644 ld/testsuite/ld-x86-64/protected-func-2c.c
 create mode 100644 ld/testsuite/ld-x86-64/single-global-definition.rd

diff --git a/bfd/elf-properties.c b/bfd/elf-properties.c
index 56ee91d7786..50c20964006 100644
--- a/bfd/elf-properties.c
+++ b/bfd/elf-properties.c
@@ -598,7 +598,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 +606,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->single_global_definition > 0 && elf_bfd != NULL)
+    {
+      /* Support -z single-global-definition.  */
+      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_SINGLE_GLOBAL_DEFINITION;
+	  p->pr_kind = property_number;
+	}
+      else
+	p->u.number
+	  |= GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION;
+    }
+
   /* Do nothing if there is no .note.gnu.property section.  */
   if (!has_properties)
     return NULL;
@@ -695,7 +738,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,6 +779,29 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
       sec->size = size;
       contents = (bfd_byte *) bfd_zalloc (first_pbfd, size);
 
+      if (info->single_global_definition <= 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->single_global_definition < 0)
+		{
+		  /* Turn on single global definition based on input
+		     properties.  */
+		  if ((p->u.number
+		       & GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION)
+		      != 0)
+		    info->single_global_definition = 1;
+		}
+	      else
+		/* Turn off single global definition.  */
+		p->u.number
+		  &= ~GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION;
+	    }
+	}
+
       elf_write_gnu_properties (first_pbfd, contents, list, size,
 				align_size);
 
@@ -747,6 +812,14 @@ _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->single_global_definition > 0)
+	{
+	  /* For single global definition, don't generate copy
+	     relocations.  */
+	  info->nocopyreloc = true;
+	  info->extern_protected_data = false;
+	}
     }
 
   return first_pbfd;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 9a05208253c..21a77bf67bd 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -3331,6 +3331,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 single global definition are local. */
+  if (info->single_global_definition > 0)
+    return true;
+
   bed = get_elf_backend_data (hash_table->dynobj);
 
   /* If extern_protected_data is false, STV_PROTECTED non-function
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 7f1b12dbf37..815780091c5 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -639,6 +639,12 @@ struct bfd_link_info
      the backend decide.  */
   int dynamic_undefined_weak;
 
+  /* GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION control:
+       > 0: Turn on.
+         0: Turn off.
+       < 0: Turn on if it is set on any inputs.  */
+  int single_global_definition;
+
   /* Non-zero if auto-import thunks for DATA items in pei386 DLLs
      should be generated/linked against.  Set to 1 if this feature
      is explicitly requested by the user, -1 if enabled by default.  */
diff --git a/ld/NEWS b/ld/NEWS
index a5ed9058c04..aa74d4fd6a0 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Add -z single-global-definition/-z nosingle-global-definition to control
+  canonical function pointers and copy relocation.
+
 * arm-symbianelf support removed.
 
 * Add -z report-relative-reloc to x86 ELF linker to report dynamic
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index bfaf8130a3e..cdf5b26621a 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -848,6 +848,10 @@ fragment <<EOF
 	link_info.textrel_check = textrel_check_none;
       else if (strcmp (optarg, "textoff") == 0)
 	link_info.textrel_check = textrel_check_none;
+      else if (strcmp (optarg, "single-global-definition") == 0)
+	link_info.single_global_definition = 1;
+      else if (strcmp (optarg, "nosingle-global-definition") == 0)
+	link_info.single_global_definition = 0;
 EOF
 fi
 
diff --git a/ld/ld.texi b/ld/ld.texi
index dd8f571d4e4..b847e78ee7f 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1442,6 +1442,18 @@ Generate GNU_PROPERTY_X86_FEATURE_1_SHSTK in .note.gnu.property section
 to indicate compatibility with Intel Shadow Stack.  Supported for
 Linux/i386 and Linux/x86_64.
 
+@item single-global-definition
+@itemx nosingle-global-definition
+Generate GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION 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}.
+
+@option{nosingle-global-definition} removes
+GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION from .note.gnu.property
+section.
+
 @item stack-size=@var{value}
 Specify a stack size for an ELF @code{PT_GNU_STACK} segment.
 Specifying zero will override any default non-zero sized
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 42660eb9a3c..99a1b0cf5f3 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -346,6 +346,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.single_global_definition = -1;
   link_info.pei386_auto_import = -1;
   link_info.spare_dynamic_tags = 5;
   link_info.path_separator = ':';
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 00274c500d0..abfc3766c7c 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -2100,6 +2100,11 @@ elf_shlib_list_options (FILE *file)
       fprintf (file, _("\
   -z textoff                  Don't treat DT_TEXTREL in output as error\n"));
     }
+  fprintf (file, _("\
+  -z single-global-definition Enable single global definition\n"));
+  fprintf (file, _("\
+  -z nosingle-global-definition\n\
+                              Disable single global definition\n"));
 }
 
 static void
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
index 00000000000..2e2517f0d4f
--- /dev/null
+++ b/ld/testsuite/ld-elf/property-1_needed-1b.d
@@ -0,0 +1,16 @@
+#source: empty.s
+#as:
+#ld: -shared -z single-global-definition
+#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: single global definition
+#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
index 00000000000..d26bce62edd
--- /dev/null
+++ b/ld/testsuite/ld-elf/property-1_needed-1c.d
@@ -0,0 +1,17 @@
+#source: empty.s
+#source: property-1_needed-1.s
+#as:
+#ld: -shared -z nosingle-global-definition
+#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/protected-data-1.h b/ld/testsuite/ld-x86-64/protected-data-1.h
new file mode 100644
index 00000000000..a80c9769d37
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/protected-data-1.h
@@ -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
index 00000000000..6942426ecb3
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/protected-data-1a.c
@@ -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
index 00000000000..a4756ee08da
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/protected-data-1b.c
@@ -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
index 00000000000..dcc857c165d
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/protected-data-2a.S
@@ -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_SINGLE_GLOBAL_DEFINITION
+# 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
index 00000000000..da8956139fe
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/protected-data-2b.S
@@ -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
index 00000000000..35c9cd121bd
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/protected-func-2a.S
@@ -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
index 00000000000..8fa4cbf09d6
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/protected-func-2b.S
@@ -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
index 00000000000..c5ec1eca17e
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/protected-func-2c.c
@@ -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;
+}
diff --git a/ld/testsuite/ld-x86-64/single-global-definition.rd b/ld/testsuite/ld-x86-64/single-global-definition.rd
new file mode 100644
index 00000000000..139dca0d6c6
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/single-global-definition.rd
@@ -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: single global definition
+#pass
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index 3bf62504cf9..5fabbec6fa7 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1334,6 +1334,47 @@ 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 single-global-definition.rd}}  \
+	    "libprotected-func-2a.so" \
+	] \
+	[list \
+	    "Build libprotected-func-2b.so" \
+	    "-shared -z single-global-definition" \
+	    "-fPIC -Wa,-mx86-used-note=yes" \
+	    { protected-func-2c.c } \
+	    {{readelf -n single-global-definition.rd}}  \
+	    "libprotected-func-2b.so" \
+	] \
+	[list \
+	    "Build libprotected-data-1.so" \
+	    "-shared" \
+	    "-fPIC -Wa,-mx86-used-note=yes" \
+	    { protected-data-1a.c } \
+	    {} \
+	    "libprotected-data-1.so" \
+	] \
+	[list \
+	    "Build libprotected-data-2a.so" \
+	    "-shared" \
+	    "-fPIC -Wa,-mx86-used-note=yes \
+	     -DUSE_GNU_PROPERTY_1_NEEDED_SINGLE_GLOBAL_DEFINITION" \
+	    { protected-data-2a.S } \
+	    {{readelf -n single-global-definition.rd}}  \
+	    "libprotected-data-2a.so" \
+	] \
+	[list \
+	    "Build libprotected-data-2b.so" \
+	    "-shared -z single-global-definition" \
+	    "-fPIC -Wa,-mx86-used-note=yes" \
+	    { protected-data-2a.S } \
+	    {{readelf -n single-global-definition.rd}}  \
+	    "libprotected-data-2b.so" \
+	] \
     ]
 
     if  {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -1761,6 +1802,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-1 without PIE" \
+	    "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-1.so" \
+	    "-Wa,-mx86-used-note=yes" \
+	    { protected-data-1b.c } \
+	    "protected-data-1a" \
+	    "pass.out" \
+	    "$NOPIE_CFLAGS" \
+	] \
+	[list \
+	    "Run protected-data-1 with PIE" \
+	    "-Wl,--no-as-needed -pie tmpdir/libprotected-data-1.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.
-- 
2.31.1



More information about the Binutils mailing list