Re: [PATCH v2 1/6] ARM: cmpxchg: always inline __arch_xchg() and __cmpxchg()

From: Gary Guo

Date: Thu Oct 08 2026 - 05:03:24 EST


On Thu Oct 8, 2026 at 7:37 AM CEST, Karl Mehltretter wrote:
> __arch_xchg(), __cmpxchg() and __cmpxchg_local() end in a default case
> that calls an undefined function. That turns an unsupported size into a
> link error. It relies on the functions being inlined, so that the
> compiler can drop the default case for a constant size.
>
> They are only marked inline. gcc 8.1.0 with CC_OPTIMIZE_FOR_SIZE does
> not inline them in rust/helpers/helpers.c, which calls xchg() and
> cmpxchg() from many small helpers. The out-of-line copies keep the
> default case and the link fails.
>
> helpers.c:(.text+0x424): undefined reference to `__bad_xchg'
> helpers.c:(.text+0x4ac): undefined reference to `__bad_cmpxchg'
>
> Seen with bcm2835_defconfig and CONFIG_RUST=y on v7.3-rc1. The same
> config links with CONFIG_RUST=n. It also links with gcc 15.2.0 and
> with clang.
>
> v6.19 links. Commit ab717dd98bee ("rust: helpers: Add i8/i16 atomic
> xchg_acquire helpers") in v7.0 triggers __bad_xchg. Commit
> ac8f06ade38a ("rust: sync: atomic: Add Atomic<*{mut,const} T> support")
> in v7.1 also triggers __bad_cmpxchg.

I think the issue is that when you get multiple function calls in a function,
GCC starts to think that not inlining can result in code deduplication where
that is not actually true.

But I am surprised that it hasn't been seen in the past, perhaps there're only
calls with single size from any translation unit previously?

The fix LGTM, but Sashiko's report is worth looking into.

Best,
Gary

>
> Mark the functions __always_inline.
>
> Fixes: ab717dd98bee ("rust: helpers: Add i8/i16 atomic xchg_acquire helpers")
> Fixes: ac8f06ade38a ("rust: sync: atomic: Add Atomic<*{mut,const} T> support")
> Cc: stable@xxxxxxxxxxxxxxx
> Assisted-by: LLM
> Signed-off-by: Karl Mehltretter <kmehltretter@xxxxxxxxx>
> ---
> arch/arm/include/asm/cmpxchg.h | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm/include/asm/cmpxchg.h b/arch/arm/include/asm/cmpxchg.h
> index 9beb64d30586..0ce5225af442 100644
> --- a/arch/arm/include/asm/cmpxchg.h
> +++ b/arch/arm/include/asm/cmpxchg.h
> @@ -26,7 +26,7 @@
> #define swp_is_buggy
> #endif
>
> -static inline unsigned long
> +static __always_inline unsigned long
> __arch_xchg(unsigned long x, volatile void *ptr, int size)
> {
> extern void __bad_xchg(volatile void *, int);
> @@ -155,8 +155,8 @@ extern void __bad_cmpxchg(volatile void *ptr, int size);
> * cmpxchg only support 32-bits operands on ARMv6.
> */
>
> -static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
> - unsigned long new, int size)
> +static __always_inline unsigned long
> +__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
> {
> unsigned long oldval, res;
>
> @@ -220,9 +220,9 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
> sizeof(*(ptr))); \
> })
>
> -static inline unsigned long __cmpxchg_local(volatile void *ptr,
> - unsigned long old,
> - unsigned long new, int size)
> +static __always_inline unsigned long
> +__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
> + int size)
> {
> unsigned long ret;
>