From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751965AbcFNPAL (ORCPT ); Tue, 14 Jun 2016 11:00:11 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:56746 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751863AbcFNPAG (ORCPT ); Tue, 14 Jun 2016 11:00:06 -0400 X-IBM-Helo: d24dlp02.br.ibm.com X-IBM-MailFrom: bauerman@linux.vnet.ibm.com X-IBM-RcptTo: linux-kernel@vger.kernel.org From: Thiago Jung Bauermann To: linuxppc-dev@lists.ozlabs.org Cc: kexec@lists.infradead.org, linux-kernel@vger.kernel.org, Thiago Jung Bauermann , Benjamin Herrenschmidt , Paul Mackerras , Michael Ellerman , Torsten Duwe Subject: [PATCH v2 5/9] powerpc: Generalize elf64_apply_relocate_add. Date: Tue, 14 Jun 2016 11:59:05 -0300 X-Mailer: git-send-email 1.9.1 In-Reply-To: <1465916349-3398-1-git-send-email-bauerman@linux.vnet.ibm.com> References: <1465916349-3398-1-git-send-email-bauerman@linux.vnet.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16061415-0020-0000-0000-00000212D430 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16061415-0021-0000-0000-00002FE54B4C Message-Id: <1465916349-3398-6-git-send-email-bauerman@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2016-06-14_06:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=1 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1604210000 definitions=main-1606140164 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When apply_relocate_add is called, modules are already loaded at their final location in memory so Elf64_Shdr.sh_addr can be used for accessing the section contents as well as the base address for relocations. This is not the case for kexec's purgatory, because it will only be copied to its final location right before being executed. Therefore, it needs to be relocated while it is still in a temporary buffer. In this case, Elf64_Shdr.sh_addr can't be used to access the sections' contents. This patch allows elf64_apply_relocate_add to be used when the ELF binary is not yet at its final location by adding an addr_base argument to specify the address at which the section will be loaded, and rela, loc_base and syms_base to point to the sections' contents. Signed-off-by: Thiago Jung Bauermann Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Torsten Duwe Cc: kexec@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- arch/powerpc/include/asm/elf_util.h | 6 ++-- arch/powerpc/kernel/elf_util_64.c | 63 +++++++++++++++++++++++++------------ arch/powerpc/kernel/module_64.c | 17 ++++++++-- 3 files changed, 61 insertions(+), 25 deletions(-) diff --git a/arch/powerpc/include/asm/elf_util.h b/arch/powerpc/include/asm/elf_util.h index 13d3ca113299..19ff3335d17d 100644 --- a/arch/powerpc/include/asm/elf_util.h +++ b/arch/powerpc/include/asm/elf_util.h @@ -64,7 +64,9 @@ static inline unsigned long my_r2(const struct elf_info *elf_info) } int elf64_apply_relocate_add(const struct elf_info *elf_info, - const char *strtab, unsigned int symindex, - unsigned int relsec, const char *obj_name); + const char *strtab, const Elf64_Rela *rela, + unsigned int num_rela, void *syms_base, + void *loc_base, Elf64_Addr addr_base, + const char *obj_name); #endif /* _ASM_POWERPC_ELF_UTIL_H */ diff --git a/arch/powerpc/kernel/elf_util_64.c b/arch/powerpc/kernel/elf_util_64.c index b53b3959a605..cde0420add9e 100644 --- a/arch/powerpc/kernel/elf_util_64.c +++ b/arch/powerpc/kernel/elf_util_64.c @@ -69,33 +69,56 @@ static void squash_toc_save_inst(const char *name, unsigned long addr) { } * elf64_apply_relocate_add - apply 64 bit RELA relocations * @elf_info: Support information for the ELF binary being relocated. * @strtab: String table for the associated symbol table. - * @symindex: Section header index for the associated symbol table. - * @relsec: Section header index for the relocations to apply. + * @rela: Contents of the section with the relocations to apply. + * @num_rela: Number of relocation entries in the section. + * @syms_base: Contents of the associated symbol table. + * @loc_base: Contents of the section to which relocations apply. + * @addr_base: The address where the section will be loaded in memory. * @obj_name: The name of the ELF binary, for information messages. + * + * Applies RELA relocations to an ELF file already at its final location + * in memory (in which case loc_base == addr_base), or still in a temporary + * buffer. */ int elf64_apply_relocate_add(const struct elf_info *elf_info, - const char *strtab, unsigned int symindex, - unsigned int relsec, const char *obj_name) + const char *strtab, const Elf64_Rela *rela, + unsigned int num_rela, void *syms_base, + void *loc_base, Elf64_Addr addr_base, + const char *obj_name) { unsigned int i; - Elf64_Shdr *sechdrs = elf_info->sechdrs; - Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr; - Elf64_Sym *sym; unsigned long *location; + unsigned long address; unsigned long value; + const char *name; + Elf64_Sym *sym; + + for (i = 0; i < num_rela; i++) { + /* + * rels[i].r_offset contains the byte offset from the beginning + * of section to the storage unit affected. + * + * This is the location to update in the temporary buffer where + * the section is currently loaded. The section will finally + * be loaded to a different address later, pointed to by + * addr_base. + */ + location = loc_base + rela[i].r_offset; + + /* Final address of the location. */ + address = addr_base + rela[i].r_offset; + /* This is the symbol the relocation is referring to. */ + sym = (Elf64_Sym *) syms_base + ELF64_R_SYM(rela[i].r_info); - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rela[i].r_offset; - /* This is the symbol it is referring to */ - sym = (Elf64_Sym *)sechdrs[symindex].sh_addr - + ELF64_R_SYM(rela[i].r_info); + if (sym->st_name) + name = strtab + sym->st_name; + else + name = ""; pr_debug("RELOC at %p: %li-type as %s (0x%lx) + %li\n", location, (long)ELF64_R_TYPE(rela[i].r_info), - strtab + sym->st_name, (unsigned long)sym->st_value, + name, (unsigned long)sym->st_value, (long)rela[i].r_addend); /* `Everything is relative'. */ @@ -187,7 +210,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, value += local_entry_offset(sym); /* Convert value to relative */ - value -= (unsigned long)location; + value -= address; if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){ pr_err("%s: REL24 %li out of range!\n", obj_name, (long int)value); @@ -202,7 +225,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, case R_PPC64_REL64: /* 64 bits relative (used by features fixups) */ - *location = value - (unsigned long)location; + *location = value - address; break; case R_PPC64_TOCSAVE: @@ -218,7 +241,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, * Optimize ELFv2 large code model entry point if * the TOC is within 2GB range of current location. */ - value = my_r2(elf_info) - (unsigned long)location; + value = my_r2(elf_info) - address; if (value + 0x80008000 > 0xffffffff) break; /* @@ -242,7 +265,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, case R_PPC64_REL16_HA: /* Subtract location pointer */ - value -= (unsigned long)location; + value -= address; value = ((value + 0x8000) >> 16); *((uint16_t *) location) = (*((uint16_t *) location) & ~0xffff) @@ -251,7 +274,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, case R_PPC64_REL16_LO: /* Subtract location pointer */ - value -= (unsigned long)location; + value -= address; *((uint16_t *) location) = (*((uint16_t *) location) & ~0xffff) | (value & 0xffff); diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 5f2eeab93651..a3cb0f6e83bb 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -438,16 +438,26 @@ int restore_r2(u32 *instruction, const char *obj_name) return 1; } +/* + * When this function is called, the module is already at its final location in + * memory, so Elf64_Shdr.sh_addr can be used for accessing the section + * contents as well as the base address for relocations. + */ int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *me) { + Elf64_Shdr *rel_section = &sechdrs[relsec]; + void *syms_base = (void *) sechdrs[symindex].sh_addr; + Elf64_Addr addr_base = sechdrs[rel_section->sh_info].sh_addr; + const Elf64_Rela *rela = (const Elf64_Rela *) rel_section->sh_addr; + unsigned int num_rela = rel_section->sh_size / sizeof(Elf64_Rela); Elf64_Sym *sym; pr_debug("Applying ADD relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); + rel_section->sh_info); /* First time we're called, we can fix up .TOC. */ if (!me->arch.toc_fixed) { @@ -459,8 +469,9 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, me->arch.toc_fixed = true; } - return elf64_apply_relocate_add(&me->arch.elf_info, strtab, symindex, - relsec, me->name); + return elf64_apply_relocate_add(&me->arch.elf_info, strtab, rela, + num_rela, syms_base, (void *) addr_base, + addr_base, me->name); } #ifdef CONFIG_DYNAMIC_FTRACE -- 1.9.1 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1bCppI-0007s7-LO for kexec@lists.infradead.org; Tue, 14 Jun 2016 15:00:28 +0000 Received: from pps.filterd (m0098394.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id u5EEsUDr115700 for ; Tue, 14 Jun 2016 11:00:08 -0400 Received: from e24smtp03.br.ibm.com (e24smtp03.br.ibm.com [32.104.18.24]) by mx0a-001b2d01.pphosted.com with ESMTP id 23jgpcgpr8-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Tue, 14 Jun 2016 11:00:08 -0400 Received: from localhost by e24smtp03.br.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 14 Jun 2016 12:00:05 -0300 Received: from d24relay02.br.ibm.com (d24relay02.br.ibm.com [9.13.184.26]) by d24dlp01.br.ibm.com (Postfix) with ESMTP id DB8EC352005C for ; Tue, 14 Jun 2016 10:59:45 -0400 (EDT) Received: from d24av05.br.ibm.com (d24av05.br.ibm.com [9.18.232.44]) by d24relay02.br.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u5EF01Xm52690978 for ; Tue, 14 Jun 2016 12:00:01 -0300 Received: from d24av05.br.ibm.com (localhost [127.0.0.1]) by d24av05.br.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u5EF01XH018928 for ; Tue, 14 Jun 2016 12:00:01 -0300 From: Thiago Jung Bauermann Subject: [PATCH v2 5/9] powerpc: Generalize elf64_apply_relocate_add. Date: Tue, 14 Jun 2016 11:59:05 -0300 In-Reply-To: <1465916349-3398-1-git-send-email-bauerman@linux.vnet.ibm.com> References: <1465916349-3398-1-git-send-email-bauerman@linux.vnet.ibm.com> Message-Id: <1465916349-3398-6-git-send-email-bauerman@linux.vnet.ibm.com> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "kexec" Errors-To: kexec-bounces+dwmw2=infradead.org@lists.infradead.org To: linuxppc-dev@lists.ozlabs.org Cc: Benjamin Herrenschmidt , Torsten Duwe , kexec@lists.infradead.org, linux-kernel@vger.kernel.org, Paul Mackerras , Michael Ellerman , Thiago Jung Bauermann When apply_relocate_add is called, modules are already loaded at their final location in memory so Elf64_Shdr.sh_addr can be used for accessing the section contents as well as the base address for relocations. This is not the case for kexec's purgatory, because it will only be copied to its final location right before being executed. Therefore, it needs to be relocated while it is still in a temporary buffer. In this case, Elf64_Shdr.sh_addr can't be used to access the sections' contents. This patch allows elf64_apply_relocate_add to be used when the ELF binary is not yet at its final location by adding an addr_base argument to specify the address at which the section will be loaded, and rela, loc_base and syms_base to point to the sections' contents. Signed-off-by: Thiago Jung Bauermann Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Torsten Duwe Cc: kexec@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- arch/powerpc/include/asm/elf_util.h | 6 ++-- arch/powerpc/kernel/elf_util_64.c | 63 +++++++++++++++++++++++++------------ arch/powerpc/kernel/module_64.c | 17 ++++++++-- 3 files changed, 61 insertions(+), 25 deletions(-) diff --git a/arch/powerpc/include/asm/elf_util.h b/arch/powerpc/include/asm/elf_util.h index 13d3ca113299..19ff3335d17d 100644 --- a/arch/powerpc/include/asm/elf_util.h +++ b/arch/powerpc/include/asm/elf_util.h @@ -64,7 +64,9 @@ static inline unsigned long my_r2(const struct elf_info *elf_info) } int elf64_apply_relocate_add(const struct elf_info *elf_info, - const char *strtab, unsigned int symindex, - unsigned int relsec, const char *obj_name); + const char *strtab, const Elf64_Rela *rela, + unsigned int num_rela, void *syms_base, + void *loc_base, Elf64_Addr addr_base, + const char *obj_name); #endif /* _ASM_POWERPC_ELF_UTIL_H */ diff --git a/arch/powerpc/kernel/elf_util_64.c b/arch/powerpc/kernel/elf_util_64.c index b53b3959a605..cde0420add9e 100644 --- a/arch/powerpc/kernel/elf_util_64.c +++ b/arch/powerpc/kernel/elf_util_64.c @@ -69,33 +69,56 @@ static void squash_toc_save_inst(const char *name, unsigned long addr) { } * elf64_apply_relocate_add - apply 64 bit RELA relocations * @elf_info: Support information for the ELF binary being relocated. * @strtab: String table for the associated symbol table. - * @symindex: Section header index for the associated symbol table. - * @relsec: Section header index for the relocations to apply. + * @rela: Contents of the section with the relocations to apply. + * @num_rela: Number of relocation entries in the section. + * @syms_base: Contents of the associated symbol table. + * @loc_base: Contents of the section to which relocations apply. + * @addr_base: The address where the section will be loaded in memory. * @obj_name: The name of the ELF binary, for information messages. + * + * Applies RELA relocations to an ELF file already at its final location + * in memory (in which case loc_base == addr_base), or still in a temporary + * buffer. */ int elf64_apply_relocate_add(const struct elf_info *elf_info, - const char *strtab, unsigned int symindex, - unsigned int relsec, const char *obj_name) + const char *strtab, const Elf64_Rela *rela, + unsigned int num_rela, void *syms_base, + void *loc_base, Elf64_Addr addr_base, + const char *obj_name) { unsigned int i; - Elf64_Shdr *sechdrs = elf_info->sechdrs; - Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr; - Elf64_Sym *sym; unsigned long *location; + unsigned long address; unsigned long value; + const char *name; + Elf64_Sym *sym; + + for (i = 0; i < num_rela; i++) { + /* + * rels[i].r_offset contains the byte offset from the beginning + * of section to the storage unit affected. + * + * This is the location to update in the temporary buffer where + * the section is currently loaded. The section will finally + * be loaded to a different address later, pointed to by + * addr_base. + */ + location = loc_base + rela[i].r_offset; + + /* Final address of the location. */ + address = addr_base + rela[i].r_offset; + /* This is the symbol the relocation is referring to. */ + sym = (Elf64_Sym *) syms_base + ELF64_R_SYM(rela[i].r_info); - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rela[i].r_offset; - /* This is the symbol it is referring to */ - sym = (Elf64_Sym *)sechdrs[symindex].sh_addr - + ELF64_R_SYM(rela[i].r_info); + if (sym->st_name) + name = strtab + sym->st_name; + else + name = ""; pr_debug("RELOC at %p: %li-type as %s (0x%lx) + %li\n", location, (long)ELF64_R_TYPE(rela[i].r_info), - strtab + sym->st_name, (unsigned long)sym->st_value, + name, (unsigned long)sym->st_value, (long)rela[i].r_addend); /* `Everything is relative'. */ @@ -187,7 +210,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, value += local_entry_offset(sym); /* Convert value to relative */ - value -= (unsigned long)location; + value -= address; if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){ pr_err("%s: REL24 %li out of range!\n", obj_name, (long int)value); @@ -202,7 +225,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, case R_PPC64_REL64: /* 64 bits relative (used by features fixups) */ - *location = value - (unsigned long)location; + *location = value - address; break; case R_PPC64_TOCSAVE: @@ -218,7 +241,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, * Optimize ELFv2 large code model entry point if * the TOC is within 2GB range of current location. */ - value = my_r2(elf_info) - (unsigned long)location; + value = my_r2(elf_info) - address; if (value + 0x80008000 > 0xffffffff) break; /* @@ -242,7 +265,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, case R_PPC64_REL16_HA: /* Subtract location pointer */ - value -= (unsigned long)location; + value -= address; value = ((value + 0x8000) >> 16); *((uint16_t *) location) = (*((uint16_t *) location) & ~0xffff) @@ -251,7 +274,7 @@ int elf64_apply_relocate_add(const struct elf_info *elf_info, case R_PPC64_REL16_LO: /* Subtract location pointer */ - value -= (unsigned long)location; + value -= address; *((uint16_t *) location) = (*((uint16_t *) location) & ~0xffff) | (value & 0xffff); diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 5f2eeab93651..a3cb0f6e83bb 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -438,16 +438,26 @@ int restore_r2(u32 *instruction, const char *obj_name) return 1; } +/* + * When this function is called, the module is already at its final location in + * memory, so Elf64_Shdr.sh_addr can be used for accessing the section + * contents as well as the base address for relocations. + */ int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *me) { + Elf64_Shdr *rel_section = &sechdrs[relsec]; + void *syms_base = (void *) sechdrs[symindex].sh_addr; + Elf64_Addr addr_base = sechdrs[rel_section->sh_info].sh_addr; + const Elf64_Rela *rela = (const Elf64_Rela *) rel_section->sh_addr; + unsigned int num_rela = rel_section->sh_size / sizeof(Elf64_Rela); Elf64_Sym *sym; pr_debug("Applying ADD relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); + rel_section->sh_info); /* First time we're called, we can fix up .TOC. */ if (!me->arch.toc_fixed) { @@ -459,8 +469,9 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, me->arch.toc_fixed = true; } - return elf64_apply_relocate_add(&me->arch.elf_info, strtab, symindex, - relsec, me->name); + return elf64_apply_relocate_add(&me->arch.elf_info, strtab, rela, + num_rela, syms_base, (void *) addr_base, + addr_base, me->name); } #ifdef CONFIG_DYNAMIC_FTRACE -- 1.9.1 _______________________________________________ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec