[CRIU] [PATCH 13/16] ppc64: pie -- Add ppc64le relocation's processing
Cyrill Gorcunov
gorcunov at openvz.org
Thu Jun 4 14:04:14 PDT 2015
From: Laurent Dufour <ldufour at linux.vnet.ibm.com>
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 at linux.vnet.ibm.com>
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
Makefile | 4 +-
arch/ppc64/crtools.c | 5 +
arch/ppc64/include/asm/restore.h | 13 +--
arch/ppc64/misc.S | 197 +++++++++++++++++++++++++++++++++++++++
arch/ppc64/parasite-head.S | 26 +++---
arch/ppc64/restorer-trampoline.S | 33 -------
arch/ppc64/vdso-pie.c | 37 --------
pie/Makefile | 15 ++-
pie/pie-relocs.h | 2 +-
pie/piegen/Makefile | 3 +
pie/piegen/elf-ppc64.c | 16 ++++
pie/piegen/elf.c | 172 +++++++++++++++++++++++++++++++++-
pie/piegen/main.c | 15 +++
pie/piegen/piegen.h | 4 +
14 files changed, 442 insertions(+), 100 deletions(-)
create mode 100644 arch/ppc64/misc.S
delete mode 100644 arch/ppc64/restorer-trampoline.S
create mode 100644 pie/piegen/elf-ppc64.c
diff --git a/Makefile b/Makefile
index 61d9b6a5c0ef..357129213fef 100644
--- a/Makefile
+++ b/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
diff --git a/arch/ppc64/crtools.c b/arch/ppc64/crtools.c
index 31cef5d222d8..c4e70b554c81 100644
--- a/arch/ppc64/crtools.c
+++ b/arch/ppc64/crtools.c
@@ -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;
diff --git a/arch/ppc64/include/asm/restore.h b/arch/ppc64/include/asm/restore.h
index a66046422118..325ff96e1018 100644
--- a/arch/ppc64/include/asm/restore.h
+++ b/arch/ppc64/include/asm/restore.h
@@ -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__ */
diff --git a/arch/ppc64/misc.S b/arch/ppc64/misc.S
new file mode 100644
index 000000000000..4ee188d554d3
--- /dev/null
+++ b/arch/ppc64/misc.S
@@ -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
diff --git a/arch/ppc64/parasite-head.S b/arch/ppc64/parasite-head.S
index e7163f0a5081..a1c189fe94ea 100644
--- a/arch/ppc64/parasite-head.S
+++ b/arch/ppc64/parasite-head.S
@@ -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)
diff --git a/arch/ppc64/restorer-trampoline.S b/arch/ppc64/restorer-trampoline.S
deleted file mode 100644
index 4c870b907599..000000000000
--- a/arch/ppc64/restorer-trampoline.S
+++ /dev/null
@@ -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
diff --git a/arch/ppc64/vdso-pie.c b/arch/ppc64/vdso-pie.c
index 8219e4af1be3..a77acf1efd26 100644
--- a/arch/ppc64/vdso-pie.c
+++ b/arch/ppc64/vdso-pie.c
@@ -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)
{
diff --git a/pie/Makefile b/pie/Makefile
index add7a0011c82..2ad4bcfca827 100644
--- a/pie/Makefile
+++ b/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 " $@
diff --git a/pie/pie-relocs.h b/pie/pie-relocs.h
index 0b64c7b7ccc3..f1e36b6ff691 100644
--- a/pie/pie-relocs.h
+++ b/pie/pie-relocs.h
@@ -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) { }
diff --git a/pie/piegen/Makefile b/pie/piegen/Makefile
index dd54c3f0b546..530af8bf8d9c 100644
--- a/pie/piegen/Makefile
+++ b/pie/piegen/Makefile
@@ -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
diff --git a/pie/piegen/elf-ppc64.c b/pie/piegen/elf-ppc64.c
new file mode 100644
index 000000000000..472725f9fe7c
--- /dev/null
+++ b/pie/piegen/elf-ppc64.c
@@ -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"
diff --git a/pie/piegen/elf.c b/pie/piegen/elf.c
index 8d36cbf64845..33ca3e12eb54 100644
--- a/pie/piegen/elf.c
+++ b/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) */
diff --git a/pie/piegen/main.c b/pie/piegen/main.c
index 64e82497469d..406a0a89718c 100644
--- a/pie/piegen/main.c
+++ b/pie/piegen/main.c
@@ -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;
}
diff --git a/pie/piegen/piegen.h b/pie/piegen/piegen.h
index 79a97e5b2f53..5b0bc7917f07 100644
--- a/pie/piegen/piegen.h
+++ b/pie/piegen/piegen.h
@@ -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
--
2.4.2
More information about the CRIU
mailing list