mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-30 13:58:34 +00:00
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 de9df91002a3 ("Per architecture restorer trampolines") in cr-restore.c are no more used but are not impacting runtime code anyway. Signed-off-by: Laurent Dufour <ldufour@linux.vnet.ibm.com> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
c755e0eb96
commit
89d6b39cfe
4
Makefile
4
Makefile
@ -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__ */
|
||||
|
197
arch/ppc64/misc.S
Normal file
197
arch/ppc64/misc.S
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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)
|
||||
|
@ -1,33 +0,0 @@
|
||||
#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)
|
||||
{
|
||||
|
15
pie/Makefile
15
pie/Makefile
@ -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
|
||||
|
16
pie/piegen/elf-ppc64.c
Normal file
16
pie/piegen/elf-ppc64.c
Normal file
@ -0,0 +1,16 @@
|
||||
#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"
|
172
pie/piegen/elf.c
172
pie/piegen/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
|
||||
|
Loading…
x
Reference in New Issue
Block a user