diff options
author | Gerald Schaefer <gerald.schaefer@de.ibm.com> | 2019-02-03 21:35:45 +0100 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2019-04-29 10:47:10 +0200 |
commit | 805bc0bc238f7209fca5e39c152b0d3c12046ac9 (patch) | |
tree | 97edfcee4981bc71c2e6a9dc853353010ac4fa94 /arch/s390/boot/startup.c | |
parent | 833b441ec0f6f3c57cc2106ef628bb19d8fb0ee2 (diff) |
s390/kernel: build a relocatable kernel
This patch adds support for building a relocatable kernel with -fPIE.
The kernel will be relocated to 0 early in the boot process.
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/boot/startup.c')
-rw-r--r-- | arch/s390/boot/startup.c | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 90898976a941..b7d6a76cb5e9 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/string.h> +#include <linux/elf.h> #include <asm/setup.h> +#include <asm/kexec.h> #include <asm/sclp.h> #include <asm/uv.h> #include "compressed/decompressor.h" @@ -47,6 +49,29 @@ static void copy_bootdata(void) memcpy((void *)vmlinux.bootdata_preserved_off, __boot_data_preserved_start, vmlinux.bootdata_preserved_size); } +static void handle_relocs(unsigned long offset) +{ + Elf64_Rela *rela_start, *rela_end, *rela; + int r_type, r_sym, rc; + Elf64_Addr loc, val; + Elf64_Sym *dynsym; + + rela_start = (Elf64_Rela *) vmlinux.rela_dyn_start; + rela_end = (Elf64_Rela *) vmlinux.rela_dyn_end; + dynsym = (Elf64_Sym *) vmlinux.dynsym_start; + for (rela = rela_start; rela < rela_end; rela++) { + loc = rela->r_offset + offset; + val = rela->r_addend + offset; + r_sym = ELF64_R_SYM(rela->r_info); + if (r_sym) + val += dynsym[r_sym].st_value; + r_type = ELF64_R_TYPE(rela->r_info); + rc = arch_kexec_do_relocs(r_type, (void *) loc, val, 0); + if (rc) + error("Unknown relocation type"); + } +} + void startup_kernel(void) { unsigned long safe_addr; @@ -67,5 +92,7 @@ void startup_kernel(void) memmove((void *)vmlinux.default_lma, img, vmlinux.image_size); } copy_bootdata(); + if (IS_ENABLED(CONFIG_RELOCATABLE)) + handle_relocs(0); vmlinux.entry(); } |