From cb58475cd72dabe971aa6bd5730f81144d3839e2 Mon Sep 17 00:00:00 2001 From: Xi Ruoyao Date: Sat, 20 Jul 2024 22:41:07 +0800 Subject: [PATCH] LoongArch: Add support for relocating the kernel with RELR relocation RELR as a relocation packing format for relative relocations for reducing the size of relative relocation records. In a position independent executable there are often many relative relocation records, and our vmlinux is a PIE. The LLD linker (since 17.0.0) and the BFD linker (since 2.43) supports packing the relocations in the RELR format for LoongArch, with the flag -z pack-relative-relocs. Commits 5cf896fb6be3eff ("arm64: Add support for relocating the kernel with RELR relocations") and ccb2d173b983984bfa ("Makefile: use -z pack-relative-relocs") have already added the framework to use RELR. We just need to wire it up and process the RELR relocation records in relocate_relative() in addition to the RELA relocation records. A ".p2align 3" directive is added to la_abs macro or the BFD linker cannot pack the relocation records against the .la_abs section (the ". = ALIGN(8);" directive in vmlinux.lds.S is too late in the linking process). With defconfig and CONFIG_RELR vmlinux.efi is 2.1 MiB (6%) smaller, and vmlinuz.efi (using gzip compression) is 384 KiB (2.8%) smaller. Link: https://groups.google.com/d/topic/generic-abi/bX460iggiKg Link: https://reviews.llvm.org/D138135#4531389 Link: https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=d89ecf33ab6d Signed-off-by: Xi Ruoyao Signed-off-by: Huacai Chen (cherry picked from commit e05d4cd9b895c503dcf19c0ed9ebb8d393b220ec) --- arch/loongarch/Kconfig | 1 + arch/loongarch/include/asm/asmmacro.h | 1 + arch/loongarch/include/asm/setup.h | 5 +++++ arch/loongarch/kernel/relocate.c | 18 ++++++++++++++++++ arch/loongarch/kernel/vmlinux.lds.S | 8 ++++++++ 5 files changed, 33 insertions(+) diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 3b4d487e0ae35..e7fea344b07a9 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -592,6 +592,7 @@ config ARCH_SELECTS_CRASH_DUMP config RELOCATABLE bool "Relocatable kernel" + select ARCH_HAS_RELR help This builds the kernel as a Position Independent Executable (PIE), which retains all relocation metadata required, so as to relocate diff --git a/arch/loongarch/include/asm/asmmacro.h b/arch/loongarch/include/asm/asmmacro.h index 655db7d7a4279..8d7f501b0a124 100644 --- a/arch/loongarch/include/asm/asmmacro.h +++ b/arch/loongarch/include/asm/asmmacro.h @@ -609,6 +609,7 @@ lu32i.d \reg, 0 lu52i.d \reg, \reg, 0 .pushsection ".la_abs", "aw", %progbits + .p2align 3 .dword 766b .dword \sym .popsection diff --git a/arch/loongarch/include/asm/setup.h b/arch/loongarch/include/asm/setup.h index ee52fb1e99631..3c2fb16b11b64 100644 --- a/arch/loongarch/include/asm/setup.h +++ b/arch/loongarch/include/asm/setup.h @@ -34,6 +34,11 @@ extern long __la_abs_end; extern long __rela_dyn_begin; extern long __rela_dyn_end; +#ifdef CONFIG_RELR +extern long __relr_dyn_begin; +extern long __relr_dyn_end; +#endif + extern unsigned long __init relocate_kernel(void); #endif diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c index d142061c61d42..614c447c8984d 100644 --- a/arch/loongarch/kernel/relocate.c +++ b/arch/loongarch/kernel/relocate.c @@ -40,6 +40,24 @@ static inline void __init relocate_relative(void) *(Elf64_Addr *)RELOCATED(addr) = relocated_addr; } + +#ifdef CONFIG_RELR + u64 *addr = NULL; + u64 *relr = (u64 *)&__relr_dyn_begin; + u64 *relr_end = (u64 *)&__relr_dyn_end; + + for ( ; relr < relr_end; relr++) { + if ((*relr & 1) == 0) { + addr = (u64 *)(*relr + reloc_offset); + *addr++ += reloc_offset; + } else { + for (u64 *p = addr, r = *relr >> 1; r; p++, r >>= 1) + if (r & 1) + *p += reloc_offset; + addr += 63; + } + } +#endif } static inline void __init relocate_absolute(long random_offset) diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S index 3c7595342730e..08ea921cdec16 100644 --- a/arch/loongarch/kernel/vmlinux.lds.S +++ b/arch/loongarch/kernel/vmlinux.lds.S @@ -113,6 +113,14 @@ SECTIONS __rela_dyn_end = .; } +#ifdef CONFIG_RELR + .relr.dyn : ALIGN(8) { + __relr_dyn_begin = .; + *(.relr.dyn) + __relr_dyn_end = .; + } +#endif + .data.rel : { *(.data.rel*) } #ifdef CONFIG_RELOCATABLE