Hi all,
This series is a backport of upstream commit e89c2e815e76 ("riscv: Handle zicsr/zifencei issues between clang and binutils") to linux-5.10.y, with the necessary machinery for CONFIG_AS_IS_GNU and CONFIG_AS_VERSION, which that commit requires.
While the middle two patches are not strictly necessary, they are good clean ups that ensure consistency with mainline. The first three changes are already present in 5.15, so there is no risk of a regression moving forward.
If there are any issues, please let me know.
NOTE: I am sending this series with 'b4 send', as that is what I am used to at this point. Please accept my apologies if this causes any issues.
--- Masahiro Yamada (2): kbuild: check the minimum assembler version in Kconfig kbuild: check CONFIG_AS_IS_LLVM instead of LLVM_IAS
Nathan Chancellor (2): kbuild: Switch to 'f' variants of integrated assembler flag riscv: Handle zicsr/zifencei issues between clang and binutils
Makefile | 8 +++--- arch/riscv/Kconfig | 22 ++++++++++++++++ arch/riscv/Makefile | 12 +++++---- init/Kconfig | 12 +++++++++ scripts/Kconfig.include | 6 +++++ scripts/as-version.sh | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ scripts/dummy-tools/gcc | 6 +++++ 7 files changed, 127 insertions(+), 8 deletions(-) --- base-commit: ca9787bdecfa2174b0a169a54916e22b89b0ef5b change-id: 20230328-riscv-zifencei-zicsr-5-10-65596f2cac9e
Best regards,
From: Masahiro Yamada masahiroy@kernel.org
commit ba64beb17493a4bfec563100c86a462a15926f24 upstream.
Documentation/process/changes.rst defines the minimum assembler version (binutils version), but we have never checked it in the build time.
Kbuild never invokes 'as' directly because all assembly files in the kernel tree are *.S, hence must be preprocessed. I do not expect raw assembly source files (*.s) would be added to the kernel tree.
Therefore, we always use $(CC) as the assembler driver, and commit aa824e0c962b ("kbuild: remove AS variable") removed 'AS'. However, we are still interested in the version of the assembler acting behind.
As usual, the --version option prints the version string.
$ as --version | head -n 1 GNU assembler (GNU Binutils for Ubuntu) 2.35.1
But, we do not have $(AS). So, we can add the -Wa prefix so that $(CC) passes --version down to the backing assembler.
$ gcc -Wa,--version | head -n 1 gcc: fatal error: no input files compilation terminated.
OK, we need to input something to satisfy gcc.
$ gcc -Wa,--version -c -x assembler /dev/null -o /dev/null | head -n 1 GNU assembler (GNU Binutils for Ubuntu) 2.35.1
The combination of Clang and GNU assembler works in the same way:
$ clang -no-integrated-as -Wa,--version -c -x assembler /dev/null -o /dev/null | head -n 1 GNU assembler (GNU Binutils for Ubuntu) 2.35.1
Clang with the integrated assembler fails like this:
$ clang -integrated-as -Wa,--version -c -x assembler /dev/null -o /dev/null | head -n 1 clang: error: unsupported argument '--version' to option 'Wa,'
For the last case, checking the error message is fragile. If the proposal for -Wa,--version support [1] is accepted, this may not be even an error in the future.
One easy way is to check if -integrated-as is present in the passed arguments. We did not pass -integrated-as to CLANG_FLAGS before, but we can make it explicit.
Nathan pointed out -integrated-as is the default for all of the architectures/targets that the kernel cares about, but it goes along with "explicit is better than implicit" policy. [2]
With all this in my mind, I implemented scripts/as-version.sh to check the assembler version in Kconfig time.
$ scripts/as-version.sh gcc GNU 23501 $ scripts/as-version.sh clang -no-integrated-as GNU 23501 $ scripts/as-version.sh clang -integrated-as LLVM 0
[1]: https://github.com/ClangBuiltLinux/linux/issues/1320 [2]: https://lore.kernel.org/linux-kbuild/20210307044253.v3h47ucq6ng25iay@archlin...
Signed-off-by: Masahiro Yamada masahiroy@kernel.org Reviewed-by: Nathan Chancellor nathan@kernel.org [nathan: Backport to 5.10. Drop minimum version checking, as it is not required in 5.10] Signed-off-by: Nathan Chancellor nathan@kernel.org --- Makefile | 4 ++- init/Kconfig | 12 +++++++++ scripts/Kconfig.include | 6 +++++ scripts/as-version.sh | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ scripts/dummy-tools/gcc | 6 +++++ 5 files changed, 96 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index 71caf5938361..44d9aff4f66a 100644 --- a/Makefile +++ b/Makefile @@ -580,7 +580,9 @@ endif ifneq ($(GCC_TOOLCHAIN),) CLANG_FLAGS += --gcc-toolchain=$(GCC_TOOLCHAIN) endif -ifneq ($(LLVM_IAS),1) +ifeq ($(LLVM_IAS),1) +CLANG_FLAGS += -integrated-as +else CLANG_FLAGS += -no-integrated-as endif CLANG_FLAGS += -Werror=unknown-warning-option diff --git a/init/Kconfig b/init/Kconfig index eba883d6d9ed..9807c66b24bb 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -47,6 +47,18 @@ config CLANG_VERSION int default $(shell,$(srctree)/scripts/clang-version.sh $(CC))
+config AS_IS_GNU + def_bool $(success,test "$(as-name)" = GNU) + +config AS_IS_LLVM + def_bool $(success,test "$(as-name)" = LLVM) + +config AS_VERSION + int + # Use clang version if this is the integrated assembler + default CLANG_VERSION if AS_IS_LLVM + default $(as-version) + config LLD_VERSION int default $(shell,$(srctree)/scripts/lld-version.sh $(LD)) diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include index a5fe72c504ff..6d37cb780452 100644 --- a/scripts/Kconfig.include +++ b/scripts/Kconfig.include @@ -42,6 +42,12 @@ $(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found) # Fail if the linker is gold as it's not capable of linking the kernel proper $(error-if,$(success, $(LD) -v | grep -q gold), gold linker '$(LD)' not supported)
+# Get the assembler name, version, and error out if it is not supported. +as-info := $(shell,$(srctree)/scripts/as-version.sh $(CC) $(CLANG_FLAGS)) +$(error-if,$(success,test -z "$(as-info)"),Sorry$(comma) this assembler is not supported.) +as-name := $(shell,set -- $(as-info) && echo $1) +as-version := $(shell,set -- $(as-info) && echo $2) + # machine bit flags # $(m32-flag): -m32 if the compiler supports it, or an empty string otherwise. # $(m64-flag): -m64 if the compiler supports it, or an empty string otherwise. diff --git a/scripts/as-version.sh b/scripts/as-version.sh new file mode 100755 index 000000000000..851dcb8a0e68 --- /dev/null +++ b/scripts/as-version.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# +# Print the assembler name and its version in a 5 or 6-digit form. +# Also, perform the minimum version check. +# (If it is the integrated assembler, return 0 as the version, and +# skip the version check.) + +set -e + +# Convert the version string x.y.z to a canonical 5 or 6-digit form. +get_canonical_version() +{ + IFS=. + set -- $1 + + # If the 2nd or 3rd field is missing, fill it with a zero. + # + # The 4th field, if present, is ignored. + # This occurs in development snapshots as in 2.35.1.20201116 + echo $((10000 * $1 + 100 * ${2:-0} + ${3:-0})) +} + +# Clang fails to handle -Wa,--version unless -no-integrated-as is given. +# We check -(f)integrated-as, expecting it is explicitly passed in for the +# integrated assembler case. +check_integrated_as() +{ + while [ $# -gt 0 ]; do + if [ "$1" = -integrated-as -o "$1" = -fintegrated-as ]; then + # For the intergrated assembler, we do not check the + # version here. It is the same as the clang version, and + # it has been already checked by scripts/cc-version.sh. + echo LLVM 0 + exit 0 + fi + shift + done +} + +check_integrated_as "$@" + +orig_args="$@" + +# Get the first line of the --version output. +IFS=' +' +set -- $(LC_ALL=C "$@" -Wa,--version -c -x assembler /dev/null -o /dev/null 2>/dev/null) + +# Split the line on spaces. +IFS=' ' +set -- $1 + +if [ "$1" = GNU -a "$2" = assembler ]; then + shift $(($# - 1)) + version=$1 + name=GNU +else + echo "$orig_args: unknown assembler invoked" >&2 + exit 1 +fi + +# Some distributions append a package release number, as in 2.34-4.fc32 +# Trim the hyphen and any characters that follow. +version=${version%-*} + +cversion=$(get_canonical_version $version) + +echo $name $cversion diff --git a/scripts/dummy-tools/gcc b/scripts/dummy-tools/gcc index 346757a87dbc..485427f40dba 100755 --- a/scripts/dummy-tools/gcc +++ b/scripts/dummy-tools/gcc @@ -67,6 +67,12 @@ if arg_contain -E "$@"; then fi fi
+# To set CONFIG_AS_IS_GNU +if arg_contain -Wa,--version "$@"; then + echo "GNU assembler (scripts/dummy-tools) 2.50" + exit 0 +fi + if arg_contain -S "$@"; then # For scripts/gcc-x86-*-has-stack-protector.sh if arg_contain -fstack-protector "$@"; then
commit 2185a7e4b0ade86c2c57fc63d4a7535c40254bd0 upstream.
It has been brought up a few times in various code reviews that clang 3.5 introduced -f{,no-}integrated-as as the preferred way to enable and disable the integrated assembler, mentioning that -{no-,}integrated-as are now considered legacy flags.
Switch the kernel over to using those variants in case there is ever a time where clang decides to remove the non-'f' variants of the flag.
Also, fix a typo in a comment ("intergrated" -> "integrated").
Link: https://releases.llvm.org/3.5.0/tools/clang/docs/ReleaseNotes.html#new-compi... Reviewed-by: Nick Desaulniers ndesaulniers@google.com Signed-off-by: Nathan Chancellor nathan@kernel.org Signed-off-by: Masahiro Yamada masahiroy@kernel.org [nathan: Backport to 5.10] Signed-off-by: Nathan Chancellor nathan@kernel.org --- Makefile | 4 ++-- scripts/as-version.sh | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/Makefile b/Makefile index 44d9aff4f66a..1272e482abbe 100644 --- a/Makefile +++ b/Makefile @@ -581,9 +581,9 @@ ifneq ($(GCC_TOOLCHAIN),) CLANG_FLAGS += --gcc-toolchain=$(GCC_TOOLCHAIN) endif ifeq ($(LLVM_IAS),1) -CLANG_FLAGS += -integrated-as +CLANG_FLAGS += -fintegrated-as else -CLANG_FLAGS += -no-integrated-as +CLANG_FLAGS += -fno-integrated-as endif CLANG_FLAGS += -Werror=unknown-warning-option KBUILD_CFLAGS += $(CLANG_FLAGS) diff --git a/scripts/as-version.sh b/scripts/as-version.sh index 851dcb8a0e68..532270bd4b7e 100755 --- a/scripts/as-version.sh +++ b/scripts/as-version.sh @@ -21,14 +21,14 @@ get_canonical_version() echo $((10000 * $1 + 100 * ${2:-0} + ${3:-0})) }
-# Clang fails to handle -Wa,--version unless -no-integrated-as is given. -# We check -(f)integrated-as, expecting it is explicitly passed in for the +# Clang fails to handle -Wa,--version unless -fno-integrated-as is given. +# We check -fintegrated-as, expecting it is explicitly passed in for the # integrated assembler case. check_integrated_as() { while [ $# -gt 0 ]; do - if [ "$1" = -integrated-as -o "$1" = -fintegrated-as ]; then - # For the intergrated assembler, we do not check the + if [ "$1" = -fintegrated-as ]; then + # For the integrated assembler, we do not check the # version here. It is the same as the clang version, and # it has been already checked by scripts/cc-version.sh. echo LLVM 0
From: Masahiro Yamada masahiroy@kernel.org
commit 52cc02b910284d6bddba46cce402044ab775f314 upstream.
LLVM_IAS is the user interface to set the -(no-)integrated-as flag, and it should be used only for that purpose.
LLVM_IAS is checked in some places to determine the assembler type, but it is not precise.
For example,
$ make CC=gcc LLVM_IAS=1
... will use the GNU assembler (i.e. binutils) since LLVM_IAS=1 is effective only when $(CC) is clang.
Of course, 'CC=gcc LLVM_IAS=1' is an odd combination, but the build system can be more robust against such insane input.
Commit ba64beb17493a ("kbuild: check the minimum assembler version in Kconfig") introduced CONFIG_AS_IS_GNU/LLVM, which is more precise because Kconfig checks the version string from the assembler in use.
Signed-off-by: Masahiro Yamada masahiroy@kernel.org Reviewed-by: Nick Desaulniers ndesaulniers@google.com Reviewed-by: Nathan Chancellor nathan@kernel.org [nathan: Backport to 5.10] Signed-off-by: Nathan Chancellor nathan@kernel.org --- Makefile | 2 +- arch/riscv/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile index 1272e482abbe..3dfacb6fa973 100644 --- a/Makefile +++ b/Makefile @@ -851,7 +851,7 @@ else DEBUG_CFLAGS += -g endif
-ifeq ($(LLVM_IAS),1) +ifdef CONFIG_AS_IS_LLVM KBUILD_AFLAGS += -g else KBUILD_AFLAGS += -Wa,-gdwarf-2 diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 9446282b52ba..14cdeaa2bb32 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -40,7 +40,7 @@ ifeq ($(CONFIG_LD_IS_LLD),y) ifeq ($(shell test $(CONFIG_LLD_VERSION) -lt 150000; echo $$?),0) KBUILD_CFLAGS += -mno-relax KBUILD_AFLAGS += -mno-relax -ifneq ($(LLVM_IAS),1) +ifndef CONFIG_AS_IS_LLVM KBUILD_CFLAGS += -Wa,-mno-relax KBUILD_AFLAGS += -Wa,-mno-relax endif
commit e89c2e815e76471cb507bd95728bf26da7976430 upstream.
There are two related issues that appear in certain combinations with clang and GNU binutils.
The first occurs when a version of clang that supports zicsr or zifencei via '-march=' [1] (i.e, >= 17.x) is used in combination with a version of GNU binutils that do not recognize zicsr and zifencei in the '-march=' value (i.e., < 2.36):
riscv64-linux-gnu-ld: -march=rv64i2p0_m2p0_a2p0_c2p0_zicsr2p0_zifencei2p0: Invalid or unknown z ISA extension: 'zifencei' riscv64-linux-gnu-ld: failed to merge target specific data of file fs/efivarfs/file.o riscv64-linux-gnu-ld: -march=rv64i2p0_m2p0_a2p0_c2p0_zicsr2p0_zifencei2p0: Invalid or unknown z ISA extension: 'zifencei' riscv64-linux-gnu-ld: failed to merge target specific data of file fs/efivarfs/super.o
The second occurs when a version of clang that does not support zicsr or zifencei via '-march=' (i.e., <= 16.x) is used in combination with a version of GNU as that defaults to a newer ISA base spec, which requires specifying zicsr and zifencei in the '-march=' value explicitly (i.e, >= 2.38):
../arch/riscv/kernel/kexec_relocate.S: Assembler messages: ../arch/riscv/kernel/kexec_relocate.S:147: Error: unrecognized opcode `fence.i', extension `zifencei' required clang-12: error: assembler command failed with exit code 1 (use -v to see invocation)
This is the same issue addressed by commit 6df2a016c0c8 ("riscv: fix build with binutils 2.38") (see [2] for additional information) but older versions of clang miss out on it because the cc-option check fails:
clang-12: error: invalid arch name 'rv64imac_zicsr_zifencei', unsupported standard user-level extension 'zicsr' clang-12: error: invalid arch name 'rv64imac_zicsr_zifencei', unsupported standard user-level extension 'zicsr'
To resolve the first issue, only attempt to add zicsr and zifencei to the march string when using the GNU assembler 2.38 or newer, which is when the default ISA spec was updated, requiring these extensions to be specified explicitly. LLVM implements an older version of the base specification for all currently released versions, so these instructions are available as part of the 'i' extension. If LLVM's implementation is updated in the future, a CONFIG_AS_IS_LLVM condition can be added to CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI.
To resolve the second issue, use version 2.2 of the base ISA spec when using an older version of clang that does not support zicsr or zifencei via '-march=', as that is the spec version most compatible with the one clang/LLVM implements and avoids the need to specify zicsr and zifencei explicitly due to still being a part of 'i'.
[1]: https://github.com/llvm/llvm-project/commit/22e199e6afb1263c943c0c0d4498694e... [2]: https://lore.kernel.org/ZAxT7T9Xy1Fo3d5W@aurel32.net/
Cc: stable@vger.kernel.org Link: https://github.com/ClangBuiltLinux/linux/issues/1808 Co-developed-by: Conor Dooley conor.dooley@microchip.com Signed-off-by: Conor Dooley conor.dooley@microchip.com Signed-off-by: Nathan Chancellor nathan@kernel.org Acked-by: Conor Dooley conor.dooley@microchip.com Link: https://lore.kernel.org/r/20230313-riscv-zicsr-zifencei-fiasco-v1-1-dd1b7840... Signed-off-by: Palmer Dabbelt palmer@rivosinc.com Signed-off-by: Nathan Chancellor nathan@kernel.org --- arch/riscv/Kconfig | 22 ++++++++++++++++++++++ arch/riscv/Makefile | 10 ++++++---- 2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 557c4a8c4087..c192bd7305dc 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -331,6 +331,28 @@ config RISCV_BASE_PMU
endmenu
+config TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI + def_bool y + # https://sourceware.org/git/?p=binutils-gdb.git%3Ba=commit%3Bh=aed44286efa8ae... + depends on AS_IS_GNU && AS_VERSION >= 23800 + help + Newer binutils versions default to ISA spec version 20191213 which + moves some instructions from the I extension to the Zicsr and Zifencei + extensions. + +config TOOLCHAIN_NEEDS_OLD_ISA_SPEC + def_bool y + depends on TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI + # https://github.com/llvm/llvm-project/commit/22e199e6afb1263c943c0c0d4498694e... + depends on CC_IS_CLANG && CLANG_VERSION < 170000 + help + Certain versions of clang do not support zicsr and zifencei via -march + but newer versions of binutils require it for the reasons noted in the + help text of CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI. This + option causes an older ISA spec compatible with these older versions + of clang to be passed to GAS, which has the same result as passing zicsr + and zifencei to -march. + config FPU bool "FPU support" default y diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 14cdeaa2bb32..daa679440000 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -53,10 +53,12 @@ riscv-march-$(CONFIG_ARCH_RV64I) := rv64ima riscv-march-$(CONFIG_FPU) := $(riscv-march-y)fd riscv-march-$(CONFIG_RISCV_ISA_C) := $(riscv-march-y)c
-# Newer binutils versions default to ISA spec version 20191213 which moves some -# instructions from the I extension to the Zicsr and Zifencei extensions. -toolchain-need-zicsr-zifencei := $(call cc-option-yn, -march=$(riscv-march-y)_zicsr_zifencei) -riscv-march-$(toolchain-need-zicsr-zifencei) := $(riscv-march-y)_zicsr_zifencei +ifdef CONFIG_TOOLCHAIN_NEEDS_OLD_ISA_SPEC +KBUILD_CFLAGS += -Wa,-misa-spec=2.2 +KBUILD_AFLAGS += -Wa,-misa-spec=2.2 +else +riscv-march-$(CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI) := $(riscv-march-y)_zicsr_zifencei +endif
KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y)) KBUILD_AFLAGS += -march=$(riscv-march-y)
Gentle ping, did this get lost?
On Tue, Mar 28, 2023 at 05:08:28PM -0700, Nathan Chancellor wrote:
Hi all,
This series is a backport of upstream commit e89c2e815e76 ("riscv: Handle zicsr/zifencei issues between clang and binutils") to linux-5.10.y, with the necessary machinery for CONFIG_AS_IS_GNU and CONFIG_AS_VERSION, which that commit requires.
While the middle two patches are not strictly necessary, they are good clean ups that ensure consistency with mainline. The first three changes are already present in 5.15, so there is no risk of a regression moving forward.
If there are any issues, please let me know.
NOTE: I am sending this series with 'b4 send', as that is what I am used to at this point. Please accept my apologies if this causes any issues.
Masahiro Yamada (2): kbuild: check the minimum assembler version in Kconfig kbuild: check CONFIG_AS_IS_LLVM instead of LLVM_IAS
Nathan Chancellor (2): kbuild: Switch to 'f' variants of integrated assembler flag riscv: Handle zicsr/zifencei issues between clang and binutils
Makefile | 8 +++--- arch/riscv/Kconfig | 22 ++++++++++++++++ arch/riscv/Makefile | 12 +++++---- init/Kconfig | 12 +++++++++ scripts/Kconfig.include | 6 +++++ scripts/as-version.sh | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ scripts/dummy-tools/gcc | 6 +++++ 7 files changed, 127 insertions(+), 8 deletions(-)
base-commit: ca9787bdecfa2174b0a169a54916e22b89b0ef5b change-id: 20230328-riscv-zifencei-zicsr-5-10-65596f2cac9e
Best regards,
Nathan Chancellor nathan@kernel.org
On Wed, Apr 12, 2023 at 08:17:06AM +0200, Greg KH wrote:
On Tue, Apr 11, 2023 at 09:20:01AM -0700, Nathan Chancellor wrote:
Gentle ping, did this get lost?
Nope, just burried under a raft of other proposed backports. It's still in my review queue, will get to it eventually...
All now queued up, sorry for the delay.
greg k-h
On Tue, Apr 18, 2023 at 11:46:56AM +0200, Greg KH wrote:
On Wed, Apr 12, 2023 at 08:17:06AM +0200, Greg KH wrote:
On Tue, Apr 11, 2023 at 09:20:01AM -0700, Nathan Chancellor wrote:
Gentle ping, did this get lost?
Nope, just burried under a raft of other proposed backports. It's still in my review queue, will get to it eventually...
All now queued up, sorry for the delay.
Thanks a lot, I will take later over never :)
Cheers Nathan
linux-stable-mirror@lists.linaro.org