linux-yocto/arch/arm64/Makefile
Mark Rutland 9abe390e68 arm64: Force position-independent veneers
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: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Will Deacon <will@kernel.org>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
Link: https://lore.kernel.org/r/20240927101838.3061054-1-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2024-10-01 12:46:27 +01:00

8.1 KiB

arch/arm64/Makefile

This file is included by the global makefile so that you can add your own

architecture-specific flags and dependencies.

This file is subject to the terms and conditions of the GNU General Public

License. See the file "COPYING" in the main directory of this archive

for more details.

Copyright (C) 1995-2001 by Russell King

LDFLAGS_vmlinux :=--no-undefined -X --pic-veneer

ifeq ($(CONFIG_RELOCATABLE), y)

Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour

for relative relocs, since this leads to better Image compression

with the relocation offsets always being zero.

LDFLAGS_vmlinux += -shared -Bsymbolic -z notext
$(call ld-option, --no-apply-dynamic-relocs) endif

ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) ifeq ($(CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419),y) LDFLAGS_vmlinux += --fix-cortex-a53-843419 endif endif

cc_has_k_constraint := $(call try-run,echo
'int main(void) {
asm volatile("and w0, w0, %w0" :: "K" (4294967295));
return 0;
}' | $(CC) -S -x c -o "$$TMP" -,,-DCONFIG_CC_HAS_K_CONSTRAINT=1)

ifeq ($(CONFIG_BROKEN_GAS_INST),y) $(warning Detected assembler with broken .inst; disassembly will be unreliable) endif

The GCC option -ffreestanding is required in order to compile code containing

ARM/NEON intrinsics in a non C99-compliant environment (such as the kernel)

CC_FLAGS_FPU := -ffreestanding

Enable <arm_neon.h>

CC_FLAGS_FPU += -isystem $(shell $(CC) -print-file-name=include) CC_FLAGS_NO_FPU := -mgeneral-regs-only

KBUILD_CFLAGS += $(CC_FLAGS_NO_FPU)
$(compat_vdso) $(cc_has_k_constraint) KBUILD_CFLAGS += $(call cc-disable-warning, psabi) KBUILD_AFLAGS += $(compat_vdso)

KBUILD_RUSTFLAGS += --target=aarch64-unknown-none -Ctarget-feature="-neon"

KBUILD_CFLAGS += $(call cc-option,-mabi=lp64) KBUILD_AFLAGS += $(call cc-option,-mabi=lp64)

Avoid generating .eh_frame* sections.

ifneq ($(CONFIG_UNWIND_TABLES),y) KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables KBUILD_AFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables KBUILD_RUSTFLAGS += -Cforce-unwind-tables=n else KBUILD_CFLAGS += -fasynchronous-unwind-tables KBUILD_AFLAGS += -fasynchronous-unwind-tables KBUILD_RUSTFLAGS += -Cforce-unwind-tables=y -Zuse-sync-unwind=n endif

ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y) prepare: stack_protector_prepare stack_protector_prepare: prepare0 $(eval KBUILD_CFLAGS += -mstack-protector-guard=sysreg
-mstack-protector-guard-reg=sp_el0
-mstack-protector-guard-offset=$(shell
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}'
include/generated/asm-offsets.h)) endif

ifeq ($(CONFIG_ARM64_BTI_KERNEL),y) KBUILD_CFLAGS += -mbranch-protection=pac-ret+bti KBUILD_RUSTFLAGS += -Zbranch-protection=bti,pac-ret else ifeq ($(CONFIG_ARM64_PTR_AUTH_KERNEL),y) KBUILD_RUSTFLAGS += -Zbranch-protection=pac-ret ifeq ($(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET),y) KBUILD_CFLAGS += -mbranch-protection=pac-ret else KBUILD_CFLAGS += -msign-return-address=non-leaf endif else KBUILD_CFLAGS += $(call cc-option,-mbranch-protection=none) endif

Tell the assembler to support instructions from the latest target

architecture.

For non-integrated assemblers we'll pass this on the command line, and for

integrated assemblers we'll define ARM64_ASM_ARCH and ARM64_ASM_PREAMBLE for

inline usage.

We cannot pass the same arch flag to the compiler as this would allow it to

freely generate instructions which are not supported by earlier architecture

versions, which would prevent a single kernel image from working on earlier

hardware.

ifeq ($(CONFIG_AS_HAS_ARMV8_5), y) asm-arch := armv8.5-a else ifeq ($(CONFIG_AS_HAS_ARMV8_4), y) asm-arch := armv8.4-a else ifeq ($(CONFIG_AS_HAS_ARMV8_3), y) asm-arch := armv8.3-a else ifeq ($(CONFIG_AS_HAS_ARMV8_2), y) asm-arch := armv8.2-a endif

ifdef asm-arch KBUILD_CFLAGS += -Wa,-march=$(asm-arch)
-DARM64_ASM_ARCH='"$(asm-arch)"' endif

