lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20231027003504.146703-2-yakoyoku@gmail.com>
Date:   Thu, 26 Oct 2023 21:34:50 -0300
From:   Martin Rodriguez Reboredo <yakoyoku@...il.com>
To:     Masahiro Yamada <masahiroy@...nel.org>,
        Nathan Chancellor <nathan@...nel.org>,
        Nick Desaulniers <ndesaulniers@...gle.com>,
        Nicolas Schier <nicolas@...sle.eu>,
        Miguel Ojeda <ojeda@...nel.org>,
        Alex Gaynor <alex.gaynor@...il.com>,
        Wedson Almeida Filho <wedsonaf@...il.com>,
        Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>,
        Björn Roy Baron <bjorn3_gh@...tonmail.com>,
        Benno Lossin <benno.lossin@...ton.me>,
        Andreas Hindborg <a.hindborg@...sung.com>,
        Alice Ryhl <aliceryhl@...gle.com>, Andrew Davis <afd@...com>,
        Rob Herring <robh@...nel.org>,
        Shuah Khan <skhan@...uxfoundation.org>,
        Andy Shevchenko <andriy.shevchenko@...ux.intel.com>,
        Chuck Lever <chuck.lever@...cle.com>
Cc:     linux-kbuild@...r.kernel.org, linux-kernel@...r.kernel.org,
        rust-for-linux@...r.kernel.org
Subject: [RFC PATCH v2 1/2] kbuild: Build Rust crates as libraries

Enables compiling Rust crates as dependencies of kernel modules. These
are also meant to be used as libraries for other parts of the kernel.

For these crates `bindings` is also exposed to them and they get their
symbols exported for them to be used by other code.

When a composite object depends on an `.rlib` file, which by the way is
a current ar archive, Kbuild will compile it from its base Rust source
and archive it.

This makes possible to have Rust bindings for a subsystem that is
compiled either built-in or as a module. They can also be made into
modules by themselves too.

Signed-off-by: Martin Rodriguez Reboredo <yakoyoku@...il.com>
---
v1 -> v2:
- Fixed kernel compilation.
- Added support for building crates as modules.

 .gitignore                |  2 ++
 Makefile                  |  4 ++--
 scripts/Makefile.build    | 49 +++++++++++++++++++++++++++++++++++----
 scripts/Makefile.lib      | 18 +++++++++++---
 scripts/Makefile.modfinal |  7 +++++-
 5 files changed, 70 insertions(+), 10 deletions(-)

diff --git a/.gitignore b/.gitignore
index 0bbae167bf93..8353b01e2915 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@
 *.o
 *.o.*
 *.patch
+*.rlib
 *.rmeta
 *.rpm
 *.rsi
@@ -53,6 +54,7 @@
 *.zst
 Module.symvers
 modules.order
+exports_*_generated.c
 
 #
 # Top-level generic files
diff --git a/Makefile b/Makefile
index 8a40530868ff..4113a5b93ddc 100644
--- a/Makefile
+++ b/Makefile
@@ -283,7 +283,7 @@ no-compiler-targets := $(no-dot-config-targets) install dtbs_install \
 			headers_install modules_install modules_sign kernelrelease image_name
 no-sync-config-targets := $(no-dot-config-targets) %install modules_sign kernelrelease \
 			  image_name
-single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %.symtypes %/
+single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rlib %.rsi %.s %.symtypes %/
 
 config-build	:=
 mixed-build	:=
@@ -1919,7 +1919,7 @@ $(clean-dirs):
 clean: $(clean-dirs)
 	$(call cmd,rmfiles)
 	@find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
