On 11/21/16 at 09:49pm, Thiago Jung Bauermann wrote: > Hello Dave, > > Thanks for your review. > > Am Sonntag, 20. November 2016, 10:45:46 BRST schrieb Dave Young: > > On 11/10/16 at 01:27am, Thiago Jung Bauermann wrote: > > > powerpc's purgatory.ro has 12 relocation types when built as > > > a relocatable object. To implement support for them requires > > > arch_kexec_apply_relocations_add to duplicate a lot of code with > > > module_64.c:apply_relocate_add. > > > > > > When built as a Position Independent Executable there are only 4 > > > relocation types in purgatory.ro, so it becomes practical for the powerpc > > > implementation of kexec_file to have its own relocation implementation. > > > > > > Also, the purgatory is an executable and not an intermediary output from > > > the compiler so it makes sense conceptually that it is easier to build > > > it as a PIE than as a partially linked object. > > > > > > Apart from the greatly reduced number of relocations, there are two > > > differences between a relocatable object and a PIE: > > > > > > 1. __kexec_load_purgatory needs to use the program headers rather than the > > > > > > section headers to figure out how to load the binary. > > > > > > 2. Symbol values are absolute addresses instead of relative to the > > > > > > start of the section. > > > > > > This patch adds the support needed in generic code for the differences > > > above and allows powerpc to load and relocate a position independent > > > purgatory. > > > > [snip] > > > > The kexec-tools machine_apply_elf_rel is pretty simple for ppc64, it is > > not that complex. So could you look into simplify your kexec_file > > implementation? > > I can try, but there is one fundamental issue here: powerpc position-dependent > code relies more on relocations than x86 position-dependent code does, so > there's a limit to how simple it can be made without switching to position- > independent code. And it will always be more involved than it is on x86. > > BTW, building x86's purgatory as PIE results in it not having any relocation > at all, so it's an advantage even in that architecture. Unfortunately, the > machine locks up during reboot and I didn't have time to try to figure out > what's going on. > > > kernel/kexec_file.c kexec_apply_relocations only do limited things > > and some of the logic is in arch/x86, so move general code out of arch > > code, then I guess the arch code will be simpler > > I agree that is a good idea. Is the patch below what you had in mind? > > > and then we probably do not need this PIE stuff anymore. > > If you are ok with the patch below I can post a new version of the series > based on it and we can see if Michael Ellerman thinks it is enough. > > > BTW, __kexec_really_load_purgatory looks worse than > > ___kexec_load_purgatory ;) > > Really? I find the special handling of bss makes the section-based loader a > bit more confusing. > > -- > Thiago Jung Bauermann > IBM Linux Technology Center > > > Subject: [PATCH] kexec_file: Move generic relocation code from arch/x86 to > kernel/kexec_file.c > > The check for undefined symbols stays in arch-specific code because > powerpc needs to allow TOC symbols to be processed even though they're > undefined. > > There is no functional change. > > Suggested-by: Dave Young <dyoung at redhat.com> > Signed-off-by: Thiago Jung Bauermann <bauerman at linux.vnet.ibm.com> > --- > arch/x86/kernel/machine_kexec_64.c | 160 +++++++------------------------------ > include/linux/kexec.h | 9 ++- > kernel/kexec_file.c | 120 +++++++++++++++++++++++++++- > 3 files changed, 154 insertions(+), 135 deletions(-) > > diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c > index 8c1f218926d7..f4860c408ece 100644 > --- a/arch/x86/kernel/machine_kexec_64.c > +++ b/arch/x86/kernel/machine_kexec_64.c > @@ -401,143 +401,45 @@ int arch_kexec_kernel_verify_sig(struct kimage *image, void *kernel, > } > #endif > > -/* > - * Apply purgatory relocations. > - * > - * ehdr: Pointer to elf headers > - * sechdrs: Pointer to section headers. > - * relsec: section index of SHT_RELA section. > - * > - * TODO: Some of the code belongs to generic code. Move that in kexec.c. > - */ > -int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, > - Elf64_Shdr *sechdrs, unsigned int relsec) > +int arch_kexec_apply_relocation_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, > + unsigned int reltype, Elf_Sym *sym, > + const char *name, unsigned long *location, > + unsigned long address, unsigned long value) > { > - unsigned int i; > - Elf64_Rela *rel; > - Elf64_Sym *sym; > - void *location; > - Elf64_Shdr *section, *symtabsec; > - unsigned long address, sec_base, value; > - const char *strtab, *name, *shstrtab; > - > - /* > - * ->sh_offset has been modified to keep the pointer to section > - * contents in memory > - */ > - rel = (void *)sechdrs[relsec].sh_offset; > - > - /* Section to which relocations apply */ > - section = &sechdrs[sechdrs[relsec].sh_info]; > - > - pr_debug("Applying relocate section %u to %u\n", relsec, > - sechdrs[relsec].sh_info); > - > - /* Associated symbol table */ > - symtabsec = &sechdrs[sechdrs[relsec].sh_link]; > - > - /* String table */ > - if (symtabsec->sh_link >= ehdr->e_shnum) { > - /* Invalid strtab section number */ > - pr_err("Invalid string table section index %d\n", > - symtabsec->sh_link); > + if (sym->st_shndx == SHN_UNDEF) { > + pr_err("Undefined symbol: %s\n", name); > return -ENOEXEC; > } > > - strtab = (char *)sechdrs[symtabsec->sh_link].sh_offset; > - > - /* section header string table */ > - shstrtab = (char *)sechdrs[ehdr->e_shstrndx].sh_offset; > - > - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { > - > - /* > - * rel[i].r_offset contains byte offset from beginning > - * of section to the storage unit affected. > - * > - * This is location to update (->sh_offset). This is temporary > - * buffer where section is currently loaded. This will finally > - * be loaded to a different address later, pointed to by > - * ->sh_addr. kexec takes care of moving it > - * (kexec_load_segment()). > - */ > - location = (void *)(section->sh_offset + rel[i].r_offset); > - > - /* Final address of the location */ > - address = section->sh_addr + rel[i].r_offset; > - > - /* > - * rel[i].r_info contains information about symbol table index > - * w.r.t which relocation must be made and type of relocation > - * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get > - * these respectively. > - */ > - sym = (Elf64_Sym *)symtabsec->sh_offset + > - ELF64_R_SYM(rel[i].r_info); > - > - if (sym->st_name) > - name = strtab + sym->st_name; > - else > - name = shstrtab + sechdrs[sym->st_shndx].sh_name; > - > - pr_debug("Symbol: %s info: %02x shndx: %02x value=%llx size: %llx\n", > - name, sym->st_info, sym->st_shndx, sym->st_value, > - sym->st_size); > - > - if (sym->st_shndx == SHN_UNDEF) { > - pr_err("Undefined symbol: %s\n", name); > - return -ENOEXEC; > - } > - > - if (sym->st_shndx == SHN_COMMON) { > - pr_err("symbol '%s' in common section\n", name); > - return -ENOEXEC; > - } > - > - if (sym->st_shndx == SHN_ABS) > - sec_base = 0; > - else if (sym->st_shndx >= ehdr->e_shnum) { > - pr_err("Invalid section %d for symbol %s\n", > - sym->st_shndx, name); > - return -ENOEXEC; > - } else > - sec_base = sechdrs[sym->st_shndx].sh_addr; > - > - value = sym->st_value; > - value += sec_base; > - value += rel[i].r_addend; > - > - switch (ELF64_R_TYPE(rel[i].r_info)) { > - case R_X86_64_NONE: > - break; > - case R_X86_64_64: > - *(u64 *)location = value; > - break; > - case R_X86_64_32: > - *(u32 *)location = value; > - if (value != *(u32 *)location) > - goto overflow; > - break; > - case R_X86_64_32S: > - *(s32 *)location = value; > - if ((s64)value != *(s32 *)location) > - goto overflow; > - break; > - case R_X86_64_PC32: > - value -= (u64)address; > - *(u32 *)location = value; > - break; > - default: > - pr_err("Unknown rela relocation: %llu\n", > - ELF64_R_TYPE(rel[i].r_info)); > - return -ENOEXEC; > - } > + switch (reltype) { > + case R_X86_64_NONE: > + break; > + case R_X86_64_64: > + *(u64 *)location = value; > + break; > + case R_X86_64_32: > + *(u32 *)location = value; > + if (value != *(u32 *)location) > + goto overflow; > + break; > + case R_X86_64_32S: > + *(s32 *)location = value; > + if ((s64)value != *(s32 *)location) > + goto overflow; > + break; > + case R_X86_64_PC32: > + value -= (u64)address; > + *(u32 *)location = value; > + break; > + default: > + pr_err("Unknown rela relocation: %u\n", reltype); > + return -ENOEXEC; > } > + > return 0; > > overflow: > - pr_err("Overflow in relocation type %d value 0x%lx\n", > - (int)ELF64_R_TYPE(rel[i].r_info), value); > + pr_err("Overflow in relocation type %u value 0x%lx\n", reltype, value); > return -ENOEXEC; > } > #endif /* CONFIG_KEXEC_FILE */ > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > index 406c33dcae13..e171a083540d 100644 > --- a/include/linux/kexec.h > +++ b/include/linux/kexec.h > @@ -320,8 +320,13 @@ void * __weak arch_kexec_kernel_image_load(struct kimage *image); > int __weak arch_kimage_file_post_load_cleanup(struct kimage *image); > int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, > unsigned long buf_len); > -int __weak arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, > - Elf_Shdr *sechdrs, unsigned int relsec); > +int __weak arch_kexec_apply_relocation_add(const Elf_Ehdr *ehdr, > + Elf_Shdr *sechdrs, > + unsigned int reltype, Elf_Sym *sym, > + const char *name, > + unsigned long *location, > + unsigned long address, > + unsigned long value); > int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, > unsigned int relsec); > void arch_kexec_protect_crashkres(void); > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > index 037c321c5618..1517f977cc25 100644 > --- a/kernel/kexec_file.c > +++ b/kernel/kexec_file.c > @@ -61,8 +61,10 @@ int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, > > /* Apply relocations of type RELA */ > int __weak > -arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, > - unsigned int relsec) > +arch_kexec_apply_relocation_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, > + unsigned int reltype, Elf_Sym *sym, > + const char *name, unsigned long *location, > + unsigned long address, unsigned long value) > { > pr_err("RELA relocation unsupported.\n"); > return -ENOEXEC; > @@ -793,6 +795,117 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, > return ret; > } > > +/** > + * kexec_apply_relocations_add - apply purgatory relocations > + * @ehdr: Pointer to elf headers > + * @sechdrs: Pointer to section headers. > + * @relsec: Section index of SHT_RELA section. > + */ > +static int kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, > + Elf64_Shdr *sechdrs, unsigned int relsec) > +{ > + int ret; > + unsigned int i; > + Elf64_Rela *rel; > + Elf64_Sym *sym; > + void *location; > + Elf64_Shdr *section, *symtabsec; > + unsigned long address, sec_base, value; > + const char *strtab, *name, *shstrtab; > + > + /* > + * ->sh_offset has been modified to keep the pointer to section > + * contents in memory > + */ > + rel = (void *)sechdrs[relsec].sh_offset; > + > + /* Section to which relocations apply */ > + section = &sechdrs[sechdrs[relsec].sh_info]; > + > + pr_debug("Applying relocate section %u to %u\n", relsec, > + sechdrs[relsec].sh_info); > + > + /* Associated symbol table */ > + symtabsec = &sechdrs[sechdrs[relsec].sh_link]; > + > + /* String table */ > + if (symtabsec->sh_link >= ehdr->e_shnum) { > + /* Invalid strtab section number */ > + pr_err("Invalid string table section index %d\n", > + symtabsec->sh_link); > + return -ENOEXEC; > + } > + > + /* String table for the associated symbol table. */ > + strtab = (char *)sechdrs[symtabsec->sh_link].sh_offset; > + > + /* section header string table */ > + shstrtab = (char *)sechdrs[ehdr->e_shstrndx].sh_offset; > + > + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { > + > + /* > + * rel[i].r_offset contains byte offset from beginning > + * of section to the storage unit affected. > + * > + * This is location to update (->sh_offset). This is temporary > + * buffer where section is currently loaded. This will finally > + * be loaded to a different address later, pointed to by > + * ->sh_addr. kexec takes care of moving it > + * (kexec_load_segment()). > + */ > + location = (void *)(section->sh_offset + rel[i].r_offset); > + > + /* Final address of the location */ > + address = section->sh_addr + rel[i].r_offset; > + > + /* > + * rel[i].r_info contains information about symbol table index > + * w.r.t which relocation must be made and type of relocation > + * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get > + * these respectively. > + */ > + sym = (Elf64_Sym *)symtabsec->sh_offset + > + ELF64_R_SYM(rel[i].r_info); > + > + if (sym->st_name) > + name = strtab + sym->st_name; > + else > + name = shstrtab + sechdrs[sym->st_shndx].sh_name; > + > + pr_debug("Symbol: %s info: %02x shndx: %02x value=%llx size: %llx\n", > + name, sym->st_info, sym->st_shndx, sym->st_value, > + sym->st_size); > + > + if (sym->st_shndx == SHN_COMMON) { > + pr_err("symbol '%s' in common section\n", name); > + return -ENOEXEC; > + } > + > + if (sym->st_shndx == SHN_ABS) > + sec_base = 0; > + else if (sym->st_shndx >= ehdr->e_shnum) { > + pr_err("Invalid section %d for symbol %s\n", > + sym->st_shndx, name); > + return -ENOEXEC; > + } else > + sec_base = sechdrs[sym->st_shndx].sh_addr; > + > + value = sym->st_value; > + value += sec_base; > + value += rel[i].r_addend; > + > + ret = arch_kexec_apply_relocation_add(ehdr, sechdrs, > + ELF64_R_TYPE(rel[i].r_info), > + sym, name, location, > + address, value); > + if (ret) > + return ret; > + } > + > + return 0; > +} > + > static int kexec_apply_relocations(struct kimage *image) > { > int i, ret; > @@ -836,8 +949,7 @@ static int kexec_apply_relocations(struct kimage *image) > * relocations of type SHT_RELA/SHT_REL. > */ > if (sechdrs[i].sh_type == SHT_RELA) > - ret = arch_kexec_apply_relocations_add(pi->ehdr, > - sechdrs, i); > + ret = kexec_apply_relocations_add(pi->ehdr, sechdrs, i); > else if (sechdrs[i].sh_type == SHT_REL) > ret = arch_kexec_apply_relocations(pi->ehdr, > sechdrs, i); Hi, As we are here, two weak functions looks not necessary, let arch code to determin if SHT_REL can be handled is reasonable though I'm not sure why there is not such things in kexec-tools. Could you just use arch_kexec_apply_relocations for these two types instead of adding another? Thanks Dave