[binutils-gdb] RISC-V: Implment the merge logic for GNU_PROPERTY_RISCV_FEATURE_1_AND

Nelson Chu nelsonc1225@sourceware.org
Tue Jun 24 10:16:23 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=84eb7d284b3ae07ee894a1f21defc3c9669297b7

commit 84eb7d284b3ae07ee894a1f21defc3c9669297b7
Author: Kito Cheng <kito.cheng@sifive.com>
Date:   Wed Jun 11 16:33:48 2025 +0800

    RISC-V: Implment the merge logic for GNU_PROPERTY_RISCV_FEATURE_1_AND
    
    GNU_PROPERTY_RISCV_FEATURE_1_AND will perform a bitwise AND operation
    on the properties of the input files.

Diff:
---
 bfd/elfnn-riscv.c                                  |  35 +++++
 bfd/elfxx-riscv.c                                  | 171 +++++++++++++++++++++
 bfd/elfxx-riscv.h                                  |  13 ++
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp         |   6 +
 ld/testsuite/ld-riscv-elf/property-combine-and-1.d |   6 +
 ld/testsuite/ld-riscv-elf/property-combine-and-2.d |  11 ++
 ld/testsuite/ld-riscv-elf/property-combine-and-3.d |  11 ++
 .../ld-riscv-elf/property-zicfilp-unlabeled.d      |  10 ++
 .../ld-riscv-elf/property-zicfilp-unlabeled.s      |  21 +++
 ld/testsuite/ld-riscv-elf/property-zicfiss.d       |  10 ++
 ld/testsuite/ld-riscv-elf/property-zicfiss.s       |  21 +++
 ld/testsuite/ld-riscv-elf/property1.s              |  21 +++
 ld/testsuite/ld-riscv-elf/property2.s              |   5 +
 ld/testsuite/ld-riscv-elf/property3.s              |  21 +++
 ld/testsuite/ld-riscv-elf/property4.s              |  21 +++
 15 files changed, 383 insertions(+)

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 49f4e76a0d1..49e812ea99c 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -177,6 +177,8 @@ struct _bfd_riscv_elf_obj_tdata
   /* tls_type for each local got entry.  */
   char *local_got_tls_type;
 
+  /* All GNU_PROPERTY_RISCV_FEATURE_1_AND properties. */
+  uint32_t gnu_and_prop;
   /* PLT type.  */
   riscv_plt_type plt_type;
 };
@@ -5809,6 +5811,36 @@ riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
     h->other |= STO_RISCV_VARIANT_CC;
 }
 
+/* Implement elf_backend_setup_gnu_properties for RISC-V.  It serves as a
+   wrapper function for _bfd_riscv_elf_link_setup_gnu_properties to account
+   for the effect of GNU properties of the output_bfd.  */
+
+static bfd *
+elfNN_riscv_link_setup_gnu_properties (struct bfd_link_info *info)
+{
+  uint32_t and_prop = _bfd_riscv_elf_tdata (info->output_bfd)->gnu_and_prop;
+
+  bfd *pbfd = _bfd_riscv_elf_link_setup_gnu_properties (info, &and_prop);
+
+  _bfd_riscv_elf_tdata (info->output_bfd)->gnu_and_prop = and_prop;
+  return pbfd;
+}
+
+/* Implement elf_backend_merge_gnu_properties for RISC-V.  It serves as a
+   wrapper function for _bfd_riscv_elf_merge_gnu_properties to account
+   for the effect of GNU properties of the output_bfd.  */
+
+static bool
+elfNN_riscv_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd,
+				  bfd *bbfd ATTRIBUTE_UNUSED,
+				  elf_property *aprop, elf_property *bprop)
+{
+  uint32_t and_prop = _bfd_riscv_elf_tdata (info->output_bfd)->gnu_and_prop;
+
+  return _bfd_riscv_elf_merge_gnu_properties (info, abfd, aprop, bprop,
+					      and_prop);
+}
+
 #define TARGET_LITTLE_SYM			riscv_elfNN_vec
 #define TARGET_LITTLE_NAME			"elfNN-littleriscv"
 #define TARGET_BIG_SYM				riscv_elfNN_be_vec
@@ -5848,6 +5880,9 @@ riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
 
 #define elf_backend_init_index_section		_bfd_elf_init_1_index_section
 
+#define elf_backend_setup_gnu_properties	elfNN_riscv_link_setup_gnu_properties
+#define elf_backend_merge_gnu_properties	elfNN_riscv_merge_gnu_properties
+
 #define elf_backend_can_gc_sections		1
 #define elf_backend_can_refcount		1
 #define elf_backend_want_got_plt		1
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 0884bb7bf3d..936adcd7d6d 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -3366,3 +3366,174 @@ riscv_print_extensions (void)
     }
   printf ("\n");
 }