-		\( -name '*.[aios]' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \
+		\( -name '*.[aios]' -o -name '*.rlib' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \
 		-o -name '*.ko.*' \
 		-o -name '*.dtb' -o -name '*.dtbo' \
 		-o -name '*.dtb.S' -o -name '*.dtbo.S' \
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index da37bfa97211..11045ddba1a9 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -20,6 +20,7 @@ always-m :=
 targets :=
 subdir-y :=
 subdir-m :=
+rust-libs :=
 EXTRA_AFLAGS   :=
 EXTRA_CFLAGS   :=
 EXTRA_CPPFLAGS :=
@@ -243,9 +244,13 @@ $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
 	$(call if_changed_rule,cc_o_c)
 	$(call cmd,force_checksrc)
 
+mod_objs = $(call real-search, $*.o, .o, -objs -y -m)
+exports_objs = $(foreach m, $(sort $(basename \
+	$(filter $(notdir $(rlib-m)), $(mod_objs)))), exports_$m_generated.o)
+
 # To make this rule robust against "Argument list too long" error,
 # ensure to add $(obj)/ prefix by a shell command.
-cmd_mod = printf '%s\n' $(call real-search, $*.o, .o, -objs -y -m) | \
+cmd_mod = printf '%s\n' $(mod_objs) $(exports_objs) | \
 	$(AWK) '!x[$$0]++ { print("$(obj)/"$$0) }' > $@
 
 $(obj)/%.mod: FORCE
@@ -274,7 +279,7 @@ rust_common_cmd = \
 	-Zcrate-attr='feature($(rust_allowed_features))' \
 	--extern alloc --extern kernel \
 	--crate-type rlib -L $(objtree)/rust/ \
-	--crate-name $(basename $(notdir $@)) \
+	--crate-name $(basename $(notdir $<)) \
 	--out-dir $(dir $@) --emit=dep-info=$(depfile)
 
 # `--emit=obj`, `--emit=asm` and `--emit=llvm-ir` imply a single codegen unit
@@ -285,11 +290,42 @@ rust_common_cmd = \
 # i.e. the outputs we would get for the different single targets (e.g. `.ll`)
 # would not match each other.
 
+rlib_obj = $(dir $@)$*.$*.o
+rlib_meta = $(dir $@)$(patsubst %.rlib,%.rmeta,$(notdir $@))
+
 quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
       cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $<
 
+quiet_cmd_ln_rlib_o = SYMLINK $@
+      cmd_ln_rlib_o = ln -s -f $*.$*.o $@
+
 $(obj)/%.o: $(src)/%.rs FORCE
-	$(call if_changed_dep,rustc_o_rs)
+	$(if $(findstring $@, $(rlib-y) $(rlib-m)), \
+		$(call if_changed,ln_rlib_o), $(call if_changed_dep,rustc_o_rs))
+
+quiet_cmd_rustc_rlib_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
+      cmd_rustc_rlib_rs = $(rust_common_cmd) --extern bindings \
+		--emit=obj=$(rlib_obj) --emit=metadata=$(rlib_meta) $<; \
+	rm -f $@; $(AR) cDPrST $@ $(rlib_obj) $(rlib_meta)
+
+quiet_cmd_rlib_exports = EXPORTS $@
+      cmd_rlib_exports = \
+	echo "\#include <linux/module.h>"  > $@; \
+	$(NM) -p --defined-only $(rlib_obj) \
+		| grep -P ' (T|R|D) (?!(init|cleanup)_module)' | cut -d ' ' -f 3 \
+		| xargs -Isymbol \
+		echo 'extern int symbol; EXPORT_SYMBOL_GPL(symbol);' >> $@
+
+$(rlib-m): $(obj)/%.o: $(obj)/exports_%_generated.o $(obj)/lib%.rlib $(src)/%.rs FORCE
+
+$(obj)/lib%.rlib: $(src)/%.rs FORCE
+	$(call if_changed_dep,rustc_rlib_rs)
+
+$(obj)/exports_%_generated.c: $(obj)/lib%.rlib FORCE
+	$(call if_changed,rlib_exports)
+
+$(obj)/exports_%_generated.o: $(obj)/exports_%_generated.c FORCE
+	$(call if_changed,cc_o_c)
 
 quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
       cmd_rustc_rsi_rs = \
@@ -394,9 +430,14 @@ $(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ;
 # To make this rule robust against "Argument list too long" error,
 # remove $(obj)/ prefix, and restore it by a shell command.
 
+# If we have a .rlib for the archive change it for its object member
+crate-obj = $(foreach m, $1, $(if $(findstring .rlib, $m), \
+	$(basename $(m:lib%=%)).$(m:lib%.rlib=%.o),$m))
+
 quiet_cmd_ar_builtin = AR      $@
       cmd_ar_builtin = rm -f $@; \
-	$(if $(real-prereqs), printf "$(obj)/%s " $(patsubst $(obj)/%,%,$(real-prereqs)) | xargs) \
+	$(if $(real-prereqs), printf "$(obj)/%s " \
+		$(call crate-obj, $(patsubst $(obj)/%,%,$(real-prereqs))) | xargs) \
 	$(AR) cDPrST $@
 
 $(obj)/built-in.a: $(real-obj-y) FORCE
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 68d0134bdbf9..3454b05dbbdc 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -45,12 +45,17 @@ else
 obj-y		:= $(filter-out %/, $(obj-y))
 endif
 
+rlib-y := $(foreach m, $(filter lib%.rlib, $(obj-y)), $(m:lib%.rlib=%.o))
+rlib-m := $(foreach m, $(filter lib%.rlib, $(obj-m)), $(m:lib%.rlib=%.o))
+
 # Expand $(foo-objs) $(foo-y) etc. by replacing their individuals
 suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s))))
 # List composite targets that are constructed by combining other targets
 multi-search = $(sort $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $m)))
 # List primitive targets that are compiled from source files
 real-search = $(foreach m, $1, $(if $(call suffix-search, $m, $2, $3 -), $(call suffix-search, $m, $2, $3), $m))
