aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKito Cheng <kito.cheng@sifive.com>2025-06-11 16:33:48 +0800
committerNelson Chu <nelson@rivosinc.com>2025-06-24 18:14:42 +0800
commit84eb7d284b3ae07ee894a1f21defc3c9669297b7 (patch)
treeed555d634ba79a83335116233ead056204c9349c
parent4ad5217caf706925014e38be2bc561a2fa094ece (diff)
downloadbinutils-84eb7d284b3ae07ee894a1f21defc3c9669297b7.zip
binutils-84eb7d284b3ae07ee894a1f21defc3c9669297b7.tar.gz
binutils-84eb7d284b3ae07ee894a1f21defc3c9669297b7.tar.bz2
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.
-rw-r--r--bfd/elfnn-riscv.c35
-rw-r--r--bfd/elfxx-riscv.c171
-rw-r--r--bfd/elfxx-riscv.h13
-rw-r--r--ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp6
-rw-r--r--ld/testsuite/ld-riscv-elf/property-combine-and-1.d6
-rw-r--r--ld/testsuite/ld-riscv-elf/property-combine-and-2.d11
-rw-r--r--ld/testsuite/ld-riscv-elf/property-combine-and-3.d11
-rw-r--r--ld/testsuite/ld-riscv-elf/property-zicfilp-unlabeled.d10
-rw-r--r--ld/testsuite/ld-riscv-elf/property-zicfilp-unlabeled.s21
-rw-r--r--ld/testsuite/ld-riscv-elf/property-zicfiss.d10
-rw-r--r--ld/testsuite/ld-riscv-elf/property-zicfiss.s21
-rw-r--r--ld/testsuite/ld-riscv-elf/property1.s21
-rw-r--r--ld/testsuite/ld-riscv-elf/property2.s5
-rw-r--r--ld/testsuite/ld-riscv-elf/property3.s21
-rw-r--r--ld/testsuite/ld-riscv-elf/property4.s21
15 files changed, 383 insertions, 0 deletions
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 49f4e76..49e812e 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 0884bb7..936adcd 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 6223281..d8845af 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 9cb847d..e03e44a 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 0000000..9f9cf83
--- /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 0000000..25b8646
--- /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 0000000..52882c6
--- /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 0000000..8aec50b
--- /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 0000000..b0192c0
--- /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 0000000..8f2af00
--- /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 0000000..21342ef
--- /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 0000000..622bbcb
--- /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 0000000..4d1610c
--- /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 0000000..61518fb
--- /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 0000000..54098a5
--- /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: