Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e01e8fd authored by Peter Collingbourne's avatar Peter Collingbourne Committed by Alistair Delva
Browse files

UPSTREAM: arm64: Add support for relocating the kernel with RELR relocations

RELR is a relocation packing format for relative relocations.
The format is described in a generic-abi proposal:
https://groups.google.com/d/topic/generic-abi/bX460iggiKg/discussion



The LLD linker can be instructed to pack relocations in the RELR
format by passing the flag --pack-dyn-relocs=relr.

This patch adds a new config option, CONFIG_RELR. Enabling this option
instructs the linker to pack vmlinux's relative relocations in the RELR
format, and causes the kernel to apply the relocations at startup along
with the RELA relocations. RELA relocations still need to be applied
because the linker will emit RELA relative relocations if they are
unrepresentable in the RELR format (i.e. address not a multiple of 2).

Enabling CONFIG_RELR reduces the size of a defconfig kernel image
with CONFIG_RANDOMIZE_BASE by 3.5MB/16% uncompressed, or 550KB/5%
compressed (lz4).

Signed-off-by: default avatarPeter Collingbourne <pcc@google.com>
Tested-by: default avatarNick Desaulniers <ndesaulniers@google.com>
Reviewed-by: default avatarNick Desaulniers <ndesaulniers@google.com>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
(cherry picked from commit 5cf896fb6be3effd9aea455b22213e27be8bdb1d)
Bug: 137200966
Test: booted defconfig + CONFIG_RELR kernel on qemu
Change-Id: I4c55bf5b10bc6c934543c651eca9fc8e260ffc6d
Signed-off-by: default avatarPeter Collingbourne <pcc@google.com>
parent ad15a425
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -924,6 +924,10 @@ ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
LDFLAGS_vmlinux	+= $(call ld-option, -X,)
endif

ifeq ($(CONFIG_RELR),y)
LDFLAGS_vmlinux	+= --pack-dyn-relocs=relr
endif

# insure the checker run with the right endianness
CHECKFLAGS += $(if $(CONFIG_CPU_BIG_ENDIAN),-mbig-endian,-mlittle-endian)

+14 −0
Original line number Diff line number Diff line
@@ -930,6 +930,20 @@ config HAVE_ARCH_PREL32_RELOCATIONS
	  architectures, and don't require runtime relocation on relocatable
	  kernels.

# Select if the architecture has support for applying RELR relocations.
config ARCH_HAS_RELR
	bool

config RELR
	bool "Use RELR relocation packing"
	depends on ARCH_HAS_RELR && TOOLS_SUPPORT_RELR
	default y
	help
	  Store the kernel's dynamic relocations in the RELR relocation packing
	  format. Requires a compatible linker (LLD supports this feature), as
	  well as compatible NM and OBJCOPY utilities (llvm-nm and llvm-objcopy
	  are compatible).

source "kernel/gcov/Kconfig"

source "scripts/gcc-plugins/Kconfig"
+1 −0
Original line number Diff line number Diff line
@@ -1195,6 +1195,7 @@ config ARM64_MODULE_PLTS

config RELOCATABLE
	bool
	select ARCH_HAS_RELR
	help
	  This builds the kernel as a Position Independent Executable (PIE),
	  which retains all relocation metadata required to relocate the
+90 −6
Original line number Diff line number Diff line
@@ -112,6 +112,8 @@ pe_header:
	 *  x23        stext() .. start_kernel()  physical misalignment/KASLR offset
	 *  x28        __create_page_tables()     callee preserved temp register
	 *  x19/x20    __primary_switch()         callee preserved temp registers
	 *  x24        __primary_switch() .. relocate_kernel()
	 *                                        current RELR displacement
	 */
ENTRY(stext)
	bl	preserve_boot_args
@@ -804,14 +806,93 @@ __relocate_kernel:

0:	cmp	x9, x10
	b.hs	1f
	ldp	x11, x12, [x9], #24
	ldr	x13, [x9, #-8]
	cmp	w12, #R_AARCH64_RELATIVE
	ldp	x12, x13, [x9], #24
	ldr	x14, [x9, #-8]
	cmp	w13, #R_AARCH64_RELATIVE
	b.ne	0b
	add	x13, x13, x23			// relocate
	str	x13, [x11, x23]
	add	x14, x14, x23			// relocate
	str	x14, [x12, x23]
	b	0b
1:	ret

1:
#ifdef CONFIG_RELR
	/*
	 * Apply RELR relocations.
	 *
	 * RELR is a compressed format for storing relative relocations. The
	 * encoded sequence of entries looks like:
	 * [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
	 *
	 * i.e. start with an address, followed by any number of bitmaps. The
	 * address entry encodes 1 relocation. The subsequent bitmap entries
	 * encode up to 63 relocations each, at subsequent offsets following
	 * the last address entry.
	 *
	 * The bitmap entries must have 1 in the least significant bit. The
	 * assumption here is that an address cannot have 1 in lsb. Odd
	 * addresses are not supported. Any odd addresses are stored in the RELA
	 * section, which is handled above.
	 *
	 * Excluding the least significant bit in the bitmap, each non-zero
	 * bit in the bitmap represents a relocation to be applied to
	 * a corresponding machine word that follows the base address
	 * word. The second least significant bit represents the machine
	 * word immediately following the initial address, and each bit
	 * that follows represents the next word, in linear order. As such,
	 * a single bitmap can encode up to 63 relocations in a 64-bit object.
	 *
	 * In this implementation we store the address of the next RELR table
	 * entry in x9, the address being relocated by the current address or
	 * bitmap entry in x13 and the address being relocated by the current
	 * bit in x14.
	 *
	 * Because addends are stored in place in the binary, RELR relocations
	 * cannot be applied idempotently. We use x24 to keep track of the
	 * currently applied displacement so that we can correctly relocate if
	 * __relocate_kernel is called twice with non-zero displacements (i.e.
	 * if there is both a physical misalignment and a KASLR displacement).
	 */
	ldr	w9, =__relr_offset		// offset to reloc table
	ldr	w10, =__relr_size		// size of reloc table
	add	x9, x9, x11			// __va(.relr)
	add	x10, x9, x10			// __va(.relr) + sizeof(.relr)

	sub	x15, x23, x24			// delta from previous offset
	cbz	x15, 7f				// nothing to do if unchanged
	mov	x24, x23			// save new offset

2:	cmp	x9, x10
	b.hs	7f
	ldr	x11, [x9], #8
	tbnz	x11, #0, 3f			// branch to handle bitmaps
	add	x13, x11, x23
	ldr	x12, [x13]			// relocate address entry
	add	x12, x12, x15
	str	x12, [x13], #8			// adjust to start of bitmap
	b	2b

3:	mov	x14, x13
4:	lsr	x11, x11, #1
	cbz	x11, 6f
	tbz	x11, #0, 5f			// skip bit if not set
	ldr	x12, [x14]			// relocate bit
	add	x12, x12, x15
	str	x12, [x14]

5:	add	x14, x14, #8			// move to next bit's address
	b	4b

6:	/*
	 * Move to the next bitmap's address. 8 is the word size, and 63 is the
	 * number of significant bits in a bitmap entry.
	 */
	add	x13, x13, #(8 * 63)
	b	2b

7:
#endif
	ret

ENDPROC(__relocate_kernel)
#endif

@@ -823,6 +904,9 @@ __primary_switch:

	bl	__enable_mmu
#ifdef CONFIG_RELOCATABLE
#ifdef CONFIG_RELR
	mov	x24, #0				// no RELR displacement yet
#endif
	bl	__relocate_kernel
#ifdef CONFIG_RANDOMIZE_BASE
	ldr	x8, =__primary_switched
+9 −0
Original line number Diff line number Diff line
@@ -184,6 +184,15 @@ SECTIONS
	__rela_offset	= ABSOLUTE(ADDR(.rela.dyn) - KIMAGE_VADDR);
	__rela_size	= SIZEOF(.rela.dyn);

#ifdef CONFIG_RELR
	.relr.dyn : ALIGN(8) {
		*(.relr.dyn)
	}

	__relr_offset	= ABSOLUTE(ADDR(.relr.dyn) - KIMAGE_VADDR);
	__relr_size	= SIZEOF(.relr.dyn);
#endif

	. = ALIGN(SEGMENT_ALIGN);
	__initdata_end = .;
	__init_end = .;
Loading