[2/2] RISC-V: Check for conflicting extensions when the linker merges arch attributes
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
Commit Message
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
Comments
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
>
>
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
>>
>>
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
>>>
>>>
I think you can try testing it with the soft-float ABI to avoid the linker error you ran into.
You can also refer to the attr-merge-arch-failed-04 test case that I added.
Ethan
On Tue, Jul 07, 2026 at 09:51:22AM +0800, Nelson Chu wrote:
> 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<mailto: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<mailto:nelson.chu@sifive.com>> wrote:
>
>
> On Mon, Jul 6, 2026 at 7:46 PM Ethan Y. C. Liang <ycl669@andestech.com<mailto: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
>
On Tue, Jul 7, 2026 at 10:05 AM Ethan Y. C. Liang <ycl669@andestech.com>
wrote:
> I think you can try testing it with the soft-float ABI to avoid the linker
> error you ran into.
I meant if we already got an error, then why not just call check confflict
without calling riscv_parse_add_implicit_subsets, since adding implicits
may waste link time, but whatever...
>
> You can also refer to the attr-merge-arch-failed-04 test case that I added.
>
Okay, the attr-merge-arch-failed-04 looks reasonable since we only check if
zcmp and zcd exist for now, without the riscv_parse_add_implicit_subsets,
zcd won't be added so the testcase won't be expected failed.
Thanks
Nelson
> Ethan
>
> On Tue, Jul 07, 2026 at 09:51:22AM +0800, Nelson Chu wrote:
> > 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<mailto:
> 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<mailto:
> nelson.chu@sifive.com>> wrote:
> >
> >
> > On Mon, Jul 6, 2026 at 7:46 PM Ethan Y. C. Liang <ycl669@andestech.com
> <mailto: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
> >
>
Sorry, forgot to commit. Committed, thanks.
Nelson
On Wed, Jul 8, 2026 at 11:07 AM Nelson Chu <nelson.chu@sifive.com> wrote:
>
>
> On Tue, Jul 7, 2026 at 10:05 AM Ethan Y. C. Liang <ycl669@andestech.com>
> wrote:
>
>> I think you can try testing it with the soft-float ABI to avoid the
>> linker error you ran into.
>
>
> I meant if we already got an error, then why not just call check confflict
> without calling riscv_parse_add_implicit_subsets, since adding implicits
> may waste link time, but whatever...
>
>
>>
>> You can also refer to the attr-merge-arch-failed-04 test case that I
>> added.
>>
>
> Okay, the attr-merge-arch-failed-04 looks reasonable since we only check
> if zcmp and zcd exist for now, without the riscv_parse_add_implicit_subsets,
> zcd won't be added so the testcase won't be expected failed.
>
> Thanks
> Nelson
>
>
>> Ethan
>>
>> On Tue, Jul 07, 2026 at 09:51:22AM +0800, Nelson Chu wrote:
>> > 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
>> <mailto: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
>> <mailto:nelson.chu@sifive.com>> wrote:
>> >
>> >
>> > On Mon, Jul 6, 2026 at 7:46 PM Ethan Y. C. Liang <ycl669@andestech.com
>> <mailto: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
>> >
>>
>
Thanks for your commit!
Ethan
On Thu, Jul 09, 2026 at 09:10:24AM +0800, Nelson Chu wrote:
> Sorry, forgot to commit. Committed, thanks.
>
> Nelson
>
> On Wed, Jul 8, 2026 at 11:07 AM Nelson Chu <nelson.chu@sifive.com<mailto:nelson.chu@sifive.com>> wrote:
>
>
> On Tue, Jul 7, 2026 at 10:05 AM Ethan Y. C. Liang <ycl669@andestech.com<mailto:ycl669@andestech.com>> wrote:
> I think you can try testing it with the soft-float ABI to avoid the linker error you ran into.
>
> I meant if we already got an error, then why not just call check confflict without calling riscv_parse_add_implicit_subsets, since adding implicits may waste link time, but whatever...
>
>
> You can also refer to the attr-merge-arch-failed-04 test case that I added.
>
> Okay, the attr-merge-arch-failed-04 looks reasonable since we only check if zcmp and zcd exist for now, without the riscv_parse_add_implicit_subsets, zcd won't be added so the testcase won't be expected failed.
>
> Thanks
> Nelson
>
> Ethan
>
> On Tue, Jul 07, 2026 at 09:51:22AM +0800, Nelson Chu wrote:
> > 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<mailto:nelson.chu@sifive.com><mailto:nelson.chu@sifive.com<mailto: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<mailto:nelson.chu@sifive.com><mailto:nelson.chu@sifive.com<mailto:nelson.chu@sifive.com>>> wrote:
> >
> >
> > On Mon, Jul 6, 2026 at 7:46 PM Ethan Y. C. Liang <ycl669@andestech.com<mailto:ycl669@andestech.com><mailto:ycl669@andestech.com<mailto: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
> >
@@ -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;
+
/* Free the previous merged_arch_str which called xmalloc. */
free (merged_arch_str);
new file mode 100644
@@ -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
new file mode 100644
@@ -0,0 +1,2 @@
+.*: `zfinx' conflicts with the `f/d/q/zfh/zfhmin' extension
+.*: failed to merge target specific data of file .*
new file mode 100644
@@ -0,0 +1 @@
+ .attribute arch, "rv32i_zfinx"
new file mode 100644
@@ -0,0 +1 @@
+ .attribute arch, "rv32if"
new file mode 100644
@@ -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
new file mode 100644
@@ -0,0 +1,2 @@
+.*: zcmp' is incompatible with `d' and `c', or `zcd' extension
+.*: failed to merge target specific data of file .*
new file mode 100644
@@ -0,0 +1 @@
+ .attribute arch, "rv32i_zcmp"
new file mode 100644
@@ -0,0 +1 @@
+ .attribute arch, "rv32i_zcd"
new file mode 100644
@@ -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
new file mode 100644
@@ -0,0 +1,2 @@
+.*: `zclsd' conflicts with the `c\+f'/`zcf' extension
+.*: failed to merge target specific data of file .*
new file mode 100644
@@ -0,0 +1 @@
+ .attribute arch, "rv32i_zclsd"
new file mode 100644
@@ -0,0 +1 @@
+ .attribute arch, "rv32i_zcf"
new file mode 100644
@@ -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
new file mode 100644
@@ -0,0 +1,2 @@
+.*: zcmp' is incompatible with `d' and `c', or `zcd' extension
+.*: failed to merge target specific data of file .*
new file mode 100644
@@ -0,0 +1 @@
+ .attribute arch, "rv32ic"
new file mode 100644
@@ -0,0 +1 @@
+ .attribute arch, "rv32id_zcmp"
@@ -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"