[PATCH 2/2] RISC-V: Check for conflicting extensions when the linker merges arch attributes
Nelson Chu
nelson.chu@sifive.com
Tue Jul 7 01:51:22 GMT 2026
Ummm, I linked a.o with c and b.o with d. It seems this isn't allowed
already because we cannot link double-float with soft-float modules. So do
we have any case where implicit extensions haven't been added for all input
objects, requiring us to call riscv_parse_add_implicit_subsets for the
merged string? If yes please also add the testcases.
Thanks
Nelson
On Tue, Jul 7, 2026 at 9:26 AM Nelson Chu <nelson.chu@sifive.com> wrote:
> Oh, okay, I see the case: inputs with 'c' and inputs with 'd' will need
> zcd after merging. Looks reasonable to call
> riscv_parse_add_implicit_subsets for merged string, too.
>
> Thanks
> Nelson
>
> On Tue, Jul 7, 2026 at 9:19 AM Nelson Chu <nelson.chu@sifive.com> wrote:
>
>>
>>
>> On Mon, Jul 6, 2026 at 7:46 PM Ethan Y. C. Liang <ycl669@andestech.com>
>> wrote:
>>
>>> The linker validates the arch of each input when parsing it, but never
>>> checks the merged arch as a whole, so conflicting extensions could
>>> silently slip through. The merge can even imply extensions that
>>> neither input implies alone, e.g. `c' from one input and `d' from
>>> another imply `zcd', which conflicts with `zcmp'.
>>>
>>> After merging the input archs, add the implicit extensions to the
>>> merged arch, then run the conflict checks on it and reject the merge
>>> if any conflict is found. Add tests for such merges.
>>> ---
>>> bfd/elfxx-riscv.c | 8 ++++++++
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.d | 5 +++++
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.l | 2 ++
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01a.s | 1 +
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01b.s | 1 +
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.d | 5 +++++
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.l | 2 ++
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02a.s | 1 +
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02b.s | 1 +
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.d | 5 +++++
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.l | 2 ++
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03a.s | 1 +
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03b.s | 1 +
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.d | 5 +++++
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.l | 2 ++
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04a.s | 1 +
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04b.s | 1 +
>>> ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 4 ++++
>>> 18 files changed, 48 insertions(+)
>>> create mode 100644 ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.d
>>> create mode 100644 ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.l
>>> create mode 100644
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01a.s
>>> create mode 100644
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01b.s
>>> create mode 100644 ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.d
>>> create mode 100644 ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.l
>>> create mode 100644
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02a.s
>>> create mode 100644
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02b.s
>>> create mode 100644 ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.d
>>> create mode 100644 ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.l
>>> create mode 100644
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03a.s
>>> create mode 100644
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03b.s
>>> create mode 100644 ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.d
>>> create mode 100644 ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.l
>>> create mode 100644
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04a.s
>>> create mode 100644
>>> ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04b.s
>>>
>>> diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
>>> index fa2f1759f31..128c0eda8c4 100644
>>> --- a/bfd/elfxx-riscv.c
>>> +++ b/bfd/elfxx-riscv.c
>>> @@ -3750,6 +3750,14 @@ riscv_merge_arch_attr_info (bfd *ibfd, char
>>> *in_arch, char *out_arch,
>>> goto cleanup;
>>> }
>>>
>>> + /* Add the implicit subsets implied by the merged subset list, then
>>> + check if the result is conflicting. */
>>> + riscv_parse_subset_t riscv_rps_ld_merged =
>>> + {&merged_subsets, _bfd_error_handler, &xlen_in, NULL, false};
>>
>> + riscv_parse_add_implicit_subsets (&riscv_rps_ld_merged);
>>> + if (!riscv_parse_check_conflicts (&riscv_rps_ld_merged))
>>> + goto cleanup;
>>> +
>>>
>>
>> Looks reasonable to call riscv_parse_check_conflicts for the merged
>> architecture string. But do we need to call
>> riscv_parse_add_implicit_subsets? Since I checked all current
>> check_implicit_* functions (always/for_i/for_zcf/for_zcd), I think all
>> implicit extensions should be added in the each input object already.
>>
>> Thanks
>> Nelson
>>
>>
>>> /* Free the previous merged_arch_str which called xmalloc. */
>>> free (merged_arch_str);
>>>
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.d
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.d
>>> new file mode 100644
>>> index 00000000000..f99677cb767
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.d
>>> @@ -0,0 +1,5 @@
>>> +#source: attr-merge-arch-failed-01a.s
>>> +#source: attr-merge-arch-failed-01b.s
>>> +#as: -mabi=ilp32
>>> +#ld: -r -m[riscv_choose_ilp32_emul]
>>> +#error_output: attr-merge-arch-failed-01.l
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.l
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.l
>>> new file mode 100644
>>> index 00000000000..ad6d2630211
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01.l
>>> @@ -0,0 +1,2 @@
>>> +.*: `zfinx' conflicts with the `f/d/q/zfh/zfhmin' extension
>>> +.*: failed to merge target specific data of file .*
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01a.s
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01a.s
>>> new file mode 100644
>>> index 00000000000..8f2a98f95f3
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01a.s
>>> @@ -0,0 +1 @@
>>> + .attribute arch, "rv32i_zfinx"
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01b.s
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01b.s
>>> new file mode 100644
>>> index 00000000000..a44b2a0d346
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-01b.s
>>> @@ -0,0 +1 @@
>>> + .attribute arch, "rv32if"
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.d
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.d
>>> new file mode 100644
>>> index 00000000000..4fb1980c97d
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.d
>>> @@ -0,0 +1,5 @@
>>> +#source: attr-merge-arch-failed-02a.s
>>> +#source: attr-merge-arch-failed-02b.s
>>> +#as: -mabi=ilp32
>>> +#ld: -r -m[riscv_choose_ilp32_emul]
>>> +#error_output: attr-merge-arch-failed-02.l
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.l
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.l
>>> new file mode 100644
>>> index 00000000000..930e03123e1
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02.l
>>> @@ -0,0 +1,2 @@
>>> +.*: zcmp' is incompatible with `d' and `c', or `zcd' extension
>>> +.*: failed to merge target specific data of file .*
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02a.s
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02a.s
>>> new file mode 100644
>>> index 00000000000..3f79059d5d0
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02a.s
>>> @@ -0,0 +1 @@
>>> + .attribute arch, "rv32i_zcmp"
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02b.s
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02b.s
>>> new file mode 100644
>>> index 00000000000..95bfe1f6d9f
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-02b.s
>>> @@ -0,0 +1 @@
>>> + .attribute arch, "rv32i_zcd"
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.d
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.d
>>> new file mode 100644
>>> index 00000000000..def49c3fb3f
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.d
>>> @@ -0,0 +1,5 @@
>>> +#source: attr-merge-arch-failed-03a.s
>>> +#source: attr-merge-arch-failed-03b.s
>>> +#as: -mabi=ilp32
>>> +#ld: -r -m[riscv_choose_ilp32_emul]
>>> +#error_output: attr-merge-arch-failed-03.l
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.l
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.l
>>> new file mode 100644
>>> index 00000000000..d9075d0c30e
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03.l
>>> @@ -0,0 +1,2 @@
>>> +.*: `zclsd' conflicts with the `c\+f'/`zcf' extension
>>> +.*: failed to merge target specific data of file .*
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03a.s
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03a.s
>>> new file mode 100644
>>> index 00000000000..f7f9ceb11f6
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03a.s
>>> @@ -0,0 +1 @@
>>> + .attribute arch, "rv32i_zclsd"
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03b.s
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03b.s
>>> new file mode 100644
>>> index 00000000000..f18129dc55d
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-03b.s
>>> @@ -0,0 +1 @@
>>> + .attribute arch, "rv32i_zcf"
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.d
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.d
>>> new file mode 100644
>>> index 00000000000..5445936df44
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.d
>>> @@ -0,0 +1,5 @@
>>> +#source: attr-merge-arch-failed-04a.s
>>> +#source: attr-merge-arch-failed-04b.s
>>> +#as: -mabi=ilp32
>>> +#ld: -r -m[riscv_choose_ilp32_emul]
>>> +#error_output: attr-merge-arch-failed-04.l
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.l
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.l
>>> new file mode 100644
>>> index 00000000000..930e03123e1
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04.l
>>> @@ -0,0 +1,2 @@
>>> +.*: zcmp' is incompatible with `d' and `c', or `zcd' extension
>>> +.*: failed to merge target specific data of file .*
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04a.s
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04a.s
>>> new file mode 100644
>>> index 00000000000..e79c25b7828
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04a.s
>>> @@ -0,0 +1 @@
>>> + .attribute arch, "rv32ic"
>>> diff --git a/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04b.s
>>> b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04b.s
>>> new file mode 100644
>>> index 00000000000..c7468e4e072
>>> --- /dev/null
>>> +++ b/ld/testsuite/ld-riscv-elf/attr-merge-arch-failed-04b.s
>>> @@ -0,0 +1 @@
>>> + .attribute arch, "rv32id_zcmp"
>>> diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>>> b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>>> index 8e26ccff10a..57f3139c9f6 100644
>>> --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>>> +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
>>> @@ -157,6 +157,10 @@ if [istarget "riscv*-*-*"] {
>>> run_dump_test "attr-merge-arch-01"
>>> run_dump_test "attr-merge-arch-02"
>>> run_dump_test "attr-merge-arch-03"
>>> + run_dump_test "attr-merge-arch-failed-01"
>>> + run_dump_test "attr-merge-arch-failed-02"
>>> + run_dump_test "attr-merge-arch-failed-03"
>>> + run_dump_test "attr-merge-arch-failed-04"
>>> run_dump_test "attr-merge-strict-align-01"
>>> run_dump_test "attr-merge-strict-align-02"
>>> run_dump_test "attr-merge-strict-align-03"
>>> --
>>> 2.54.0
>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/binutils/attachments/20260707/e0cc3490/attachment-0001.htm>
More information about the Binutils
mailing list