rust: export zerocopy symbols to modules
Alexandre Courbot
reviewerPATCH 1/1 rust: export zerocopy symbols to modules
Non-generic, non-inlined functions of the zerocopy crate are only codegen'd into zerocopy.o, with their symbols currently not exported, making them unavailable to loadable modules.
This can break e.g. nova-core built as a module when CONFIG_CC_OPTIMIZE_FOR_SIZE=y:
ERROR: modpost: "_RNvMNtCs5wX7wwEUCR9_8zerocopy6layoutNtB2_8SizeInfo24try_to_nonzero_elem_size" [drivers/gpu/nova-core.ko] undefined!
ERROR: modpost: "_RNvNtCs5wX7wwEUCR9_8zerocopy4util18padding_needed_for" [drivers/gpu/nova-core.ko] undefined!
Fix this by generating and including exports for zerocopy.o, similarly to what is already done for kernel.o. All defined symbols (~12 in total) are exported since the compiler gives no guarantee as to which functions are codegen'd.
---
My CONFIG_CC_OPTIMIZE_FOR_SIZE=y config is uncovering the most interesting bugs. :) This one was revealed after applying [1].
I am not a build system expert at all, so be aware that the patch is mostly mimicking what I am seeing for the kernel crate and there might be a better way.
[1] https://lore.kernel.org/[email protected]
--- rust/Makefile | 4 ++++ rust/exports.c | 1 + 2 files changed, 5 insertions(+)
rust/Makefile +4 -0
@@ -7,6 +7,7 @@ obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o always-$(CONFIG_RUST) += exports_core_generated.h obj-$(CONFIG_RUST) += zerocopy.o +always-$(CONFIG_RUST) += exports_zerocopy_generated.h ifdef CONFIG_RUST_INLINE_HELPERS always-$(CONFIG_RUST) += helpers/helpers.bc helpers/helpers_module.bc
@@ -566,6 +567,9 @@ $(obj)/exports_bindings_generated.h: $(obj)/bindings.o FORCE $(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE $(call if_changed,exports) +$(obj)/exports_zerocopy_generated.h: $(obj)/zerocopy.o FORCE + $(call if_changed,exports) + quiet_cmd_rustc_procmacrolibrary = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) PL $@ cmd_rustc_procmacrolibrary = \ $(rustc_target_envs) \
rust/exports.c +1 -0
@@ -18,6 +18,7 @@#include "exports_core_generated.h" #include "exports_bindings_generated.h" #include "exports_kernel_generated.h" +#include "exports_zerocopy_generated.h" #ifndef CONFIG_RUST_INLINE_HELPERS #include "exports_helpers_generated.h"
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260708-zerocopy-export-e6d29c42386c
Best regards,
Signature · 1 line
Alexandre Courbot <[email protected]>
Quoted 4 lines · Alexandre Courbot
Non-generic, non-inlined functions of the
zerocopycrate are only codegen'd intozerocopy.o, with their symbols currently not exported, making them unavailable to loadable modules.
Ah, in that case, yeah, we definitely need this.
Quoted 2 lines
My
CONFIG_CC_OPTIMIZE_FOR_SIZE=yconfig is uncovering the most interesting bugs. :) This one was revealed after applying [1].
Yeah, it is a bit painful. I will add it to my set.
Quoted 1 line
I am not a build system expert at all, so be aware that the patch is
No one really is... :) (Unless you are named Masahiro!)
I think I will route this one via rust-fixes.
Cheers,
Miguel
Gary Guo
reviewerQuoted 9 lines · Alexandre Courbot
Non-generic, non-inlined functions of the
zerocopycrate are only codegen'd intozerocopy.o, with their symbols currently not exported, making them unavailable to loadable modules.This can break e.g. nova-core built as a module when
CONFIG_CC_OPTIMIZE_FOR_SIZE=y:ERROR: modpost: "
_RNvMNtCs5wX7wwEUCR9_8zerocopy6layoutNtB2_8SizeInfo24try_to_nonzero_elem_size" [drivers/gpu/nova-core.ko] undefined!
ERROR: modpost: "_RNvNtCs5wX7wwEUCR9_8zerocopy4util18padding_needed_for" [drivers/gpu/nova-core.ko] undefined!
It looks to me that this should be done by fixing zerocopy.
Both these functions should be marked as #[inline]. I would expect zerocopy.o to be having no .text.
Instead of exporting this, I would vouch for going to another extreme -- completely leave zerocopy.o unlinked, so we catch cases where code is actually generated.
Best,
Gary
Quoted 20 lines
Fix this by generating and including exports for
zerocopy.o, similarly to what is already done forkernel.o. All defined symbols (~12 in total) are exported since the compiler gives no guarantee as to which functions are codegen'd.Signed-off-by Alexandre Courbot <[email protected]>---
MyCONFIG_CC_OPTIMIZE_FOR_SIZE=yconfig is uncovering the most interesting bugs. :) This one was revealed after applying [1].I am not a build system expert at all, so be aware that the patch is mostly mimicking what I am seeing for the kernel crate and there might be a better way.
[1] https://lore.kernel.org/[email protected]
--- rust/Makefile | 4 ++++ rust/exports.c | 1 + 2 files changed, 5 insertions(+)
Quoted 9 lines · Gary Guo
It looks to me that this should be done by fixing zerocopy.
Both these functions should be marked as
#[inline]. I would expect zerocopy.o to be having no .text.Instead of exporting this, I would vouch for going to another extreme -- completely leave zerocopy.o unlinked, so we catch cases where code is actually generated.
Cc'ing Joshua and Jack -- context here:
https://lore.kernel.org/rust-for-linux/[email protected]/
Cheers,
Miguel
A message that is not in the archive (sent off-list or not yet received): CAPvrYMF3L0x5PBJk2TnSPyi0Lci2H0vGBu6QS_Rm4XFQtTV6mw@mail.gmail.com
Quoted 2 lines · Joshua Liebow-Feeser
What's the list of symbols that you'd like to be marked
#[inline]? It'd be easy for us to add that upstream.
Thanks for the reply! Gary sent a reply here:
https://lore.kernel.org/rust-for-linux/[email protected]/
Cheers,
Miguel
Gary Guo
reviewerQuoted 16 lines · Gary Guo
Quoted 9 lines · Alexandre Courbot
Non-generic, non-inlined functions of the
zerocopycrate are only codegen'd intozerocopy.o, with their symbols currently not exported, making them unavailable to loadable modules.This can break e.g. nova-core built as a module when
CONFIG_CC_OPTIMIZE_FOR_SIZE=y:ERROR: modpost: "
_RNvMNtCs5wX7wwEUCR9_8zerocopy6layoutNtB2_8SizeInfo24try_to_nonzero_elem_size" [drivers/gpu/nova-core.ko] undefined!
ERROR: modpost: "_RNvNtCs5wX7wwEUCR9_8zerocopy4util18padding_needed_for" [drivers/gpu/nova-core.ko] undefined!It looks to me that this should be done by fixing zerocopy.
Both these functions should be marked as
#[inline]. I would expect zerocopy.o to be having no .text.
Quoted 7 lines
Instead of exporting this, I would vouch for going to another extreme -- completely leave zerocopy.o unlinked, so we catch cases where code is actually generated.
Best,
Gary
This should do the trick. The only other unexported symbols are f32_ext and f64_ext, which we never use. We can mark them as #[inline(always)] as well, but figuring out how to compile them out completely might be better.
rust/Makefile +1 -1
@@ -6,7 +6,7 @@ rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o always-$(CONFIG_RUST) += exports_core_generated.h -obj-$(CONFIG_RUST) += zerocopy.o +always-$(CONFIG_RUST) += zerocopy.o ifdef CONFIG_RUST_INLINE_HELPERS always-$(CONFIG_RUST) += helpers/helpers.bc helpers/helpers_module.bc
rust/zerocopy/src/layout.rs +1 -0
@@ -71,6 +71,7 @@ impl SizeInfo {/// Attempts to create a `SizeInfo` from `Self` in which `elem_size` is a /// `NonZeroUsize`. If `elem_size` is 0, returns `None`. #[allow(unused)] +#[inline(always)] const fn try_to_nonzero_elem_size (&self) ->Option <SizeInfo <NonZeroUsize >> {Some (match *self {SizeInfo ::Sized { size } =>SizeInfo ::Sized { size },
rust/zerocopy/src/util/mod.rs +3 -0
@@ -150,6 +150,7 @@ pub(crate) fn validate_aligned_to<T: AsAddress, U>(t: T) -> Result<(), Alignment// Ensures that we add the minimum required padding. kani::ensures(|&p| p < align.get()), )] +#[inline(always)] pub (crate )const fn padding_needed_for (len:usize , align:NonZeroUsize ) ->usize {#[cfg(kani)] #[kani::proof_for_contract(padding_needed_for)]
@@ -251,6 +252,7 @@ fn proof() { n & mask } +#[inline(always)] pub (crate )const fn max (a:NonZeroUsize , b:NonZeroUsize ) ->NonZeroUsize {if a.get () < b.get () { b
@@ -259,6 +261,7 @@ pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize { } } +#[inline(always)] pub (crate )const fn min (a:NonZeroUsize , b:NonZeroUsize ) ->NonZeroUsize {if a.get () > b.get () { b