+
+/* Find the first input bfd with GNU property and merge it with GPROP.  If no
+   such input is found, add it to a new section at the last input.  Update
+   GPROP accordingly.  */
+
+bfd *
+_bfd_riscv_elf_link_setup_gnu_properties (struct bfd_link_info *info,
+					  uint32_t *and_prop_p)
+{
+  asection *sec;
+  bfd *pbfd;
+  bfd *ebfd = NULL;
+  elf_property *prop;
+
+  uint32_t and_prop = *and_prop_p;
+
+  /* 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 it is either an input with property note or the last
+     input.  Either way if we have and_prop, we should add it (by
+     creating a section if needed).  */
+  if (ebfd != NULL && (and_prop))
+    {
+      prop = _bfd_elf_get_property (ebfd, GNU_PROPERTY_RISCV_FEATURE_1_AND, 4);
+
+      prop->u.number |= and_prop;
+      prop->pr_kind = property_number;
+
+      /* pbfd being NULL implies ebfd is the last input.  Create the GNU
+	 property note section.  */
+      if (pbfd == NULL)
+	{
+	  sec
+	    = bfd_make_section_with_flags (ebfd, 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"));
+
+	  elf_section_type (sec) = SHT_NOTE;
+	}
+    }
+
+  pbfd = _bfd_elf_link_setup_gnu_properties (info);
+
+  if (bfd_link_relocatable (info))
+    return pbfd;
+
+  /* If pbfd has any GNU_PROPERTY_RISCV_FEATURE_1_AND properties, update
+  and_prop accordingly.  */
+  if (pbfd != NULL)
+    {
+      elf_property_list *p;
+      elf_property_list *plist = elf_properties (pbfd);
+
+      if ((p = _bfd_elf_find_property (plist, GNU_PROPERTY_RISCV_FEATURE_1_AND,
+				       NULL))
+	  != NULL)
+	and_prop = p->property.u.number
+		   & (GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
+		      | GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS);
+    }
+
+  *and_prop_p = and_prop;
+  return pbfd;
+}
+
+/* Define elf_backend_parse_gnu_properties for RISC-V.  */
+
+enum elf_property_kind
+_bfd_riscv_elf_parse_gnu_properties (bfd *abfd, unsigned int type,
+				     bfd_byte *ptr, unsigned int datasz)
+{
+  elf_property *prop;
+
+  switch (type)
+    {
+    case GNU_PROPERTY_RISCV_FEATURE_1_AND:
+      if (datasz != 4)
+	{
+	  _bfd_error_handler (_ (
+				"error: %pB: <corrupt RISC-V used size: 0x%x>"),
+			      abfd, datasz);
+	  return property_corrupt;
+	}
+      prop = _bfd_elf_get_property (abfd, type, datasz);
+      /* Combine properties of the same type.  */
+      prop->u.number |= bfd_h_get_32 (abfd, ptr);
+      prop->pr_kind = property_number;
+      break;
+
+    default:
+      return property_ignored;
+    }
+
+  return property_number;
+}
+
+/* Merge RISC-V GNU property BPROP with APROP also accounting for PROP.
+   If APROP isn't NULL, merge it with BPROP and/or PROP.  Vice-versa if BROP
+   isn't NULL.  Return TRUE if there is any update to APROP or if BPROP should
+   be merge with ABFD.  */
+
+bool
+_bfd_riscv_elf_merge_gnu_properties
+  (struct bfd_link_info *info ATTRIBUTE_UNUSED, bfd *abfd ATTRIBUTE_UNUSED,
+   elf_property *aprop, elf_property *bprop, uint32_t and_prop)
+{
+  unsigned int orig_number;
+  bool updated = false;
+  unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type;
+
+  switch (pr_type)
+    {
+      case GNU_PROPERTY_RISCV_FEATURE_1_AND: {
+	if (aprop != NULL && bprop != NULL)
+	  {
+	    orig_number = aprop->u.number;
+	    aprop->u.number = (orig_number & bprop->u.number) | and_prop;
+	    updated = orig_number != aprop->u.number;
+	    /* Remove the property if all feature bits are cleared.  */
+	    if (aprop->u.number == 0)
+	      aprop->pr_kind = property_remove;
+	    break;
+	  }
+	/* If either is NULL, the AND would be 0 so, if there is
+	   any PROP, asign it to the input that is not NULL.  */
+	if (and_prop)
+	  {
+	    if (aprop != NULL)
+	      {
+		orig_number = aprop->u.number;
+		aprop->u.number = and_prop;
+		updated = orig_number != aprop->u.number;
+	      }
+	    else if (bprop != NULL)
+	      {
+		bprop->u.number = and_prop;
+		updated = true;
+	      }
+	    /* Shouldn't happen because we checked one of APROP or BPROP !=
+	     * NULL. */
+	    else
+	      abort ();
+	  }
+	/* No PROP and BPROP is NULL, so remove APROP.  */
+	else if (!and_prop && bprop == NULL && aprop != NULL)
+	  {
+	    aprop->pr_kind = property_remove;
+	    updated = true;
+	  }
+      }
+      break;
+
+    default:
+      abort ();
+    }
+
+  return updated;
+}
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 6223281acb5..d8845afb666 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -133,3 +133,16 @@ extern void
 bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);
 extern void
 bfd_elf64_riscv_set_data_segment_info (struct bfd_link_info *, int *);
