diff options
author | Anton Blanchard <anton@samba.org> | 2016-02-26 18:04:16 +1100 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2016-03-24 13:59:57 +0900 |
commit | 1e423dc297d10eb7ff25c829d2856ef12fc81d77 (patch) | |
tree | 4861027f58989fb0ce848598d3c6d3f8c87bffcc | |
parent | 4a2ae3a39c64dc43e9d094be9541253234ff4822 (diff) |
ppc64: purgatory: Handle local symbols in ELF ABIv2
The PowerPC64 ELF ABIv2 has the concept of global and local symbols
and information on this is encoded in sym->st_other. When doing a
R_PPC64_REL24 branch we want to hit the local entry point, so adjust
it as necessary.
Signed-off-by: Anton Blanchard <anton@samba.org>
Tested-by: Dave Young <dyoung@redhat.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r-- | kexec/arch/ppc64/kexec-elf-rel-ppc64.c | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/kexec/arch/ppc64/kexec-elf-rel-ppc64.c b/kexec/arch/ppc64/kexec-elf-rel-ppc64.c index 8604c4f..43851f6 100644 --- a/kexec/arch/ppc64/kexec-elf-rel-ppc64.c +++ b/kexec/arch/ppc64/kexec-elf-rel-ppc64.c @@ -5,6 +5,24 @@ #include "../../kexec-elf.h" #include "kexec-ppc64.h" +#if defined(_CALL_ELF) && _CALL_ELF == 2 +#define STO_PPC64_LOCAL_BIT 5 +#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) +#define PPC64_LOCAL_ENTRY_OFFSET(other) \ + (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) + +static unsigned int local_entry_offset(struct mem_sym *sym) +{ + /* If this symbol has a local entry point, use it. */ + return PPC64_LOCAL_ENTRY_OFFSET(sym->st_other); +} +#else +static unsigned int local_entry_offset(struct mem_sym *UNUSED(sym)) +{ + return 0; +} +#endif + int machine_verify_elf_rel(struct mem_ehdr *ehdr) { if (ehdr->ei_class != ELFCLASS64) { @@ -114,6 +132,7 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *sym, break; case R_PPC64_REL24: + value += local_entry_offset(sym); /* Convert value to relative */ value -= address; if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0) { |