Message ID | 20240927101838.3061054-1-mark.rutland@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | arm64: Force position-independent veneers | expand |
On Fri, 27 Sept 2024 at 12:18, Mark Rutland <mark.rutland@arm.com> wrote: > > Certain portions of code always need to be position-independent > regardless of CONFIG_RELOCATABLE, including code which is executed in an > idmap or which is executed before relocations are applied. In some > kernel configurations the LLD linker generates position-dependent > veneers for such code, and when executed these result in early boot-time > failures. > ... > > I've opted to pass '--pic-veneer' unconditionally, as: > > * In addition to solving the boot failure, these sequences are generally > nicer as they require fewer instructions and don't need to perform > data accesses. > Yeah, and accessing literal pools interspersed with the code. I find it rather bizarre that --pic-veneer is not the default when using the small code model. ... > > Signed-off-by: Mark Rutland <mark.rutland@arm.com> > Reported-by: Marc Zyngier <maz@kernel.org> > Cc: Ard Biesheuvel <ardb@kernel.org> > Cc: Catalin Marinas <catalin.marinas@arm.com> > Cc: Nathan Chancellor <nathan@kernel.org> > Cc: Nick Desaulniers <ndesaulniers@google.com> > Cc: Will Deacon <will@kernel.org> > --- > arch/arm64/Makefile | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > Acked-by: Ard Biesheuvel <ardb@kernel.org>
On Fri, Sep 27, 2024 at 11:18:38AM +0100, Mark Rutland wrote: > Certain portions of code always need to be position-independent > regardless of CONFIG_RELOCATABLE, including code which is executed in an > idmap or which is executed before relocations are applied. In some > kernel configurations the LLD linker generates position-dependent > veneers for such code, and when executed these result in early boot-time > failures. > > Marc Zyngier encountered a boot failure resulting from this when > building a (particularly cursed) configuration with LLVM, as he reported > to the list: Heh, I admire the "particularly cursed" bit. > I've tested with GNU LD 2.30 to 2.42 inclusive and LLVM 13.0.1 to 19.1.0 > inclusive, using the kernel.org binaries from: > > * https://mirrors.edge.kernel.org/pub/tools/crosstool/ > * https://mirrors.edge.kernel.org/pub/tools/llvm/ > > Signed-off-by: Mark Rutland <mark.rutland@arm.com> > Reported-by: Marc Zyngier <maz@kernel.org> > Cc: Ard Biesheuvel <ardb@kernel.org> > Cc: Catalin Marinas <catalin.marinas@arm.com> > Cc: Nathan Chancellor <nathan@kernel.org> > Cc: Nick Desaulniers <ndesaulniers@google.com> > Cc: Will Deacon <will@kernel.org> Thanks for the patch! Reviewed-by: Nathan Chancellor <nathan@kernel.org> > --- > arch/arm64/Makefile | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile > index f6bc3da1ef110..c8e237b20ef29 100644 > --- a/arch/arm64/Makefile > +++ b/arch/arm64/Makefile > @@ -10,7 +10,7 @@ > # > # Copyright (C) 1995-2001 by Russell King > > -LDFLAGS_vmlinux :=--no-undefined -X > +LDFLAGS_vmlinux :=--no-undefined -X --pic-veneer > > ifeq ($(CONFIG_RELOCATABLE), y) > # Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour > -- > 2.30.2 >
On Fri, 27 Sep 2024 11:18:38 +0100, Mark Rutland wrote: > Certain portions of code always need to be position-independent > regardless of CONFIG_RELOCATABLE, including code which is executed in an > idmap or which is executed before relocations are applied. In some > kernel configurations the LLD linker generates position-dependent > veneers for such code, and when executed these result in early boot-time > failures. > > [...] Applied to arm64 (for-next/fixes), thanks! [1/1] arm64: Force position-independent veneers https://git.kernel.org/arm64/c/9abe390e689f
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index f6bc3da1ef110..c8e237b20ef29 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -10,7 +10,7 @@ # # Copyright (C) 1995-2001 by Russell King -LDFLAGS_vmlinux :=--no-undefined -X +LDFLAGS_vmlinux :=--no-undefined -X --pic-veneer ifeq ($(CONFIG_RELOCATABLE), y) # Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour
Certain portions of code always need to be position-independent regardless of CONFIG_RELOCATABLE, including code which is executed in an idmap or which is executed before relocations are applied. In some kernel configurations the LLD linker generates position-dependent veneers for such code, and when executed these result in early boot-time failures. Marc Zyngier encountered a boot failure resulting from this when building a (particularly cursed) configuration with LLVM, as he reported to the list: https://lore.kernel.org/linux-arm-kernel/86wmjwvatn.wl-maz@kernel.org/ In Marc's kernel configuration, the .head.text and .rodata.text sections end up more than 128MiB apart, requiring a veneer to branch between the two: | [mark@lakrids:~/src/linux]% usekorg 14.1.0 aarch64-linux-objdump -t vmlinux | grep -w _text | ffff800080000000 g .head.text 0000000000000000 _text | [mark@lakrids:~/src/linux]% usekorg 14.1.0 aarch64-linux-objdump -t vmlinux | grep -w primary_entry | ffff8000889df0e0 g .rodata.text 000000000000006c primary_entry, ... consequently, LLD inserts a position-dependent veneer for the branch from _stext (in .head.text) to primary_entry (in .rodata.text): | ffff800080000000 <_text>: | ffff800080000000: fa405a4d ccmp x18, #0x0, #0xd, pl // pl = nfrst | ffff800080000004: 14003fff b ffff800080010000 <__AArch64AbsLongThunk_primary_entry> ... | ffff800080010000 <__AArch64AbsLongThunk_primary_entry>: | ffff800080010000: 58000050 ldr x16, ffff800080010008 <__AArch64AbsLongThunk_primary_entry+0x8> | ffff800080010004: d61f0200 br x16 | ffff800080010008: 889df0e0 .word 0x889df0e0 | ffff80008001000c: ffff8000 .word 0xffff8000 ... and as this is executed early in boot before the kernel is mapped in TTBR1 this results in a silent boot failure. Fix this by passing '--pic-veneer' to the linker, which will cause the linker to use position-independent veneers, e.g. | ffff800080000000 <_text>: | ffff800080000000: fa405a4d ccmp x18, #0x0, #0xd, pl // pl = nfrst | ffff800080000004: 14003fff b ffff800080010000 <__AArch64ADRPThunk_primary_entry> ... | ffff800080010000 <__AArch64ADRPThunk_primary_entry>: | ffff800080010000: f004e3f0 adrp x16, ffff800089c8f000 <__idmap_text_start> | ffff800080010004: 91038210 add x16, x16, #0xe0 | ffff800080010008: d61f0200 br x16 I've opted to pass '--pic-veneer' unconditionally, as: * In addition to solving the boot failure, these sequences are generally nicer as they require fewer instructions and don't need to perform data accesses. * While the position-independent veneer sequences have a limited +/-2GiB range, this is not a new restriction. Even kernels built with CONFIG_RELOCATABLE=n are limited to 2GiB in size as we have several structues using 32-bit relative offsets and PPREL32 relocations, which are similarly limited to +/-2GiB in range. These include extable entries, jump table entries, and alt_instr entries. * GNU LD defaults to using position-independent veneers, and supports the same '--pic-veneer' option, so this change is not expected to adversely affect GNU LD. I've tested with GNU LD 2.30 to 2.42 inclusive and LLVM 13.0.1 to 19.1.0 inclusive, using the kernel.org binaries from: * https://mirrors.edge.kernel.org/pub/tools/crosstool/ * https://mirrors.edge.kernel.org/pub/tools/llvm/ Signed-off-by: Mark Rutland <mark.rutland@arm.com> Reported-by: Marc Zyngier <maz@kernel.org> Cc: Ard Biesheuvel <ardb@kernel.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Nathan Chancellor <nathan@kernel.org> Cc: Nick Desaulniers <ndesaulniers@google.com> Cc: Will Deacon <will@kernel.org> --- arch/arm64/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)