Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <f1e1e8a6-e8a2-4a40-a5c5-54757567854d@app.fastmail.com>
Date: Sun, 04 Oct 2026 05:58:28 +0200
From: Alex Rønne Petersen <alex@...xrp.com>
To: "Rich Felker" <dalias@...c.org>
Cc: musl@...ts.openwall.com
Subject: Re: [PATCH] riscv: declare all vector registers as clobbers of syscalls

On Sun, Oct 4, 2026, at 05:51, Rich Felker wrote:
> On Sun, Oct 04, 2026 at 05:35:36AM +0200, Alex Rønne Petersen wrote:
>> On Sun, Oct 4, 2026, at 05:04, Rich Felker wrote:
>> > On Sun, Oct 04, 2026 at 04:48:52AM +0200, Alex Rønne Petersen wrote:
>> >> The kernel intentionally clobbers vector registers (by setting them to all 1s).
>> >> musl didn't declare this, so with a compiler targeting the V extension, this
>> >> could lead to all sorts of breakage that at first glance looks like
>> >> miscompilations.
>> >> ---
>> >>  arch/riscv32/syscall_arch.h | 9 ++++++++-
>> >>  arch/riscv64/syscall_arch.h | 9 ++++++++-
>> >>  2 files changed, 16 insertions(+), 2 deletions(-)
>> >> 
>> >> diff --git a/arch/riscv32/syscall_arch.h b/arch/riscv32/syscall_arch.h
>> >> index 70d2773f..9149cb9e 100644
>> >> --- a/arch/riscv32/syscall_arch.h
>> >> +++ b/arch/riscv32/syscall_arch.h
>> >> @@ -3,9 +3,16 @@
>> >>  ((union { long long ll; long l[2]; }){ .ll = x }).l[1]
>> >>  #define __SYSCALL_LL_O(x) __SYSCALL_LL_E((x))
>> >>  
>> >> +#define SYSCALL_CLOBBERLIST \
>> >> +	"v0" , "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7", \
>> >> +	"v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15", \
>> >> +	"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", \
>> >> +	"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", \
>> >> +	"vl", "vtype", "vxsat", "vxrm", "memory"
>> >> +
>> >>  #define __asm_syscall(...) \
>> >>  	__asm__ __volatile__ ("ecall\n\t" \
>> >> -	: "=r"(a0) : __VA_ARGS__ : "memory"); \
>> >> +	: "=r"(a0) : __VA_ARGS__ : SYSCALL_CLOBBERLIST); \
>> >>  	return a0; \
>> >>  
>> >>  static inline long __syscall0(long n)
>> >> diff --git a/arch/riscv64/syscall_arch.h b/arch/riscv64/syscall_arch.h
>> >> index 81993fc8..6e05c9b3 100644
>> >> --- a/arch/riscv64/syscall_arch.h
>> >> +++ b/arch/riscv64/syscall_arch.h
>> >> @@ -1,9 +1,16 @@
>> >>  #define __SYSCALL_LL_E(x) (x)
>> >>  #define __SYSCALL_LL_O(x) (x)
>> >>  
>> >> +#define SYSCALL_CLOBBERLIST \
>> >> +	"v0" , "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7", \
>> >> +	"v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15", \
>> >> +	"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", \
>> >> +	"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", \
>> >> +	"vl", "vtype", "vxsat", "vxrm", "memory"
>> >> +
>> >>  #define __asm_syscall(...) \
>> >>  	__asm__ __volatile__ ("ecall\n\t" \
>> >> -	: "=r"(a0) : __VA_ARGS__ : "memory"); \
>> >> +	: "=r"(a0) : __VA_ARGS__ : SYSCALL_CLOBBERLIST); \
>> >>  	return a0; \
>> >>  
>> >>  static inline long __syscall0(long n)
>> >> -- 
>> >> 2.53.0
>> >
>> > I don't doubt that something like this is needed, but I'm a little
>> > concerned about a couple things. Does this break build for targets that
>> > lack these registers or compilers that aren't aware of them? And is
>> > the set stable, or will it grow as other extensions are added?
>> >
>> > If there are no good answers to these questions, it might require
>> > dropping inline syscalls for riscv and forcing them all to go through
>> > an external call where the call ABI governs the register clobbers.
>> 
>> Older GCCs will complain about the V registers. GCC 13 (~2023) is
>> the first version that became aware of them. A newer GCC with V
>> disabled will just ignore those clobbers. I believe the story is
>> similar for Clang; it gained full awareness of V registers in Clang
>> 18 (~2024).
>> 
>> So we probably need to at least check __GNUC__ and __clang__ if we
>> go with this approach.
>> 
>> I seem to recall the kernel did something similar to this for
>> SVE/SME state on AArch64? So I don't think we can rule out the
>> possibility of this being the norm going forward. Then again, it's
>> not the case for vector registers on LoongArch... :shrug:
>> 
>> My suggestion, FWIW, would be to leave it as-is for now. If the
>> kernel folks do decide to do this again for a future RISC-V
>> extension, then it's probably time to switch to an external call
>> because a pattern has been established.
>
> Well if we're going to include this fix, it needs to actually compile
> on any compiler someone might use.
>
> Is there a predefined macro that declares the availability of these
> registers that we could use? I really do not want to hard-code
> particular gcc or clang versions.

Unfortunately no:

    $ riscv64-linux-gnu-gcc -march=rv64gc -dM -E - < /dev/null | grep __riscv
    #define __riscv 1
    #define __riscv_atomic 1
    #define __riscv_cmodel_medany 1
    #define __riscv_zmmul 1000000
    #define __riscv_zalrsc 1000000
    #define __riscv_zaamo 1000000
    #define __riscv_mul 1
    #define __riscv_misaligned_slow 1
    #define __riscv_muldiv 1
    #define __riscv_xlen 64
    #define __riscv_fsqrt 1
    #define __riscv_m 2000000
    #define __riscv_fdiv 1
    #define __riscv_a 2001000
    #define __riscv_c 2000000
    #define __riscv_d 2002000
    #define __riscv_f 2002000
    #define __riscv_i 2001000
    #define __riscv_zicsr 2000000
    #define __riscv_compressed 1
    #define __riscv_float_abi_double 1
    #define __riscv_flen 64
    #define __riscv_arch_test 1
    #define __riscv_div 1
    #define __riscv_zca 1000000
    #define __riscv_zcd 1000000
    #define __riscv_zifencei 2000000

I suppose we could do a configure check? Though that's not amazingly appealing either.

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.