+
+extern bfd *
+_bfd_riscv_elf_link_setup_gnu_properties (struct bfd_link_info *, uint32_t *);
+
+extern enum elf_property_kind
+_bfd_riscv_elf_parse_gnu_properties (bfd *, unsigned int, bfd_byte *,
+				     unsigned int);
+
+extern bool
+_bfd_riscv_elf_merge_gnu_properties (struct bfd_link_info *, bfd *,
+				     elf_property *, elf_property *, uint32_t);
+
+#define elf_backend_parse_gnu_properties _bfd_riscv_elf_parse_gnu_properties
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 9cb847d3d8a..e03e44ae4a2 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -227,6 +227,12 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "data-reloc-rv64-addr32-pic"
     run_dump_test "data-reloc-rv64-undef32-pic"
 
+    run_dump_test "property-zicfilp-unlabeled"
+    run_dump_test "property-zicfiss"
+    run_dump_test "property-combine-and-1"
+    run_dump_test "property-combine-and-2"
+    run_dump_test "property-combine-and-3"
+
     # IFUNC testcases.
     # Check IFUNC by single type relocs.
     run_dump_test_ifunc "ifunc-reloc-call-01" rv32 exe
diff --git a/ld/testsuite/ld-riscv-elf/property-combine-and-1.d b/ld/testsuite/ld-riscv-elf/property-combine-and-1.d
new file mode 100644
index 00000000000..9f9cf83b792
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property-combine-and-1.d
@@ -0,0 +1,6 @@
+#name: RISC-V GNU Property (multiple inputs, combine section) - 1
+#source: property1.s
+#source: property2.s
+#as: -march=rv64g
+#ld: -shared
+#readelf: -n
diff --git a/ld/testsuite/ld-riscv-elf/property-combine-and-2.d b/ld/testsuite/ld-riscv-elf/property-combine-and-2.d
new file mode 100644
index 00000000000..25b864665c7
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property-combine-and-2.d
@@ -0,0 +1,11 @@
+#name: RISC-V GNU Property (multiple inputs, combine section) - 2
+#source: property1.s
+#source: property3.s
+#as: -march=rv64g
+#ld: -shared
+#readelf: -n
+
+Displaying notes found in: .note.gnu.property
+[ 	]+Owner[ 	]+Data size[ 	]+Description
+[ 	]+GNU[ 	]+0x00000010[ 	]+NT_GNU_PROPERTY_TYPE_0
+[ 	]+Properties: RISC-V AND feature: CFI_LP_UNLABELED
diff --git a/ld/testsuite/ld-riscv-elf/property-combine-and-3.d b/ld/testsuite/ld-riscv-elf/property-combine-and-3.d
new file mode 100644
index 00000000000..52882c6fcf5
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property-combine-and-3.d
@@ -0,0 +1,11 @@
+#name: RISC-V GNU Property (multiple inputs, combine section) - 3
+#source: property1.s
+#source: property4.s
+#as: -march=rv64g
+#ld: -shared
+#readelf: -n
+
+Displaying notes found in: .note.gnu.property
+[ 	]+Owner[ 	]+Data size[ 	]+Description
+[ 	]+GNU[ 	]+0x00000010[ 	]+NT_GNU_PROPERTY_TYPE_0
+[ 	]+Properties: RISC-V AND feature: CFI_SS
diff --git a/ld/testsuite/ld-riscv-elf/property-zicfilp-unlabeled.d b/ld/testsuite/ld-riscv-elf/property-zicfilp-unlabeled.d
new file mode 100644
index 00000000000..8aec50b5026
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property-zicfilp-unlabeled.d
@@ -0,0 +1,10 @@
+#name: GNU Property (single input, CFI_LP_UNLABELED)
+#source: property-zicfilp-unlabeled.s
+#as: -march=rv64g
+#ld: -shared
+#readelf: -n
+
+Displaying notes found in: .note.gnu.property
+[ 	]+Owner[ 	]+Data size[ 	]+Description
+[ 	]+GNU[ 	]+0x00000010[ 	]+NT_GNU_PROPERTY_TYPE_0
+[ 	]+Properties: RISC-V AND feature: CFI_LP_UNLABELED
diff --git a/ld/testsuite/ld-riscv-elf/property-zicfilp-unlabeled.s b/ld/testsuite/ld-riscv-elf/property-zicfilp-unlabeled.s
new file mode 100644
index 00000000000..b0192c06739
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property-zicfilp-unlabeled.s
@@ -0,0 +1,21 @@
+	.text
+	.globl _start
+	.type _start,@function
+_start:
+    ret
+
+	.section ".note.gnu.property", "a"
+	.p2align 3
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align 3
+2:	.long 0xc0000000	/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+	.long 0x1		/* GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED.  */
+4:
+	.p2align 3
+5:
diff --git a/ld/testsuite/ld-riscv-elf/property-zicfiss.d b/ld/testsuite/ld-riscv-elf/property-zicfiss.d
new file mode 100644
index 00000000000..8f2af00734a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property-zicfiss.d
@@ -0,0 +1,10 @@
+#name: GNU Property (single input, CFI_SS)
+#source: property-zicfiss.s
+#as: -march=rv64g
+#ld: -shared
+#readelf: -n
+
+Displaying notes found in: .note.gnu.property
+[ 	]+Owner[ 	]+Data size[ 	]+Description
+[ 	]+GNU[ 	]+0x00000010[ 	]+NT_GNU_PROPERTY_TYPE_0
+[ 	]+Properties: RISC-V AND feature: CFI_SS
diff --git a/ld/testsuite/ld-riscv-elf/property-zicfiss.s b/ld/testsuite/ld-riscv-elf/property-zicfiss.s
new file mode 100644
index 00000000000..21342ef1d0d
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property-zicfiss.s
@@ -0,0 +1,21 @@
+	.text
+	.globl _start
+	.type _start,@function
+_start:
+    ret
+
+	.section ".note.gnu.property", "a"
+	.p2align 3
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align 3
+2:	.long 0xc0000000	/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+	.long 0x2		/* GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS.  */
+4:
+	.p2align 3
+5:
diff --git a/ld/testsuite/ld-riscv-elf/property1.s b/ld/testsuite/ld-riscv-elf/property1.s
new file mode 100644
index 00000000000..622bbcbd02c
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property1.s
@@ -0,0 +1,21 @@
+	.text
+	.globl _start
+	.type _start,@function
+_start:
+    ret
+
+	.section ".note.gnu.property", "a"
+	.p2align 3
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align 3
+2:	.long 0xc0000000	/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+	.long 0x3		/* CFI_LP_UNLABELED and CFI_SS.  */
+4:
+	.p2align 3
+5:
diff --git a/ld/testsuite/ld-riscv-elf/property2.s b/ld/testsuite/ld-riscv-elf/property2.s
new file mode 100644
index 00000000000..4d1610c8e0f
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property2.s
@@ -0,0 +1,5 @@
+	.text
+	.globl foo
+	.type foo,@function
+foo:
+    ret
diff --git a/ld/testsuite/ld-riscv-elf/property3.s b/ld/testsuite/ld-riscv-elf/property3.s
new file mode 100644
index 00000000000..61518fb0188
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property3.s
@@ -0,0 +1,21 @@
+	.text
+	.globl _start
+	.type _start,@function
+bar:
+    ret
+
+	.section ".note.gnu.property", "a"
+	.p2align 3
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align 3
+2:	.long 0xc0000000	/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+	.long 0x1		/* CFI_LP_UNLABELED.  */
+4:
+	.p2align 3
+5:
diff --git a/ld/testsuite/ld-riscv-elf/property4.s b/ld/testsuite/ld-riscv-elf/property4.s
new file mode 100644
index 00000000000..54098a50291
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/property4.s
@@ -0,0 +1,21 @@
+	.text
+	.globl _start
+	.type _start,@function
+zoo:
+    ret
+
+	.section ".note.gnu.property", "a"
+	.p2align 3
+	.long 1f - 0f		/* name length */
+	.long 5f - 2f		/* data length */
+	.long 5			/* note type */
+0:	.asciz "GNU"		/* vendor name */
+1:
+	.p2align 3
+2:	.long 0xc0000000	/* pr_type.  */
+	.long 4f - 3f		/* pr_datasz.  */
+3:
+	.long 0x2		/* CFI_LP_SS.  */
+4:
+	.p2align 3
+5:


More information about the Binutils-cvs mailing list