]> www.infradead.org Git - nvme.git/commitdiff
LoongArch: Add support for relocating the kernel with RELR relocation
authorXi Ruoyao <xry111@xry111.site>
Sat, 20 Jul 2024 14:41:07 +0000 (22:41 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Sat, 20 Jul 2024 14:41:07 +0000 (22:41 +0800)
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 <xry111@xry111.site>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/Kconfig
arch/loongarch/include/asm/asmmacro.h
arch/loongarch/include/asm/setup.h
arch/loongarch/kernel/relocate.c
arch/loongarch/kernel/vmlinux.lds.S

index 9687b1d241269f37cb66a20d0624792bfb5bd006..f5df69ad70a661c1742c16e70bb5161396b4fe06 100644 (file)
@@ -610,6 +610,7 @@ config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
 
 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
index 655db7d7a42796d947e857b6c546023d82c13fba..8d7f501b0a124e09dd5be9daf0579674c92ccea9 100644 (file)
        lu32i.d \reg, 0
        lu52i.d \reg, \reg, 0
        .pushsection ".la_abs", "aw", %progbits
+       .p2align 3
        .dword  766b
        .dword  \sym
        .popsection
index ee52fb1e99631653e3e40d6998afd159a7e5986d..3c2fb16b11b649cdfc895c9051d471307c9ca0ce 100644 (file)
@@ -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
index e3836f0b9bd8551b2fdad16637f85ed796292b43..50c469067f3aa37f4f07999221c6254a15e0598e 100644 (file)
@@ -38,6 +38,24 @@ static inline void __init relocate_relative(void)
                relocated_addr = (Elf64_Addr)RELOCATED(relocated_addr);
                *(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)
index 3c7595342730ed2c1e76c343e16553180fbd167d..08ea921cdec16eca09e51cdaac4cb6e75e942a26 100644 (file)
@@ -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