ifeq ($(CONFIG_SHADOW_CALL_STACK), y) KBUILD_CFLAGS += -ffixed-x18 KBUILD_RUSTFLAGS += -Zfixed-x18 endif

ifeq ($(CONFIG_CPU_BIG_ENDIAN), y) KBUILD_CPPFLAGS += -mbig-endian CHECKFLAGS += -D__AARCH64EB__

Prefer the baremetal ELF build target, but not all toolchains include

it so fall back to the standard linux version if needed.

KBUILD_LDFLAGS += -EB $(call ld-option, -maarch64elfb, -maarch64linuxb -z norelro) UTS_MACHINE := aarch64_be else KBUILD_CPPFLAGS += -mlittle-endian CHECKFLAGS += -D__AARCH64EL__

Same as above, prefer ELF but fall back to linux target if needed.

KBUILD_LDFLAGS += -EL $(call ld-option, -maarch64elf, -maarch64linux -z norelro) UTS_MACHINE := aarch64 endif

ifeq ($(CONFIG_LD_IS_LLD), y) KBUILD_LDFLAGS += -z norelro endif

CHECKFLAGS += -D__aarch64__

ifeq ($(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS),y) KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY CC_FLAGS_FTRACE := -fpatchable-function-entry=4,2 else ifeq ($(CONFIG_DYNAMIC_FTRACE_WITH_ARGS),y) KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY CC_FLAGS_FTRACE := -fpatchable-function-entry=2 endif

ifeq ($(CONFIG_KASAN_SW_TAGS), y) KASAN_SHADOW_SCALE_SHIFT := 4 else ifeq ($(CONFIG_KASAN_GENERIC), y) KASAN_SHADOW_SCALE_SHIFT := 3 endif

KBUILD_CFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) KBUILD_CPPFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) KBUILD_AFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)

libs-y := arch/arm64/lib/ $(libs-y) libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a

Default target when executing plain make

boot := arch/arm64/boot

BOOT_TARGETS := Image vmlinuz.efi image.fit

PHONY += $(BOOT_TARGETS)

ifeq ($(CONFIG_EFI_ZBOOT),) KBUILD_IMAGE := $(boot)/Image.gz else KBUILD_IMAGE := $(boot)/vmlinuz.efi endif

all: $(notdir $(KBUILD_IMAGE))

image.fit: dtbs

vmlinuz.efi image.fit: Image $(BOOT_TARGETS): vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@

Image.%: Image $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@

ifeq ($(CONFIG_COMPRESSED_INSTALL),y) DEFAULT_KBUILD_IMAGE = $(KBUILD_IMAGE) else DEFAULT_KBUILD_IMAGE = $(boot)/Image endif

install: KBUILD_IMAGE := $(DEFAULT_KBUILD_IMAGE) install zinstall: $(call cmd,install)

archprepare: $(Q)$(MAKE) $(build)=arch/arm64/tools kapi ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) ifneq ($(CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419),y) @echo "warning: ld does not support --fix-cortex-a53-843419; kernel may be susceptible to erratum" >&2 endif endif ifeq ($(CONFIG_ARM64_USE_LSE_ATOMICS),y) ifneq ($(CONFIG_ARM64_LSE_ATOMICS),y) @echo "warning: LSE atomics not supported by binutils" >&2 endif endif

ifeq ($(KBUILD_EXTMOD),)

We need to generate vdso-offsets.h before compiling certain files in kernel/.

In order to do that, we should use the archprepare target, but we can't since

asm-offsets.h is included in some files used to generate vdso-offsets.h, and

asm-offsets.h is built in prepare0, for which archprepare is a dependency.

Therefore we need to generate the header after prepare0 has been made, hence

this hack.

prepare: vdso_prepare vdso_prepare: prepare0 $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso
include/generated/vdso-offsets.h arch/arm64/kernel/vdso/vdso.so ifdef CONFIG_COMPAT_VDSO $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32
arch/arm64/kernel/vdso32/vdso.so endif endif

vdso-install-y += arch/arm64/kernel/vdso/vdso.so.dbg vdso-install-$(CONFIG_COMPAT_VDSO) += arch/arm64/kernel/vdso32/vdso32.so.dbg

include $(srctree)/scripts/Makefile.defconf

PHONY += virtconfig virtconfig: $(call merge_into_defconfig_override,defconfig,virt)

define archhelp echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)' echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)' echo ' image.fit - Flat Image Tree (arch/$(ARCH)/boot/image.fit)' echo ' install - Install kernel (compressed if COMPRESSED_INSTALL set)' echo ' zinstall - Install compressed kernel' echo ' Install using (your) ~/bin/installkernel or' echo ' (distribution) /sbin/installkernel or' echo ' install to $$(INSTALL_PATH) and run lilo' endef