+# List exported symbols from .rlib targets
+rlib-exports = $(foreach m, $1, $(if $(findstring .rlib, $m),$(m:lib%.rlib=exports_%_generated.o)) $m)
 
 # If $(foo-objs), $(foo-y), $(foo-m), or $(foo-) exists, foo.o is a composite object
 multi-obj-y := $(call multi-search, $(obj-y), .o, -objs -y)
@@ -59,7 +64,7 @@ multi-obj-ym := $(multi-obj-y) $(multi-obj-m)
 
 # Replace multi-part objects by their individual parts,
 # including built-in.a from subdirectories
-real-obj-y := $(call real-search, $(obj-y), .o, -objs -y)
+real-obj-y := $(call rlib-exports, $(call real-search, $(obj-y), .o, -objs -y))
 real-obj-m := $(call real-search, $(obj-m), .o, -objs -y -m)
 
 always-y += $(always-m)
@@ -95,6 +100,8 @@ extra-y		:= $(addprefix $(obj)/,$(extra-y))
 always-y	:= $(addprefix $(obj)/,$(always-y))
 targets		:= $(addprefix $(obj)/,$(targets))
 obj-m		:= $(addprefix $(obj)/,$(obj-m))
+rlib-y		:= $(addprefix $(obj)/,$(rlib-y))
+rlib-m		:= $(addprefix $(obj)/,$(rlib-m))
 lib-y		:= $(addprefix $(obj)/,$(lib-y))
 real-obj-y	:= $(addprefix $(obj)/,$(real-obj-y))
 real-obj-m	:= $(addprefix $(obj)/,$(real-obj-m))
@@ -210,7 +217,11 @@ _cpp_flags += -I $(srctree)/$(src) -I $(objtree)/$(obj)
 endif
 endif
 
-part-of-module = $(if $(filter $(basename $@).o, $(real-obj-m)),y)
+_rust_libs = $(foreach l, $(rust-libs), -L $(obj)/$(dir $l) --extern $(notdir $(basename $l)))
+
+part-of-module =                                             \
+	$(if $(or $(filter $(basename $@).o, $(real-obj-m)), \
+		$(filter $(basename $@).rlib, $(real-obj-m))),y)
 quiet_modtag = $(if $(part-of-module),[M],   )
 
 modkern_cflags =                                          \
@@ -232,7 +243,8 @@ c_flags        = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
 		 $(_c_flags) $(modkern_cflags)                           \
 		 $(basename_flags) $(modname_flags)
 
-rust_flags     = $(_rust_flags) $(modkern_rustflags) @$(objtree)/include/generated/rustc_cfg
+rust_flags     = $(_rust_flags) $(modkern_rustflags) $(_rust_libs) \
+		 @$(objtree)/include/generated/rustc_cfg
 
 a_flags        = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
 		 $(_a_flags) $(modkern_aflags)
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index b3a6aa8fbe8c..e05749a5ca0a 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -30,11 +30,16 @@ quiet_cmd_cc_o_c = CC [M]  $@
 
 ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
 
+# Symlinks of foo.o that point to foo.foo.o are members of a .rlib archives,
+# so their exports should be added to the module
+ko_objs = $(foreach o, $(filter %.o, $^),$(if \
+	$(filter-out %$o,$(realpath $o)),$(dir $o)exports_$(notdir $*)_generated.o) $o)
+
 quiet_cmd_ld_ko_o = LD [M]  $@
       cmd_ld_ko_o +=							\
 	$(LD) -r $(KBUILD_LDFLAGS)					\
 		$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE)		\
-		-T scripts/module.lds -o $@ $(filter %.o, $^);		\
+		-T scripts/module.lds -o $@ $(ko_objs);			\
 	$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
 
 quiet_cmd_btf_ko = BTF [M] $@
-- 
2.42.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