On 2024-04-18, Nick Desaulniers wrote:
On Thu, Apr 18, 2024 at 1:17 PM Ard Biesheuvel ardb+git@google.com wrote:
From: Ard Biesheuvel ardb@kernel.org
On x86, the ordinary, position dependent 'small' and 'kernel' code models only support placement of the executable in 32-bit addressable memory, due to the use of 32-bit signed immediates to generate references to global variables. For the kernel, this implies that all global variables must reside in the top 2 GiB of the kernel virtual address space, where the implicit address bits 63:32 are equal to sign bit 31.
This means the kernel code model is not suitable for other bare metal executables such as the kexec purgatory, which can be placed arbitrarily in the physical address space, where its address may no longer be representable as a sign extended 32-bit quantity. For this reason, commit
e16c2983fba0 ("x86/purgatory: Change compiler flags from -mcmodel=kernel to -mcmodel=large to fix kexec relocation errors")
switched to the 'large' code model, which uses 64-bit immediates for all symbol references, including function calls, in order to avoid relying on any assumptions regarding proximity of symbols in the final executable.
The large code model is rarely used, clunky and the least likely to operate in a similar fashion when comparing GCC and Clang, so it is best avoided. This is especially true now that Clang 18 has started to emit executable code in two separate sections (.text and .ltext), which triggers an issue in the kexec loading code at runtime.
Instead, use the position independent small code model, which makes no assumptions about placement but only about proximity, where all referenced symbols must be within -/+ 2 GiB, i.e., in range for a RIP-relative reference. Use hidden visibility to suppress the use of a GOT, which carries absolute addresses that are not covered by static ELF relocations, and is therefore incompatible with the kexec loader's relocation logic.
Cc: Nathan Chancellor nathan@kernel.org Cc: Nick Desaulniers ndesaulniers@google.com
Thanks Ard!
Acked-by: Nick Desaulniers ndesaulniers@google.com Reported-by: ns 0n-s@users.noreply.github.com Closes: https://github.com/ClangBuiltLinux/linux/issues/2016 Fixes: e16c2983fba0 ("x86/purgatory: Change compiler flags from -mcmodel=kernel to -mcmodel=large to fix kexec relocation errors")
(I don't have a kexec setup ready to go; maybe someone that does can help test it.)
LGTM.
Position-dependent small code model may generate R_X86_64_32S relocations with a range of [0,2GiB) (the negative half cannot be used). Position-independent small code model with hidden visibility will generate R_X86_64_PC32 and can typically be quite larger than 2G without hitting an overflow issue.
(I have some notes about R_X86_64_32S at https://maskray.me/blog/2023-05-14-relocation-overflow-and-code-models#x86-6...)
Reviewed-by: Fangrui Song maskray@google.com
Cc: Bill Wendling morbo@google.com Cc: Justin Stitt justinstitt@google.com Cc: Song Liu song@kernel.org Cc: Ricardo Ribalda ribalda@kernel.org Cc: Fangrui Song maskray@google.com Cc: Arthur Eubanks aeubanks@google.com Link: https://lore.kernel.org/all/20240417-x86-fix-kexec-with-llvm-18-v1-0-5383121... Cc: stable@vger.kernel.org Signed-off-by: Ard Biesheuvel ardb@kernel.org
arch/x86/purgatory/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile index bc31863c5ee6..a18591f6e6d9 100644 --- a/arch/x86/purgatory/Makefile +++ b/arch/x86/purgatory/Makefile @@ -42,7 +42,8 @@ KCOV_INSTRUMENT := n # make up the standalone purgatory.ro
PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel -PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss -g0 +PURGATORY_CFLAGS := -mcmodel=small -ffreestanding -fno-zero-initialized-in-bss -g0 +PURGATORY_CFLAGS += -fpic -fvisibility=hidden PURGATORY_CFLAGS += $(DISABLE_STACKLEAK_PLUGIN) -DDISABLE_BRANCH_PROFILING PURGATORY_CFLAGS += -fno-stack-protector
-- 2.44.0.769.g3c40516874-goog
-- Thanks, ~Nick Desaulniers