On 32-bit ARM, you may encounter linker errors such as this one:
ld.lld: error: undefined symbol: _find_next_zero_bit >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a
This error occurs because even though the functions are declared by include/linux/find.h, the definition is #ifdef'd out on 32-bit ARM. This is because arch/arm/include/asm/bitops.h contains:
#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off)
And the underscore-prefixed function is conditional on #ifndef of the non-underscore-prefixed name, but the declaration in find.h is *not* conditional on that #ifndef.
To fix the linker error, we ensure that the symbols in question exist when compiling Rust code. We do this by definining them in rust/helpers/ whenever the normal definition is #ifndef'd out.
Note that these helpers are somewhat unusual in that they do not have the rust_helper_ prefix that most helpers have. Adding the rust_helper_ prefix does not compile, as 'bindings::_find_next_zero_bit()' will result in a call to a symbol called _find_next_zero_bit as defined by include/linux/find.h rather than a symbol with the rust_helper_ prefix. This is because when a symbol is present in both include/ and rust/helpers/, the one from include/ wins under the assumption that the current configuration is one where that helper is unnecessary. This heuristic fails for _find_next_zero_bit() because the header file always declares it even if the symbol does not exist.
The functions still use the __rust_helper annotation. This lets the wrapper function be inlined into Rust code even if full kernel LTO is not used once the patch series for that feature lands.
Cc: stable@vger.kernel.org Fixes: 6cf93a9ed39e ("rust: add bindings for bitops.h") Reported-by: Andreas Hindborg a.hindborg@kernel.org Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/x/topic/x/near/56167730... Signed-off-by: Alice Ryhl aliceryhl@google.com --- Changes in v2: - Remove rust_helper_ prefix from helpers. - Improve commit message. - The set of functions for which a helper is added is changed so that it matches arch/arm/include/asm/bitops.h - Link to v1: https://lore.kernel.org/r/20251203-bitops-find-helper-v1-1-5193deb57766@goog... --- rust/helpers/bitops.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/rust/helpers/bitops.c b/rust/helpers/bitops.c index 5d0861d29d3f0d705a014ae4601685828405f33b..e79ef9e6d98f969e2a0a2a6f62d9fcec3ef0fd72 100644 --- a/rust/helpers/bitops.c +++ b/rust/helpers/bitops.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0
#include <linux/bitops.h> +#include <linux/find.h>
void rust_helper___set_bit(unsigned long nr, unsigned long *addr) { @@ -21,3 +22,44 @@ void rust_helper_clear_bit(unsigned long nr, volatile unsigned long *addr) { clear_bit(nr, addr); } + +/* + * The rust_helper_ prefix is intentionally omitted below so that the + * declarations in include/linux/find.h are compatible with these helpers. + * + * Note that the below #ifdefs mean that the helper is only created if C does + * not provide a definition. + */ +#ifdef find_first_zero_bit +__rust_helper +unsigned long _find_first_zero_bit(const unsigned long *p, unsigned long size) +{ + return find_first_zero_bit(p, size); +} +#endif /* find_first_zero_bit */ + +#ifdef find_next_zero_bit +__rust_helper +unsigned long _find_next_zero_bit(const unsigned long *addr, + unsigned long size, unsigned long offset) +{ + return find_next_zero_bit(addr, size, offset); +} +#endif /* find_next_zero_bit */ + +#ifdef find_first_bit +__rust_helper +unsigned long _find_first_bit(const unsigned long *addr, unsigned long size) +{ + return find_first_bit(addr, size); +} +#endif /* find_first_bit */ + +#ifdef find_next_bit +__rust_helper +unsigned long _find_next_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + return find_next_bit(addr, size, offset); +} +#endif /* find_next_bit */
--- base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8 change-id: 20251203-bitops-find-helper-25ed1bbae700
Best regards,
On Mon, Jan 05, 2026 at 10:44:06AM +0000, Alice Ryhl wrote:
atus: O Content-Length: 4697 Lines: 121
On 32-bit ARM, you may encounter linker errors such as this one:
ld.lld: error: undefined symbol: _find_next_zero_bit
referenced by rust_binder_main.43196037ba7bcee1-cgu.0 drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a referenced by rust_binder_main.43196037ba7bcee1-cgu.0 drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a
This error occurs because even though the functions are declared by include/linux/find.h, the definition is #ifdef'd out on 32-bit ARM. This is because arch/arm/include/asm/bitops.h contains:
#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off)
And the underscore-prefixed function is conditional on #ifndef of the non-underscore-prefixed name, but the declaration in find.h is *not* conditional on that #ifndef.
To fix the linker error, we ensure that the symbols in question exist when compiling Rust code. We do this by definining them in rust/helpers/ whenever the normal definition is #ifndef'd out.
Note that these helpers are somewhat unusual in that they do not have the rust_helper_ prefix that most helpers have. Adding the rust_helper_ prefix does not compile, as 'bindings::_find_next_zero_bit()' will result in a call to a symbol called _find_next_zero_bit as defined by include/linux/find.h rather than a symbol with the rust_helper_ prefix. This is because when a symbol is present in both include/ and rust/helpers/, the one from include/ wins under the assumption that the current configuration is one where that helper is unnecessary. This heuristic fails for _find_next_zero_bit() because the header file always declares it even if the symbol does not exist.
The functions still use the __rust_helper annotation. This lets the wrapper function be inlined into Rust code even if full kernel LTO is not used once the patch series for that feature lands.
Cc: stable@vger.kernel.org Fixes: 6cf93a9ed39e ("rust: add bindings for bitops.h") Reported-by: Andreas Hindborg a.hindborg@kernel.org Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/x/topic/x/near/56167730... Signed-off-by: Alice Ryhl aliceryhl@google.com
Which means, you're running active testing, which in turn means that Rust is in a good shape indeed. Thanks to you and Andreas for the work.
Before I merge it, can you also test m68k build? Arm and m68k are the only arches implementing custom API there.
Thanks, Yury
Changes in v2:
- Remove rust_helper_ prefix from helpers.
- Improve commit message.
- The set of functions for which a helper is added is changed so that it matches arch/arm/include/asm/bitops.h
- Link to v1: https://lore.kernel.org/r/20251203-bitops-find-helper-v1-1-5193deb57766@goog...
rust/helpers/bitops.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
diff --git a/rust/helpers/bitops.c b/rust/helpers/bitops.c index 5d0861d29d3f0d705a014ae4601685828405f33b..e79ef9e6d98f969e2a0a2a6f62d9fcec3ef0fd72 100644 --- a/rust/helpers/bitops.c +++ b/rust/helpers/bitops.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/bitops.h> +#include <linux/find.h> void rust_helper___set_bit(unsigned long nr, unsigned long *addr) { @@ -21,3 +22,44 @@ void rust_helper_clear_bit(unsigned long nr, volatile unsigned long *addr) { clear_bit(nr, addr); }
+/*
- The rust_helper_ prefix is intentionally omitted below so that the
- declarations in include/linux/find.h are compatible with these helpers.
- Note that the below #ifdefs mean that the helper is only created if C does
- not provide a definition.
- */
+#ifdef find_first_zero_bit +__rust_helper +unsigned long _find_first_zero_bit(const unsigned long *p, unsigned long size) +{
- return find_first_zero_bit(p, size);
+} +#endif /* find_first_zero_bit */
+#ifdef find_next_zero_bit +__rust_helper +unsigned long _find_next_zero_bit(const unsigned long *addr,
unsigned long size, unsigned long offset)+{
- return find_next_zero_bit(addr, size, offset);
+} +#endif /* find_next_zero_bit */
+#ifdef find_first_bit +__rust_helper +unsigned long _find_first_bit(const unsigned long *addr, unsigned long size) +{
- return find_first_bit(addr, size);
+} +#endif /* find_first_bit */
+#ifdef find_next_bit +__rust_helper +unsigned long _find_next_bit(const unsigned long *addr, unsigned long size,
unsigned long offset)+{
- return find_next_bit(addr, size, offset);
+} +#endif /* find_next_bit */
base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8 change-id: 20251203-bitops-find-helper-25ed1bbae700
Best regard
On Mon, Jan 5, 2026 at 6:03 PM Yury Norov yury.norov@gmail.com wrote:
Which means, you're running active testing, which in turn means that Rust is in a good shape indeed. Thanks to you and Andreas for the work.
Yeah -- to clarify, we have been doing "active testing" for ~5 years, even before Rust was in mainline, for several architectures and configurations. :)
By the way, this reminds me I have to reply to your other message from a while ago.
i.e. this "active testing" does not mean you don't need to test your branch.
Cheers, Miguel
On Mon, Jan 5, 2026 at 6:03 PM Yury Norov yury.norov@gmail.com wrote:
On Mon, Jan 05, 2026 at 10:44:06AM +0000, Alice Ryhl wrote:
atus: O Content-Length: 4697 Lines: 121
On 32-bit ARM, you may encounter linker errors such as this one:
ld.lld: error: undefined symbol: _find_next_zero_bit >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.aThis error occurs because even though the functions are declared by include/linux/find.h, the definition is #ifdef'd out on 32-bit ARM. This is because arch/arm/include/asm/bitops.h contains:
#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off)And the underscore-prefixed function is conditional on #ifndef of the non-underscore-prefixed name, but the declaration in find.h is *not* conditional on that #ifndef.
To fix the linker error, we ensure that the symbols in question exist when compiling Rust code. We do this by definining them in rust/helpers/ whenever the normal definition is #ifndef'd out.
Note that these helpers are somewhat unusual in that they do not have the rust_helper_ prefix that most helpers have. Adding the rust_helper_ prefix does not compile, as 'bindings::_find_next_zero_bit()' will result in a call to a symbol called _find_next_zero_bit as defined by include/linux/find.h rather than a symbol with the rust_helper_ prefix. This is because when a symbol is present in both include/ and rust/helpers/, the one from include/ wins under the assumption that the current configuration is one where that helper is unnecessary. This heuristic fails for _find_next_zero_bit() because the header file always declares it even if the symbol does not exist.
The functions still use the __rust_helper annotation. This lets the wrapper function be inlined into Rust code even if full kernel LTO is not used once the patch series for that feature lands.
Cc: stable@vger.kernel.org Fixes: 6cf93a9ed39e ("rust: add bindings for bitops.h") Reported-by: Andreas Hindborg a.hindborg@kernel.org Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/x/topic/x/near/56167730... Signed-off-by: Alice Ryhl aliceryhl@google.com
Which means, you're running active testing, which in turn means that Rust is in a good shape indeed. Thanks to you and Andreas for the work.
I've put together this collection of GitHub actions jobs that build and test a few common configurations, which I used to test this: https://github.com/Darksonn/linux
Before I merge it, can you also test m68k build? Arm and m68k are the only arches implementing custom API there.
I ran a gcc build for m68k with these patches applied and it built successfully for me.
Alice
On Tue, Jan 06, 2026 at 10:03:10AM +0100, Alice Ryhl wrote:
On Mon, Jan 5, 2026 at 6:03 PM Yury Norov yury.norov@gmail.com wrote:
On Mon, Jan 05, 2026 at 10:44:06AM +0000, Alice Ryhl wrote:
atus: O Content-Length: 4697 Lines: 121
On 32-bit ARM, you may encounter linker errors such as this one:
ld.lld: error: undefined symbol: _find_next_zero_bit >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.aThis error occurs because even though the functions are declared by include/linux/find.h, the definition is #ifdef'd out on 32-bit ARM. This is because arch/arm/include/asm/bitops.h contains:
#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off)And the underscore-prefixed function is conditional on #ifndef of the non-underscore-prefixed name, but the declaration in find.h is *not* conditional on that #ifndef.
To fix the linker error, we ensure that the symbols in question exist when compiling Rust code. We do this by definining them in rust/helpers/ whenever the normal definition is #ifndef'd out.
Note that these helpers are somewhat unusual in that they do not have the rust_helper_ prefix that most helpers have. Adding the rust_helper_ prefix does not compile, as 'bindings::_find_next_zero_bit()' will result in a call to a symbol called _find_next_zero_bit as defined by include/linux/find.h rather than a symbol with the rust_helper_ prefix. This is because when a symbol is present in both include/ and rust/helpers/, the one from include/ wins under the assumption that the current configuration is one where that helper is unnecessary. This heuristic fails for _find_next_zero_bit() because the header file always declares it even if the symbol does not exist.
The functions still use the __rust_helper annotation. This lets the wrapper function be inlined into Rust code even if full kernel LTO is not used once the patch series for that feature lands.
Cc: stable@vger.kernel.org Fixes: 6cf93a9ed39e ("rust: add bindings for bitops.h") Reported-by: Andreas Hindborg a.hindborg@kernel.org Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/x/topic/x/near/56167730... Signed-off-by: Alice Ryhl aliceryhl@google.com
Which means, you're running active testing, which in turn means that Rust is in a good shape indeed. Thanks to you and Andreas for the work.
I've put together this collection of GitHub actions jobs that build and test a few common configurations, which I used to test this: https://github.com/Darksonn/linux
Before I merge it, can you also test m68k build? Arm and m68k are the only arches implementing custom API there.
I ran a gcc build for m68k with these patches applied and it built successfully for me.
Thanks, Alice! Added in -next for testing. I'm going to send PR with the next -rc as it's a real build fix.
Dirk and everyone, please send your tags before the end of the week, if you want.
Thanks, Yury
Am 1/5/2026 um 11:44 AM schrieb Alice Ryhl:
On 32-bit ARM, you may encounter linker errors such as this one:
ld.lld: error: undefined symbol: _find_next_zero_bit
referenced by rust_binder_main.43196037ba7bcee1-cgu.0 drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a referenced by rust_binder_main.43196037ba7bcee1-cgu.0 drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a
This error occurs because even though the functions are declared by include/linux/find.h, the definition is #ifdef'd out on 32-bit ARM. This is because arch/arm/include/asm/bitops.h contains:
#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off)
And the underscore-prefixed function is conditional on #ifndef of the non-underscore-prefixed name, but the declaration in find.h is *not* conditional on that #ifndef.
To fix the linker error, we ensure that the symbols in question exist when compiling Rust code. We do this by definining them in rust/helpers/
Just a quite minor nit: typo: definining -> defining
Dirk
Alice Ryhl aliceryhl@google.com writes:
On 32-bit ARM, you may encounter linker errors such as this one:
ld.lld: error: undefined symbol: _find_next_zero_bit
referenced by rust_binder_main.43196037ba7bcee1-cgu.0 drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a referenced by rust_binder_main.43196037ba7bcee1-cgu.0 drivers/android/binder/rust_binder_main.o:(<rust_binder_main::process::Process>::insert_or_update_handle) in archive vmlinux.a
This error occurs because even though the functions are declared by include/linux/find.h, the definition is #ifdef'd out on 32-bit ARM. This is because arch/arm/include/asm/bitops.h contains:
#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off)
And the underscore-prefixed function is conditional on #ifndef of the non-underscore-prefixed name, but the declaration in find.h is *not* conditional on that #ifndef.
To fix the linker error, we ensure that the symbols in question exist when compiling Rust code. We do this by definining them in rust/helpers/ whenever the normal definition is #ifndef'd out.
Note that these helpers are somewhat unusual in that they do not have the rust_helper_ prefix that most helpers have. Adding the rust_helper_ prefix does not compile, as 'bindings::_find_next_zero_bit()' will result in a call to a symbol called _find_next_zero_bit as defined by include/linux/find.h rather than a symbol with the rust_helper_ prefix. This is because when a symbol is present in both include/ and rust/helpers/, the one from include/ wins under the assumption that the current configuration is one where that helper is unnecessary. This heuristic fails for _find_next_zero_bit() because the header file always declares it even if the symbol does not exist.
The functions still use the __rust_helper annotation. This lets the wrapper function be inlined into Rust code even if full kernel LTO is not used once the patch series for that feature lands.
Cc: stable@vger.kernel.org Fixes: 6cf93a9ed39e ("rust: add bindings for bitops.h") Reported-by: Andreas Hindborg a.hindborg@kernel.org Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/x/topic/x/near/56167730... Signed-off-by: Alice Ryhl aliceryhl@google.com
Built tested for arm32 with bindgen 0.72.1 with rustc-1.78.0 and rustc-1.88.0.
Tested-by: Andreas Hindborg a.hindborg@kernel.org
Best regards, Andreas Hindborg
linux-stable-mirror@lists.linaro.org