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 <dyo...@redhat.com>
> Signed-off-by: Thiago Jung Bauermann <bauer...@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

Reply via email to