Skip to content

Conversation

@omatiusha
Copy link
Contributor

This PR fixes some issues discussed in #811 and #1224.
I decided to submit small changes sequentially and hold off on the --distro option.

This patch introduces ability to pick a CROSS_COMPILE
environment variable which can be used for
specifying cross-complier prefix.
It allows to build live patches not only on
target system, but also on hosts for a target other
than the one on which the compiler is running.

@rbilovol
Copy link

This PR fixes some issues discussed in #811 and #1224. I decided to submit small changes sequentially and hold off on the --distro option.

It makes sense to describe what issues have been fixed in a new patch version (e.g. what is a difference between old and new version of patch)

@omatiusha
Copy link
Contributor Author

Well, the --cross-compile option is replaced with picking a CROSS_COMPILE variable from shell environment, changes in kpatch-cc are moved to MAKEVARS in kpatch-build so kpatch-cc won't be changed, and cross-compile prefix is now added to all of the tools used, not just gcc, but also objcopy and ld.

@sm00th
Copy link
Contributor

sm00th commented Nov 2, 2021

Hi, looked into it a bit and I have a couple of questions. Where does this come from? You mentioned these patches are included in openembedded build, but do you know how is it used there? Looking at the original commit message it looks like openembedded uses it to build patches for same arch but other different variants. Is that correct? If so this might be a good first step but there is a lot more work to be done for proper cross-compilation support.

Regarding the patch itself: what is the point of KPATCH_CROSS_COMPILE variable? Why not use CROSS_COMPILE itself instead?

@omatiusha
Copy link
Contributor Author

Hi, this patch is not directly related to openembedded one, but is a prerequisite to upstream it, too, after deciding how to better implement --distro functionality from #811. This patch also allows #1234 to work on cross-compiled kernels. So I decided to split it up a bit.

