From: Kito Cheng Date: Wed, 11 Jun 2025 08:33:48 +0000 (+0800) Subject: RISC-V: Implment the merge logic for GNU_PROPERTY_RISCV_FEATURE_1_AND X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=84eb7d284b3ae07ee894a1f21defc3c9669297b7;p=thirdparty%2Fbinutils-gdb.git 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 --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: "), + 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: