Skip to content

Commit

Permalink
LoongArch: Add support for relocating the kernel with RELR relocation
Browse files Browse the repository at this point in the history
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 5cf896f ("arm64: Add support for relocating the kernel
with RELR relocations") and ccb2d17 ("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 <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
(cherry picked from commit e05d4cd9b895c503dcf19c0ed9ebb8d393b220ec)
  • Loading branch information
xry111 authored and opsiff committed Nov 28, 2024
1 parent 1a5ae89 commit cb58475
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/loongarch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions arch/loongarch/include/asm/asmmacro.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions arch/loongarch/include/asm/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions arch/loongarch/kernel/relocate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions arch/loongarch/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit cb58475

Please sign in to comment.