Regarding KPATCH_CROSS_COMPILE - you are completely right and I`ll rework that.

@omatiusha omatiusha force-pushed the master branch 2 times, most recently from f99c5cd to 94a2f29 Compare November 2, 2021 13:27
@sm00th
Copy link
Contributor

sm00th commented Nov 2, 2021

This patch also allows #1234 to work on cross-compiled kernels.

That was the reason I was asking. Is there a working cross-compilation scenario that this patch enables? Right now kpatch-build only supports x86_64 and ppc64le, both of those have code wrapped in #ifdefs so it won't work out of the box without something like #1179.

@omatiusha
Copy link
Contributor Author

Hi, I got into the specifics of the project a little bit and now I want to resume the discussion. The project builds kernels for the same architecture, but:

  1. It uses different, custom compiler to do so, that's why we need CROSS_COMPILE or something similar to specify toolchain prefix. I think that wouldn't be confusing if properly documented;
  2. It does build kernel from source for target another than the build host, but same architecture, that's why we need to override the distro-specific checks by being able to directly set the DISTRO variable. However, option names can be a bit confusing, because there is no ability to actually cross-compile kernels for different arch. I think we can name it like --skip-distro-check or something.

What do you think about it?

@joe-lawrence
Copy link
Contributor

My kbuild understanding is that CROSS_COMPILE points to the compiler, while it's ARCH that sets the target. As @sm00th mentioned above, the code is definitely not ready for building cross-arch, but I think it could work for picking the toolset. (@sm00th : how did we handle using clang?)

I think some of the DISTRO checks could be skipped, given the user provides source dir and vmlinux files. That variable is also used during parts of the build process to do Ubuntu or RHEL specific things. I would think that should still apply if I wanted to build an Ubuntu kpatch from Gentoo? Does that suggest a TARGET_DISTRO setting :(

One more question: from the current changes, objcopy is CROSS_COMPILE prefixed. Just curious, if the project goal is keeping the arch consistent, is there some reason why the generic x86 elfutils don't work? Similarly, should some or all of the readelf invocations be similarly prefixed?

@sm00th
Copy link
Contributor

sm00th commented Dec 17, 2021

My kbuild understanding is that CROSS_COMPILE points to the compiler, while it's ARCH that sets the target.

In gcc's case this is true, but when using clang kbuild derives more info from CROSS_COMPILE:

CLANG_FLAGS     += --target=$(notdir $(CROSS_COMPILE:%-=%))
...
CLANG_FLAGS     += --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE))

As @sm00th mentioned above, the code is definitely not ready for building cross-arch, but I think it could work for picking the toolset.

I agree, even if we won't be doing real cross-compilation just yet having this stepping stone definitely won't hurt.

(@sm00th : how did we handle using clang?)

With clang we set (HOST)?CC/(HOST)?LD directly.

I think some of the DISTRO checks could be skipped, given the user provides source dir and vmlinux files. That variable is also used during parts of the build process to do Ubuntu or RHEL specific things. I would think that should still apply if I wanted to build an Ubuntu kpatch from Gentoo? Does that suggest a TARGET_DISTRO setting :(

I think we mostly ignore DISTRO variable when building from user-specified source.

One more question: from the current changes, objcopy is CROSS_COMPILE prefixed. Just curious, if the project goal is keeping the arch consistent, is there some reason why the generic x86 elfutils don't work? Similarly, should some or all of the readelf invocations be similarly prefixed?

It will probably work but the goal is to replicate target's environment, so I do think we want everything prefixed.

@omatiusha
Copy link
Contributor Author

I updated the commit.

In gcc's case this is true, but when using clang kbuild derives more info from CROSS_COMPILE

Didn't test with clang, but added cross-compile prefix in MAKEVARS for it too

With clang we set (HOST)?CC/(HOST)?LD directly.

idk if we need prefix here, so I left it untouched

I think some of the DISTRO checks could be skipped, given the user provides source dir and vmlinux files.

I implemented this variation because it was more intuitive for me

It will probably work but the goal is to replicate target's environment, so I do think we want everything prefixed.

and left everything prefixed, so I think this will work fine.

@joe-lawrence
Copy link
Contributor

Hi @omatiusha, I think this last push broke the integration tests (make integration) in the case CROSS_COMPILE is not specified:

(rhel-7.6 install)
build: meminfo-init2-FAIL
ERROR: Unsupported distribution.
build: meminfo-init-FAIL
ERROR: Unsupported distribution.
build: symvers-disagreement-FAIL
ERROR: Unsupported distribution.
build: warn-detect-FAIL
ERROR: Unsupported distribution.
combine: skipping rhel-7.6/meminfo-init2-FAIL.patch
combine: skipping rhel-7.6/meminfo-init-FAIL.patch
combine: skipping rhel-7.6/symvers-disagreement-FAIL.patch
combine: skipping rhel-7.6/warn-detect-FAIL.patch
build: combined module
ERROR: Unsupported distribution.
ERROR: combined build failed
can't find test-COMBINED.ko, skipping
ERROR: dmesg overflow, try increasing kernel log buffer size
1 errors encountered

@omatiusha
Copy link
Contributor Author

Hi @joe-lawrence, it seems to be broken due to fallback to distro-specific sources download on line 825. Should I add a fallback option for "dummy" DISTRO which checks whether CROSS_COMPILE and/or KERNEL_SRCDIR are set?

@joe-lawrence
Copy link
Contributor

Hi @joe-lawrence, it seems to be broken due to fallback to distro-specific sources download on line 825. Should I add a fallback option for "dummy" DISTRO which checks whether CROSS_COMPILE and/or KERNEL_SRCDIR are set?

Without testing, I'm not 100%, but I think the problem is that before this change DISTRO is read from the ID value that was sourced from the RELEASE_FILE. In your branch, that occurs after it is used in this conditional:

if [[ -n "$USERSRCDIR" ]] && [[ -n "$VMLINUX" ]]; then
	DISTRO="dummy"
else 
	DISTRO="$ID"  # ID is not set
fi
...
[[ -f "$RELEASE_FILE" ]] && source "$RELEASE_FILE"  # ID is set here
DISTRO="$ID"

I think that entire conditional and dummy value could be completely removed if the release file sourcing and DISTRO assignment only occurred when USERSRCDIR is not specified:

if [[ -z "$USERSRCDIR" ]] && [[ -f "$RELEASE_FILE" ]]; then
	source "$RELEASE_FILE"
	DISTRO="$ID"
fi

That should solve for:

  1. Typical distribution case, USERSRCDIR is not specified and therefore DISTRO is set
  2. This cross-build case, USERSRCDIR is specified (DISTRO is not) and the script proceeds with its existing checks on USERSRCDIR

@joe-lawrence
Copy link
Contributor

One more question: from the current changes, objcopy is CROSS_COMPILE prefixed. Just curious, if the project goal is keeping the arch consistent, is there some reason why the generic x86 elfutils don't work? Similarly, should some or all of the readelf invocations be similarly prefixed?

It will probably work but the goal is to replicate target's environment, so I do think we want everything prefixed.

So should the prefix apply to the readelf invocations as well?

@omatiusha
Copy link
Contributor Author

I think that entire conditional and dummy value could be completely removed if the release file sourcing and DISTRO assignment only occurred when USERSRCDIR is not specified

Ok, I'll try that.

So should the prefix apply to the readelf invocations as well?

Yes it is, I forgot to prepend readelf and one gcc invocation.

@joe-lawrence
Copy link
Contributor

Latest update seems to make internal integration tests happy. Later this week, I'd like to run a few tests with these changes so that we can also document how to use this.

In the meantime, a few nits with the commit message. We're not as strict as the kernel, but to tweak it to look more like the project's conventions:

  1. Use active voice and word wrap closer to 80 chars, like:
Introduce the ability to pick a CROSS_COMPILE environment variable for
specifying toolchain prefix for all gcc and binutils.  To facilitate its
use, do not set the DISTRO variable when VMLINUX and USERSRCDIR are
specified.
  1. We use Signed-off-by lines to imply that contributions are your own and open source. In this case, I think the patchset originated with @rbilovol, so at the bottom you would list like:
Signed-off-by: Ruslan Bilovol <rbilovol@cisco.com>
Signed-off-by: Oleh Matiusha <oleh.matiusha@globallogic.com>
  1. Ruslan also appears as the committer. Since you are submitting the patch, you could quickly replace with your own name with something like: git commit --amend --no-edit --reset-author

@omatiusha
Copy link
Contributor Author

Thank you very much @joe-lawrence, I've done what you suggested. I'll be waiting patiently for the test results.

@joe-lawrence
Copy link
Contributor

Okay, I ran two tests:

  1. On x86_64, with this toolchain: https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/11.1.0/x86_64-gcc-11.1.0-nolibc-x86_64-linux.tar.gz . I built a local kernel with COMPILE prefix, then used the same prefix to kpatch-build with good results. 👍

  2. On ppc64le, with: https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/ppc64le/11.1.0/ppc64le-gcc-11.1.0-nolibc-powerpc64-linux.tar.gz but ran into issues with the kpatch gcc-plugin:

  CC      scripts/mod/empty.o
cc1: error: cannot load plugin /root/kpatch/kpatch-build/gcc-plugins/ppc64le-plugin.so: /root/kpatch/kpatch-build/gcc-plugins/ppc64le-plugin.so: undefined symbol: _ZN8opt_pass14set_pass_paramEjb
make[1]: *** [scripts/Makefile.build:271: scripts/mod/empty.o] Error 1
make: *** [Makefile:1216: prepare0] Error 2
make: *** Waiting for unfinished jobs....

I get the same results, even with this small change to point to the cross-compiler's plugins include files:

diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile
index 50899b6..3b586fe 100644
--- a/kpatch-build/Makefile
+++ b/kpatch-build/Makefile
@@ -18,7 +18,7 @@ else ifeq ($(ARCH),ppc64le)
 SOURCES += gcc-plugins/ppc64le-plugin.c
 PLUGIN   = gcc-plugins/ppc64le-plugin.so
 TARGETS += $(PLUGIN)
-GCC_PLUGINS_DIR := $(shell gcc -print-file-name=plugin)
+GCC_PLUGINS_DIR := $(shell $(CROSS_COMPILE)gcc -print-file-name=plugin)
 PLUGIN_CFLAGS := $(filter-out -Wconversion, $(CFLAGS))
 PLUGIN_CFLAGS += -shared -I$(GCC_PLUGINS_DIR)/include \
                   -Igcc-plugins -fPIC -fno-rtti -O2 -Wall

I can easily reproduce this with a super small repro:

$ cat test.c
void foo() { }

$ /root/gcc-11.1.0-nolibc/powerpc64-linux/bin/powerpc64-linux-gcc test.c -fplugin=/root/kpatch/kpatch-build/gcc-plugins/ppc64le-plugin.so -c -o test.o
cc1: error: cannot load plugin /root/kpatch/kpatch-build/gcc-plugins/ppc64le-plugin.so: /root/kpatch/kpatch-build/gcc-plugins/ppc64le-plugin.so: undefined symbol: _ZN8opt_pass14set_pass_paramEjb

$ c++filt _ZN8opt_pass14set_pass_paramEjb
opt_pass::set_pass_param(unsigned int, bool)

I'm not very experienced with gcc plugins, so I'm unsure how to continue debugging this.

@omatiusha
Copy link
Contributor Author

Thank you
Unfortunately, I am not familiar with neither ppc64 nor gcc plugins. Do you compile ppc64 patch module on the same arch host (not amd64) ?
If yes then I have no proposals except for disabling this patch for ppc64 arch.

@joe-lawrence
Copy link
Contributor

Thank you Unfortunately, I am not familiar with neither ppc64 nor gcc plugins. Do you compile ppc64 patch module on the same arch host (not amd64) ? If yes then I have no proposals except for disabling this patch for ppc64 arch.

Yes in the ppc64le case, I was building on a powerpc host using the alternate compiler from crosstool mentioned above. I'll give the IBM Advance Toolchain for Linux on Power a try and hope to have better luck with that.

As far x86_64 goes, the patchset it probably all set... I'd like to figure out what it takes to get ppc64le working, too, since we may have interest in cross-compiling from x86_64 to ppc64le one day.

@jpoimboe
Copy link
Member

@joe-lawrence Does this help?

diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile
index 50899b6..ddcd2cb 100644
--- a/kpatch-build/Makefile
+++ b/kpatch-build/Makefile
@@ -36,7 +36,7 @@ create-klp-module: create-klp-module.o kpatch-elf.o
 create-kpatch-module: create-kpatch-module.o kpatch-elf.o
 
 $(PLUGIN): gcc-plugins/ppc64le-plugin.c
-	g++ $(PLUGIN_CFLAGS) $< -o $@
+	$(CROSS_COMPILE)g++ $(PLUGIN_CFLAGS) $< -o $@
 
 install: all
 	$(INSTALL) -d $(LIBEXECDIR)

@joe-lawrence
Copy link
Contributor

@joe-lawrence Does this help?

diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile
index 50899b6..ddcd2cb 100644
--- a/kpatch-build/Makefile
+++ b/kpatch-build/Makefile
@@ -36,7 +36,7 @@ create-klp-module: create-klp-module.o kpatch-elf.o
 create-kpatch-module: create-kpatch-module.o kpatch-elf.o
 
 $(PLUGIN): gcc-plugins/ppc64le-plugin.c
-	g++ $(PLUGIN_CFLAGS) $< -o $@
+	$(CROSS_COMPILE)g++ $(PLUGIN_CFLAGS) $< -o $@
 
 install: all
 	$(INSTALL) -d $(LIBEXECDIR)

Ok, that revealed that the cross compilers that Arnd posts up on https://mirrors.edge.kernel.org/pub/tools/crosstool/ don't include g++.

As far setting the cross compiler prefix, I had not seen other examples cross compile the plugin itself. Would that make sense if I was targeting a different arch?

I did give the IBM compiler a spin, and it does build my toy test.c example with only the header file path updated. But then the kernel build doesn't seem to like its linker. So I'm willing to believe that the problem was in the incomplete toolchain I was trying to use. Since there would be more cross compilation (and arch) work to do, I'm fine approving this change and completing the rest as needed.

@jpoimboe
Copy link
Member

Oh right, I guess it doesn't make sense to cross-compile the gcc plugin.

gcc_version_from_file() {
readelf -p .comment "$1" | grep -m 1 -o 'GCC:.*'
"$CROSS_COMPILE"readelf -p .comment "$1" | grep -m 1 -o 'GCC:.*'
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang_version_from_file() and clang_version_check() are missing CROSS_COMPILE.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, instead of sprinkling CROSS_COMPILE everywhere, it may be cleaner to just have GCC, CLANG, READELF, OBJCOPY, LD, LD_LLD variables defined at the top of the file to include CROSS_COMPILE.

(As a further eventual cleanup we might want to just have CC and LD variables instead of GCC/CLANG/LD/LD_LLD, but that might be a little tricky since it depends on the config file, and maybe can be done later.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not know if these changes work with clang as well, so I can add them at our own risk

DISTRO="$ID"
fi


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one newline here please, for consistency with the rest of the file.

rm -f "$LOGFILE"



Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary newlines added.

@jpoimboe
Copy link
Member

So I'm willing to believe that the problem was in the incomplete toolchain I was trying to use. Since there would be more cross compilation (and arch) work to do, I'm fine approving this change and completing the rest as needed.

Agreed

@sm00th
Copy link
Contributor

sm00th commented Jan 17, 2022

As far setting the cross compiler prefix, I had not seen other examples cross compile the plugin itself. Would that make sense if I was targeting a different arch?

I had previous run-ins with this and we definitely don't want the plugin to be built with a cross-compiler. We need it to be built for the host architecture against cross-compiler's headers and linked against it. I believe our makefile should achieve this already, will make sure tomorrow.

@sm00th
Copy link
Contributor

sm00th commented Jan 18, 2022

Ok, that revealed that the cross compilers that Arnd posts up on https://mirrors.edge.kernel.org/pub/tools/crosstool/ don't include g++.

That is it, I've tried this on fedora35 with gcc-c++-ppc64-linux-gnu gcc-ppc64-linux-gnu installed and your testcase works fine.
We do need your fix though.

@omatiusha could you please add the GCC_PLUGINS_DIR change from Joe's comment

@omatiusha
Copy link
Contributor Author

Sure. Should I add also this? I did not test cross compilation on clang.

@sm00th
Copy link
Contributor

sm00th commented Jan 18, 2022

Sure. Should I add also this? I did not test cross compilation on clang.

Yes, even if it breaks we can fix clang later. We only support it experimentally anyway.

@jpoimboe
Copy link
Member

@omatiusha I think you missed one of my comments:

Also, instead of sprinkling CROSS_COMPILE everywhere, it may be cleaner to just have GCC, CLANG, READELF, OBJCOPY, LD, LD_LLD variables defined at the top of the file to include CROSS_COMPILE.

e.g, something like this at the top:

index 193a42e..9155a4d 100755
--- a/kpatch-build/kpatch-build
+++ b/kpatch-build/kpatch-build
@@ -58,6 +58,13 @@ APPLIED_PATCHES=0
 OOT_MODULE=
 KLP_REPLACE=1
 
+GCC="{$CROSS_COMPILE:-}gcc"
+CLANG="{$CROSS_COMPILE:-}clang"
+LD="{$CROSS_COMPILE:-}ld"
+LLD="{$CROSS_COMPILE:-}lld"
+READELF="{$CROSS_COMPILE:-}readelf"
+OBJCOPY="{$CROSS_COMPILE:-}objcopy"
+
 warn() {
        echo "ERROR: $1" >&2
 }

Introduce the ability to pick a CROSS_COMPILE environment variable for
specifying toolchain prefix for all gcc and binutils. To facilitate its
use, do not set the DISTRO variable when USERSRCDIR is specified.

Signed-off-by: Ruslan Bilovol <rbilovol@cisco.com>
Signed-off-by: Oleh Matiusha <oleh.matiusha@globallogic.com>
Ignore distro-specific checks if kernel source directory is supplied as a
command line argument to remove the distro-specific tunings during
cross-compilation.

Signed-off-by: Ruslan Bilovol <rbilovol@cisco.com>
Signed-off-by: Oleh Matiusha <oleh.matiusha@globallogic.com>
@omatiusha
Copy link
Contributor Author

@jpoimboe thanks, all is ready, your diff had typos in $ positions but I tested the fixed version and all seems to work fine.

@joe-lawrence joe-lawrence merged commit 110e196 into dynup:master Feb 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants