Commit 89d6b39c authored by Laurent Dufour's avatar Laurent Dufour Committed by Pavel Emelyanov

ppc64: pie -- Add ppc64le relocation's processing

This cleans the assembly code, removing no more needed trick with the
register 2 (TOC pointer). As a consequence, the __export_restore_task_trampoline()
and __export_unmap_trampoline() are no more needed.

Thus, the changes introduced by the commit de9df910 ("Per architecture restorer
trampolines") in cr-restore.c are no more used but are not impacting
runtime code anyway.
Signed-off-by: 's avatarLaurent Dufour <ldufour@linux.vnet.ibm.com>
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent c755e0eb
......@@ -152,7 +152,7 @@ ARCH-LIB := $(ARCH_DIR)/crtools.built-in.o
CRIU-SO := libcriu
CRIU-LIB := lib/$(CRIU-SO).so
CRIU-INC := lib/criu.h include/criu-plugin.h include/criu-log.h protobuf/rpc.proto
ifneq ($(filter i386 ia32 x86_64, $(ARCH)),)
ifneq ($(filter i386 ia32 x86_64 ppc64le, $(ARCH)),)
PIEGEN := pie/piegen/piegen
endif
......@@ -197,7 +197,7 @@ $(ARCH_DIR)/%:: protobuf config
$(ARCH_DIR): protobuf config
$(Q) $(MAKE) $(build)=$(ARCH_DIR) all
ifneq ($(filter i386 ia32 x86_64, $(ARCH)),)
ifneq ($(filter i386 ia32 x86_64 ppc64le, $(ARCH)),)
pie/piegen/%: config
$(Q) $(MAKE) $(build)=pie/piegen $@
pie/piegen: config
......
......@@ -39,6 +39,11 @@ static inline void __check_code_syscall(void)
void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs)
{
/*
* OpenPOWER ABI requires that r12 is set to the calling function addressi
* to compute the TOC pointer.
*/
regs->gpr[12] = new_ip;
regs->nip = new_ip;
if (stack)
regs->gpr[1] = (unsigned long) stack;
......
......@@ -13,24 +13,19 @@
task_args) \
asm volatile( \
"mr 1,%0 \n" \
"mr 3,%1 \n" \
"mtctr 3 \n" \
"mr 12,%1 \n" \
"mtctr 12 \n" \
"mr 3,%2 \n" \
"mr 2,%3 \n" \
"bctr \n" \
: \
: "r"(new_sp), \
"r"((unsigned long)restore_task_exec_start), \
"r"(task_args), \
"r"((unsigned long)task_args->bootstrap_start + 0x8000) \
: "sp", "1", "2", "3", "memory")
"r"(task_args) \
: "sp", "1", "2", "3", "12", "memory")
/* There is nothing to do since TLS is accessed through r13 */
#define core_get_tls(pcore, ptls)
int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core);
#define arch_export_restore_task __export_restore_task_trampoline
#define arch_export_unmap __export_unmap_trampoline
#endif /* __CR_ASM_RESTORE_H__ */
/*
* This is from linux/arch/powerpc/lib/crtsavres.S:
*
* Special support for eabi and SVR4
*
* Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
* Copyright 2008 Freescale Semiconductor, Inc.
* Written By Michael Meissner
*
* Based on gcc/config/rs6000/crtsavres.asm from gcc
* 64 bit additions from reading the PPC elf64abi document.
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* In addition to the permissions in the GNU General Public License, the
* Free Software Foundation gives you unlimited permission to link the
* compiled version of this file with other programs, and to distribute
* those programs without any restriction coming from the use of this
* file. (The General Public License restrictions do apply in other
* respects; for example, they cover modification of the file, and
* distribution when not linked into another program.)
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* As a special exception, if you link this library with files
* compiled with GCC to produce an executable, this does not cause
* the resulting executable to be covered by the GNU General Public License.
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*/
#define r0 0
#define r1 1
#define r2 2
#define r3 3
#define r4 4
#define r5 5
#define r6 6
#define r7 7
#define r8 8
#define r9 9
#define r10 10
#define r11 11
#define r12 12
#define r13 13
#define r14 14
#define r15 15
#define r16 16
#define r17 17
#define r18 18
#define r19 19
#define r20 20
#define r21 21
#define r22 22
#define r23 23
#define r24 24
#define r25 25
#define r26 26
#define r27 27
#define r28 28
#define r29 29
#define r30 30
#define r31 31
.text
.globl _savegpr0_14
_savegpr0_14:
std r14,-144(r1)
.globl _savegpr0_15
_savegpr0_15:
std r15,-136(r1)
.globl _savegpr0_16
_savegpr0_16:
std r16,-128(r1)
.globl _savegpr0_17
_savegpr0_17:
std r17,-120(r1)
.globl _savegpr0_18
_savegpr0_18:
std r18,-112(r1)
.globl _savegpr0_19
_savegpr0_19:
std r19,-104(r1)
.globl _savegpr0_20
_savegpr0_20:
std r20,-96(r1)
.globl _savegpr0_21
_savegpr0_21:
std r21,-88(r1)
.globl _savegpr0_22
_savegpr0_22:
std r22,-80(r1)
.globl _savegpr0_23
_savegpr0_23:
std r23,-72(r1)
.globl _savegpr0_24
_savegpr0_24:
std r24,-64(r1)
.globl _savegpr0_25
_savegpr0_25:
std r25,-56(r1)
.globl _savegpr0_26
_savegpr0_26:
std r26,-48(r1)
.globl _savegpr0_27
_savegpr0_27:
std r27,-40(r1)
.globl _savegpr0_28
_savegpr0_28:
std r28,-32(r1)
.globl _savegpr0_29
_savegpr0_29:
std r29,-24(r1)
.globl _savegpr0_30
_savegpr0_30:
std r30,-16(r1)
.globl _savegpr0_31
_savegpr0_31:
std r31,-8(r1)
std r0,16(r1)
blr
.globl _restgpr0_14
_restgpr0_14:
ld r14,-144(r1)
.globl _restgpr0_15
_restgpr0_15:
ld r15,-136(r1)
.globl _restgpr0_16
_restgpr0_16:
ld r16,-128(r1)
.globl _restgpr0_17
_restgpr0_17:
ld r17,-120(r1)
.globl _restgpr0_18
_restgpr0_18:
ld r18,-112(r1)
.globl _restgpr0_19
_restgpr0_19:
ld r19,-104(r1)
.globl _restgpr0_20
_restgpr0_20:
ld r20,-96(r1)
.globl _restgpr0_21
_restgpr0_21:
ld r21,-88(r1)
.globl _restgpr0_22
_restgpr0_22:
ld r22,-80(r1)
.globl _restgpr0_23
_restgpr0_23:
ld r23,-72(r1)
.globl _restgpr0_24
_restgpr0_24:
ld r24,-64(r1)
.globl _restgpr0_25
_restgpr0_25:
ld r25,-56(r1)
.globl _restgpr0_26
_restgpr0_26:
ld r26,-48(r1)
.globl _restgpr0_27
_restgpr0_27:
ld r27,-40(r1)
.globl _restgpr0_28
_restgpr0_28:
ld r28,-32(r1)
.globl _restgpr0_29
_restgpr0_29:
ld r0,16(r1)
ld r29,-24(r1)
mtlr r0
ld r30,-16(r1)
ld r31,-8(r1)
blr
.globl _restgpr0_30
_restgpr0_30:
ld r30,-16(r1)
.globl _restgpr0_31
_restgpr0_31:
ld r0,16(r1)
ld r31,-8(r1)
mtlr r0
blr
......@@ -9,7 +9,6 @@ ENTRY(__export_parasite_head_start)
// int __used parasite_service(unsigned int cmd, void *args)
// cmd = r3 = *__export_parasite_cmd (u32 ?)
// args = r4 = @parasite_args_ptr + @pc
bl 0f
0: mflr r2
......@@ -21,24 +20,27 @@ ENTRY(__export_parasite_head_start)
lwz r3,0(r3)
LOAD_REG_ADDR(r4,parasite_args_ptr)
lwz r4,0(r4)
add r4,r4,r2 // Fix up ptr
ld r4,0(r4)
// Set the TOC pointer
LOAD_REG_ADDR(r5,parasite_toc_ptr)
ld r5,0(r5)
add r2,r2,r5 // Fix up ptr
LOAD_REG_ADDR(r12,parasite_service_ptr)
ld r12,0(r12)
mtctr r12
bl parasite_service
bctrl // call parasite_service
twi 31,0,0 // Should generate SIGTRAP
parasite_args_ptr:
.long __export_parasite_args - (0b - __export_parasite_head_start)
.quad __export_parasite_args
parasite_service_ptr:
// We want to run the function prototype to set r2.
// Since the relocation will prefer the local entry
// point, we force it to the global one which is 2
// instructions above the local one.
// FIXME: There should be a way to specify the global entry here.
.quad parasite_service - 8
__export_parasite_cmd:
.long 0
parasite_toc_ptr:
.long .TOC. - (0b - __export_parasite_head_start)
END(__export_parasite_head_start)
#include "asm/linkage.h"
#include "parasite.h"
.section .head.text
.align 8
// Called through parasite_unmap
// This trampoline is there to restore r2 before jumping back to the
// C code.
#define LOAD_REG_ADDR(reg, name) \
addis reg,r7,(name - 0b)@ha; \
addi reg,r7,(name - 0b)@l;
ENTRY(__export_unmap_trampoline)
bl 0f
0: mflr r7
LOAD_REG_ADDR(r8,restorer_r2)
ld r2,0(r8)
b __export_unmap
//END(__export_restore_unmap_trampoline)
// Called from JUMP_TO_RESTORER_BLOB, ctr contains the address where
// to jump to, and r3 etc contains the parameter.
// Assuming up to 4 parameters here since we are using r7 and r8.
ENTRY(__export_restore_task_trampoline)
bl 0f
0: mflr r7
LOAD_REG_ADDR(r8,restorer_r2)
std r2,0(r8)
b __export_restore_task
restorer_r2:
.long 0
......@@ -192,42 +192,6 @@ static unsigned long elf_hash(const unsigned char *name)
return h;
}
/*
* TODO :
* PIE linking doesn't work for this kind of definition.
* When build for the parasite code, the pointers to the string are
* computed from the start of the object but the generated code is
* assuming that the pointers are fixed by the loader.
*
* In addition, GCC create a call to C library memcpy when the table is
* containing more than 9 items. Since the parasite code is not linked
* with the C library an undefined symbol error is raised at build time.
* By initialising the table at run time, we are working around this
* issue.
*/
#ifdef __pie__
static const char *VDSO_SYMBOL(int i)
{
static char *vdso_symbols[VDSO_SYMBOL_MAX];
static int init_done = 0;
#define SET_VDSO_SYM(s) vdso_symbols[VDSO_SYMBOL_##s] = VDSO_SYMBOL_##s##_NAME
if (!init_done) {
SET_VDSO_SYM(CLOCK_GETRES);
SET_VDSO_SYM(CLOCK_GETTIME);
SET_VDSO_SYM(GET_SYSCALL_MAP);
SET_VDSO_SYM(GET_TBFREQ);
SET_VDSO_SYM(GETCPU);
SET_VDSO_SYM(GETTIMEOFDAY);
SET_VDSO_SYM(SIGTRAMP_RT64);
SET_VDSO_SYM(SYNC_DICACHE);
SET_VDSO_SYM(SYNC_DICACHE_P5);
SET_VDSO_SYM(TIME);
init_done = 1;
}
return vdso_symbols[i];
}
#else
#define SET_VDSO_SYM(s) [VDSO_SYMBOL_##s] = VDSO_SYMBOL_##s##_NAME
const char *vdso_symbols[VDSO_SYMBOL_MAX] = {
SET_VDSO_SYM(CLOCK_GETRES),
......@@ -242,7 +206,6 @@ const char *vdso_symbols[VDSO_SYMBOL_MAX] = {
SET_VDSO_SYM(TIME)
};
#define VDSO_SYMBOL(i) vdso_symbols[i]
#endif
int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t)
{
......
......@@ -14,6 +14,7 @@ ifeq ($(SRCARCH), ppc64)
asm-e += $(ARCH_DIR)/vdso-trampoline.o
asm-e += $(ARCH_DIR)/memcpy_power7.o
asm-e += $(ARCH_DIR)/memcmp_64.o
asm-e += $(ARCH_DIR)/misc.o
endif
endif
......@@ -23,9 +24,6 @@ parasite-libs-e += $(SYSCALL-LIB)
restorer-obj-y += restorer.o
restorer-obj-e += $(ARCH_DIR)/restorer.o
ifeq ($(SRCARCH), ppc64)
restorer-asm-e += $(ARCH_DIR)/restorer-trampoline.o
endif
restorer-libs-e += $(SYSCALL-LIB)
#
......@@ -54,23 +52,30 @@ PIELDS := pie.lds.S
.SECONDARY:
ifneq ($(filter i386 ia32 x86_64, $(ARCH)),)
ifneq ($(filter i386 ia32 x86_64 ppc64le, $(ARCH)),)
ldflags-y += -r
target-name = $(patsubst pie/%-blob.h,%,$(1))
ifeq ($(SRCARCH),ppc64)
$(obj)/$(PIELDS): $(obj)/pie-reloc.lds.S.in
$(E) " GEN " $@
$(Q) echo "OUTPUT_ARCH($(LDARCH))" > $(obj)/$(PIELDS)
$(Q) cat $< >> $(obj)/$(PIELDS)
else
ifeq ($(ARCH),x86_64)
$(obj)/$(PIELDS): $(obj)/pie-reloc.lds.S.in
$(E) " GEN " $@
$(Q) echo "OUTPUT_ARCH(i386:x86-64)" > $(obj)/$(PIELDS)
$(Q) echo "TARGET(elf64-x86-64)" >> $(obj)/$(PIELDS)
$(Q) cat $< >> $(obj)/$(PIELDS)
else
else # i386 ia32
$(obj)/$(PIELDS): $(obj)/pie-reloc.lds.S.in
$(E) " GEN " $@
$(Q) echo "OUTPUT_ARCH(i386)" > $(obj)/$(PIELDS)
$(Q) echo "TARGET(elf32-i386)" >> $(obj)/$(PIELDS)
$(Q) cat $< >> $(obj)/$(PIELDS)
endif
endif
$(obj)/%.built-in.bin.o: $(obj)/%.built-in.o $(obj)/$(PIELDS)
$(E) " GEN " $@
......
......@@ -6,7 +6,7 @@
#include "compiler.h"
#include "config.h"
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_32)
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_32) || defined(CONFIG_PPC64)
extern __maybe_unused void elf_relocs_apply(void *mem, void *vbase, size_t size, elf_reloc_t *elf_relocs, size_t nr_relocs);
#else
static always_inline void elf_relocs_apply(void *mem, void *vbase, size_t size, elf_reloc_t *elf_relocs, size_t nr_relocs) { }
......
......@@ -5,6 +5,9 @@ ifneq ($(filter i386 ia32 x86_64, $(ARCH)),)
obj-y += elf-x86-32.o
obj-y += elf-x86-64.o
endif
ifeq ($(SRCARCH),ppc64)
obj-y += elf-ppc64.o
endif
cleanup-y += $(obj)/piegen
cleanup-y += $(obj)/*.o
......
#define ELF_PPC64
#define handle_elf handle_elf_ppc64
#define Ehdr_t Elf64_Ehdr
#define Shdr_t Elf64_Shdr
#define Sym_t Elf64_Sym
#define Rel_t Elf64_Rel
#define Rela_t Elf64_Rela
#define ELF_ST_TYPE ELF64_ST_TYPE
#define ELF_ST_BIND ELF64_ST_BIND
#define ELF_R_SYM ELF64_R_SYM
#define ELF_R_TYPE ELF64_R_TYPE
#include "elf.c"
......@@ -43,6 +43,25 @@ static bool test_pointer(const void *ptr, const void *start, const size_t size,
} \
} while (0)
#ifdef ELF_PPC64
static int do_relative_toc(long value, uint16_t *location,
unsigned long mask, int complain_signed)
{
if (complain_signed && (value + 0x8000 > 0xffff)) {
pr_err("TOC16 relocation overflows (%ld)\n", value);
return -1;
}
if ((~mask & 0xffff) & value) {
pr_err("bad TOC16 relocation (%ld) (0x%lx)\n", value, (~mask & 0xffff) & value);
return -1;
}
*location = (*location & ~mask) | (value & mask);
return 0;
}
#endif
int handle_elf(const piegen_opt_t *opts, void *mem, size_t size)
{
const char *symstrings = NULL;
......@@ -56,6 +75,9 @@ int handle_elf(const piegen_opt_t *opts, void *mem, size_t size)
const char *secstrings;
size_t i, k, nr_gotpcrel = 0;
#ifdef ELF_PPC64
s64 toc_offset = 0;
#endif
pr_debug("Header\n------------\n");
pr_debug("\ttype 0x%x machine 0x%x version 0x%x\n",
......@@ -99,6 +121,13 @@ int handle_elf(const piegen_opt_t *opts, void *mem, size_t size)
(unsigned)sh->sh_type, &secstrings[sh->sh_name]);
sec_hdrs[i] = sh;
#ifdef ELF_PPC64
if (!strcmp(&secstrings[sh->sh_name], ".toc")) {
toc_offset = sh->sh_addr + 0x8000;
pr_debug("\t\tTOC offset 0x%lx\n", toc_offset);
}
#endif
}
if (!symtab_hdr) {
......@@ -141,6 +170,16 @@ int handle_elf(const piegen_opt_t *opts, void *mem, size_t size)
pr_debug("\ttype 0x%-2x bind 0x%-2x shndx 0x%-4x value 0x%-2lx name %s\n",
(unsigned)ELF_ST_TYPE(sym->st_info), (unsigned)ELF_ST_BIND(sym->st_info),
(unsigned)sym->st_shndx, (unsigned long)sym->st_value, name);
#ifdef ELF_PPC64
if (!sym->st_value && !strncmp(name, ".TOC.", 6)) {
if (!toc_offset) {
pr_err("No TOC pointer\n");
goto err;
}
sym->st_value = toc_offset;
continue;
}
#endif
if (strncmp(name, "__export", 8))
continue;
if (sym->st_shndx && sym->st_shndx < hdr->e_shnum) {
......@@ -207,8 +246,22 @@ int handle_elf(const piegen_opt_t *opts, void *mem, size_t size)
(unsigned long)ELF_R_TYPE(r->rel.r_info),
(unsigned long)sh_src->sh_offset);
if (sym->st_shndx == SHN_UNDEF)
if (sym->st_shndx == SHN_UNDEF) {
#ifdef ELF_PPC64
/* On PowerPC, TOC symbols appear to be
* undefined but should be processed as well.
* Their type is STT_NOTYPE, so report any
* other one.
*/
if (ELF32_ST_TYPE(sym->st_info) != STT_NOTYPE
|| strncmp(name, ".TOC.", 6)) {
pr_err("Unexpected undefined symbol:%s\n", name);
goto err;
}
#else
continue;
#endif
}
ptr_func_exit((mem + sh_rel->sh_offset + r->rel.r_offset));
if (sh->sh_type == SHT_REL) {
......@@ -227,7 +280,124 @@ int handle_elf(const piegen_opt_t *opts, void *mem, size_t size)
value32 = (s32)sh_src->sh_offset + (s32)sym->st_value;
value64 = (s64)sh_src->sh_offset + (s64)sym->st_value;
#ifdef ELF_PPC64
/* Snippet from the OpenPOWER ABI for Linux Supplement:
* The OpenPOWER ABI uses the three most-significant bits in the symbol
* st_other field specifies the number of instructions between a function's
* global entry point and local entry point. The global entry point is used
* when it is necessary to set up the TOC pointer (r2) for the function. The
* local entry point is used when r2 is known to already be valid for the
* function. A value of zero in these bits asserts that the function does
* not use r2.
* The st_other values have the following meanings:
* 0 and 1, the local and global entry points are the same.
* 2, the local entry point is at 1 instruction past the global entry point.
* 3, the local entry point is at 2 instructions past the global entry point.
* 4, the local entry point is at 4 instructions past the global entry point.
* 5, the local entry point is at 8 instructions past the global entry point.
* 6, the local entry point is at 16 instructions past the global entry point.
* 7, reserved.
*
* Here we are only handle the case '3' which is the most commonly seen.
*/
#define LOCAL_OFFSET(s) ((s->st_other >> 5) & 0x7)
if (LOCAL_OFFSET(sym)) {
if (LOCAL_OFFSET(sym) != 3) {
pr_err("Unexpected local offset value %d\n",
LOCAL_OFFSET(sym));
goto err;
}
pr_debug("\t\t\tUsing local offset\n");
value64 += 8;
value32 += 8;
}
#endif
switch (ELF_R_TYPE(r->rel.r_info)) {
#ifdef ELF_PPC64
case R_PPC64_REL24:
/* Update PC relative offset, linker has not done this yet */
pr_debug("\t\t\tR_PPC64_REL24 at 0x%-4lx val 0x%lx\n",
place, value64);
/* Convert value to relative */
value64 -= place;
if (value64 + 0x2000000 > 0x3ffffff || (value64 & 3) != 0) {
pr_err("REL24 %li out of range!\n", (long int)value64);
goto err;
}
/* Only replace bits 2 through 26 */
*(uint32_t *)where = (*(uint32_t *)where & ~0x03fffffc) |
(value64 & 0x03fffffc);
break;
case R_PPC64_ADDR32:
pr_debug("\t\t\tR_PPC64_ADDR32 at 0x%-4lx val 0x%x\n",
place, (unsigned int)(value32 + addend32));
pr_out(" { .offset = 0x%-8x, .type = PIEGEN_TYPE_INT, "
" .addend = %-8d, .value = 0x%-16x, "
"}, /* R_PPC64_ADDR32 */\n",
(unsigned int) place, addend32, value32);
break;
case R_PPC64_ADDR64:
case R_PPC64_REL64:
pr_debug("\t\t\tR_PPC64_ADDR64 at 0x%-4lx val 0x%lx\n",
place, value64 + addend64);
pr_out("\t{ .offset = 0x%-8x, .type = PIEGEN_TYPE_LONG,"
" .addend = %-8ld, .value = 0x%-16lx, "
"}, /* R_PPC64_ADDR64 */\n",
(unsigned int) place, (long)addend64, (long)value64);
break;
case R_PPC64_TOC16_HA:
pr_debug("\t\t\tR_PPC64_TOC16_HA at 0x%-4lx val 0x%lx\n",
place, value64 + addend64 - toc_offset + 0x8000);
if (do_relative_toc((value64 + addend64 - toc_offset + 0x8000) >> 16,
where, 0xffff, 1))
goto err;
break;
case R_PPC64_TOC16_LO:
pr_debug("\t\t\tR_PPC64_TOC16_LO at 0x%-4lx val 0x%lx\n",
place, value64 + addend64 - toc_offset);
if (do_relative_toc(value64 + addend64 - toc_offset,
where, 0xffff, 1))
goto err;
break;
case R_PPC64_TOC16_LO_DS:
pr_debug("\t\t\tR_PPC64_TOC16_LO_DS at 0x%-4lx val 0x%lx\n",
place, value64 + addend64 - toc_offset);
if (do_relative_toc(value64 + addend64 - toc_offset,
where, 0xfffc, 0))
goto err;
break;
case R_PPC64_REL16_HA:
value64 += addend64 - place;
pr_debug("\t\t\tR_PPC64_REL16_HA at 0x%-4lx val 0x%lx\n",
place, value64);
/* check that we are dealing with the addis 2,12 instruction */
if (((*(uint32_t*)where) & 0xffff0000) != 0x3c4c0000) {
pr_err("Unexpected instruction for R_PPC64_REL16_HA\n");
goto err;
}
*(uint16_t *)where = ((value64 + 0x8000) >> 16) & 0xffff;
break;
case R_PPC64_REL16_LO:
value64 += addend64 - place;
pr_debug("\t\t\tR_PPC64_REL16_LO at 0x%-4lx val 0x%lx\n",
place, value64);
/* check that we are dealing with the addi 2,2 instruction */
if (((*(uint32_t*)where) & 0xffff0000) != 0x38420000) {
pr_err("Unexpected instruction for R_PPC64_REL16_LO");
goto err;
}
*(uint16_t *)where = value64 & 0xffff;
break;
#endif /* ELF_PPC64 */
#ifdef ELF_X86_64
case R_X86_64_32: /* Symbol + Addend (4 bytes) */
......
......@@ -44,6 +44,21 @@ static int handle_elf(const piegen_opt_t *opts, void *mem, size_t size)
return handle_elf_x86_64(opts, mem, size);
#endif
#if defined(CONFIG_PPC64)
const unsigned char elf_ident[EI_NIDENT] = {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#else
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#endif
};
if (memcmp(mem, elf_ident, sizeof(elf_ident)) == 0)
return handle_elf_ppc64(opts, mem, size);
#endif /* CONFIG_PPC64 */
pr_err("Unsupported Elf format detected\n");
return -1;
}
......
......@@ -19,6 +19,10 @@ extern int handle_elf_x86_32(const piegen_opt_t *opts, void *mem, size_t size);
extern int handle_elf_x86_64(const piegen_opt_t *opts, void *mem, size_t size);
#endif
#if defined(CONFIG_PPC64)
extern int handle_elf_ppc64(const piegen_opt_t *opts, void *mem, size_t size);
#endif
#define pr_out(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__)
#if 0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment