From a5224eb31a4c8a680587e74cc402e5ed92ead216 Mon Sep 17 00:00:00 2001
From: "A. Wilcox" <AWilcox@Wilcox-Tech.com>
Date: Thu, 27 Sep 2018 15:42:40 -0500
Subject: [PATCH] Ensure ELFv2 is supported on PPC64

---
 coregrind/m_dispatch/dispatch-ppc64be-linux.S | 107 ++++++++++++++++--
 coregrind/m_initimg/initimg-linux.c           |   5 +-
 coregrind/m_libcsetjmp.c                      |   7 +-
 coregrind/m_machine.c                         |   3 +-
 coregrind/m_main.c                            |  19 ++--
 coregrind/m_sigframe/sigframe-ppc64-linux.c   |   3 +-
 coregrind/m_signals.c                         |  11 +-
 coregrind/m_stacktrace.c                      |  12 +-
 coregrind/m_syscall.c                         |   9 +-
 coregrind/m_syswrap/syscall-ppc64be-linux.S   |  19 +++-
 coregrind/m_syswrap/syswrap-ppc64-linux.c     |   9 +-
 coregrind/m_trampoline.S                      |   4 +-
 coregrind/m_translate.c                       |  23 ++--
 coregrind/m_ume/elf.c                         |   8 +-
 coregrind/pub_core_machine.h                  |  12 +-
 coregrind/vg_preloaded.c                      |   3 +-
 include/valgrind.h                            |  16 ++-
 memcheck/mc_leakcheck.c                       |   2 +-
 memcheck/mc_machine.c                         |   3 +-
 19 files changed, 206 insertions(+), 69 deletions(-)

diff --git a/coregrind/m_dispatch/dispatch-ppc64be-linux.S b/coregrind/m_dispatch/dispatch-ppc64be-linux.S
index 91bd3b236..eb8026c7c 100644
--- a/coregrind/m_dispatch/dispatch-ppc64be-linux.S
+++ b/coregrind/m_dispatch/dispatch-ppc64be-linux.S
@@ -75,14 +75,26 @@ void VG_(disp_run_translations)( UWord* two_words,
 .section ".text"
 .align   2
 .globl   VG_(disp_run_translations)
+#if _CALL_ELF == 2
+.type VG_(disp_run_translations),@function
+VG_(disp_run_translations):
+.type    .VG_(disp_run_translations),@function
+#else
 .section ".opd","aw"
 .align   3
 VG_(disp_run_translations):
 .quad    .VG_(disp_run_translations),.TOC.@tocbase,0
 .previous
 .type    .VG_(disp_run_translations),@function
+#endif
 .globl   .VG_(disp_run_translations)
 .VG_(disp_run_translations):
+#if  _CALL_ELF == 2
+0:      addis 2, 12,.TOC.-0b@ha
+        addi  2,2,.TOC.-0b@l
+        .localentry VG_(disp_run_translations), .-VG_(disp_run_translations)
+#endif
+
 	/* r3 holds two_words */
 	/* r4 holds guest_state */
         /* r5 holds host_addr */
@@ -231,6 +243,11 @@ VG_(disp_run_translations):
 
         /* Set up the guest state ptr */
         mr      31,4      /* r31 (generated code gsp) = r4 */
+#if  _CALL_ELF == 2
+/*  for the LE ABI need to setup r2 and r12 */
+0:      addis 2, 12,.TOC.-0b@ha
+        addi  2,2,.TOC.-0b@l
+#endif
 
         /* and jump into the code cache.  Chained translations in
            the code cache run, until for whatever reason, they can't
@@ -385,7 +402,9 @@ VG_(disp_run_translations):
         mtlr    0
         addi    1,1,624   /* stack_size */
         blr
-
+#if _CALL_ELF == 2
+	.size VG_(disp_run_translations),.-VG_(disp_run_translations)
+#endif
 
 /*----------------------------------------------------*/
 /*--- Continuation points                          ---*/
@@ -395,15 +414,25 @@ VG_(disp_run_translations):
         .section ".text"
         .align   2
         .globl   VG_(disp_cp_chain_me_to_slowEP)
-        .section ".opd","aw"
+#if  _CALL_ELF == 2
+        .type VG_(disp_cp_chain_me_to_slowEP),@function
+	VG_(disp_cp_chain_me_to_slowEP):
+#else
+	.section ".opd","aw"
         .align   3
 VG_(disp_cp_chain_me_to_slowEP):
         .quad    .VG_(disp_cp_chain_me_to_slowEP),.TOC.@tocbase,0
         .previous
+#endif
         .type    .VG_(disp_cp_chain_me_to_slowEP),@function
         .globl   .VG_(disp_cp_chain_me_to_slowEP)
 .VG_(disp_cp_chain_me_to_slowEP):
-        /* We got called.  The return address indicates
+#if  _CALL_ELF == 2
+0:      addis 2, 12,.TOC.-0b@ha
+        addi  2,2,.TOC.-0b@l
+        .localentry VG_(disp_cp_chain_me_to_slowEP), .-VG_(disp_cp_chain_me_to_slowEP)
+#endif
+	/* We got called.  The return address indicates
            where the patching needs to happen.  Collect
            the return address and, exit back to C land,
            handing the caller the pair (Chain_me_S, RA) */
@@ -415,20 +444,33 @@ VG_(disp_cp_chain_me_to_slowEP):
         */
         subi 7,7,20+4+4
         b    .postamble
+#if  _CALL_ELF == 2
+        .size VG_(disp_cp_chain_me_to_slowEP),.-VG_(disp_cp_chain_me_to_slowEP)
+#endif
 
 /* ------ Chain me to fast entry point ------ */
         .section ".text"
         .align   2
         .globl   VG_(disp_cp_chain_me_to_fastEP)
-        .section ".opd","aw"
+#if  _CALL_ELF == 2
+        .type VG_(disp_cp_chain_me_to_fastEP),@function
+VG_(disp_cp_chain_me_to_fastEP):
+#else
+	.section ".opd","aw"
         .align   3
 VG_(disp_cp_chain_me_to_fastEP):
         .quad    .VG_(disp_cp_chain_me_to_fastEP),.TOC.@tocbase,0
         .previous
+#endif
         .type    .VG_(disp_cp_chain_me_to_fastEP),@function
         .globl   .VG_(disp_cp_chain_me_to_fastEP)
 .VG_(disp_cp_chain_me_to_fastEP):
-        /* We got called.  The return address indicates
+#if  _CALL_ELF == 2
+0:      addis 2, 12,.TOC.-0b@ha
+        addi  2,2,.TOC.-0b@l
+        .localentry VG_(disp_cp_chain_me_to_fastEP), .-VG_(disp_cp_chain_me_to_fastEP)
+#endif
+	/* We got called.  The return address indicates
            where the patching needs to happen.  Collect
            the return address and, exit back to C land,
            handing the caller the pair (Chain_me_S, RA) */
@@ -440,20 +482,33 @@ VG_(disp_cp_chain_me_to_fastEP):
         */
         subi 7,7,20+4+4
         b    .postamble
+#if _CALL_ELF == 2
+        .size VG_(disp_cp_chain_me_to_fastEP),.-VG_(disp_cp_chain_me_to_fastEP)
+#endif
 
 /* ------ Indirect but boring jump ------ */
         .section ".text"
         .align   2
         .globl   VG_(disp_cp_xindir)
-        .section ".opd","aw"
+#if _CALL_ELF == 2
+        .type VG_(disp_cp_xindir),@function
+VG_(disp_cp_xindir):
+#else
+	.section ".opd","aw"
         .align   3
 VG_(disp_cp_xindir):
         .quad    .VG_(disp_cp_xindir),.TOC.@tocbase,0
         .previous
+#endif
         .type    .VG_(disp_cp_xindir),@function
         .globl   .VG_(disp_cp_xindir)
 .VG_(disp_cp_xindir):
-        /* Where are we going? */
+#if  _CALL_ELF == 2
+0:      addis 2, 12,.TOC.-0b@ha
+        addi  2,2,.TOC.-0b@l
+        .localentry VG_(disp_cp_xindir), .-VG_(disp_cp_xindir)
+#endif
+	/* Where are we going? */
         ld      3,OFFSET_ppc64_CIA(31)
 
         /* stats only */
@@ -479,6 +534,9 @@ VG_(disp_cp_xindir):
         /* Found a match.  Jump to .host. */
         mtctr   7
         bctr
+#if _CALL_ELF == 2
+        .size VG_(disp_cp_xindir),.-VG_(disp_cp_xindir)
+#endif
 
 .fast_lookup_failed:
         /* stats only */
@@ -496,39 +554,64 @@ VG_(disp_cp_xindir):
 .section ".text"
         .align   2
         .globl   VG_(disp_cp_xassisted)
-        .section ".opd","aw"
+#if _CALL_ELF == 2
+        .type VG_(disp_cp_xassisted),@function
+VG_(disp_cp_xassisted):
+#else
+	.section ".opd","aw"
         .align   3
 VG_(disp_cp_xassisted):
         .quad    .VG_(disp_cp_xassisted),.TOC.@tocbase,0
         .previous
-        .type    .VG_(disp_cp_xassisted),@function
+#endif
+#if  _CALL_ELF == 2
+0:      addis 2, 12,.TOC.-0b@ha
+        addi  2,2,.TOC.-0b@l
+        .localentry VG_(disp_cp_xassisted), .-VG_(disp_cp_xassisted)
+#endif
+	.type    .VG_(disp_cp_xassisted),@function
         .globl   .VG_(disp_cp_xassisted)
 .VG_(disp_cp_xassisted):
         /* r31 contains the TRC */
         mr      6,31
         li      7,0
         b       .postamble
+#if _CALL_ELF == 2
+        .size VG_(disp_cp_xassisted),.-VG_(disp_cp_xassisted)
+#endif
 
 /* ------ Event check failed ------ */
         .section ".text"
         .align   2
         .globl   VG_(disp_cp_evcheck_fail)
-        .section ".opd","aw"
+#if _CALL_ELF == 2
+        .type VG_(disp_cp_evcheck_fail),@function
+VG_(disp_cp_evcheck_fail):
+#else
+	.section ".opd","aw"
         .align   3
 VG_(disp_cp_evcheck_fail):
         .quad    .VG_(disp_cp_evcheck_fail),.TOC.@tocbase,0
         .previous
+#endif
+#if  _CALL_ELF == 2
+0:      addis 2, 12,.TOC.-0b@ha
+        addi  2,2,.TOC.-0b@l
+        .localentry VG_(disp_cp_evcheck_fail), .-VG_(disp_cp_evcheck_fail)
+#endif
         .type    .VG_(disp_cp_evcheck_fail),@function
         .globl   .VG_(disp_cp_evcheck_fail)
 .VG_(disp_cp_evcheck_fail):
         li      6,VG_TRC_INNER_COUNTERZERO
         li      7,0
         b       .postamble
+#if  _CALL_ELF == 2
+       .size VG_(disp_cp_evcheck_fail),.-VG_(disp_cp_evcheck_fail)
+#endif
 
-        
 .size .VG_(disp_run_translations), .-.VG_(disp_run_translations)
 
-#endif // defined(VGP_ppc64be_linux)
+#endif // defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
 
 /* Let the linker know we don't need an executable stack */
 MARK_STACK_NO_EXEC
diff --git a/coregrind/m_initimg/initimg-linux.c b/coregrind/m_initimg/initimg-linux.c
index 61cc458bc..19df79705 100644
--- a/coregrind/m_initimg/initimg-linux.c
+++ b/coregrind/m_initimg/initimg-linux.c
@@ -1117,7 +1117,8 @@ void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
    arch->vex.guest_GPR1 = iifii.initial_client_SP;
    arch->vex.guest_GPR2 = iifii.initial_client_TOC;
    arch->vex.guest_CIA  = iifii.initial_client_IP;
-#if defined(VGP_ppc64le_linux)
+#if (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+    && !defined(VG_PLAT_USES_PPCTOC)
    arch->vex.guest_GPR12 = iifii.initial_client_IP;
 #endif
 
diff --git a/coregrind/m_libcsetjmp.c b/coregrind/m_libcsetjmp.c
index c73180640..ed96f4739 100644
--- a/coregrind/m_libcsetjmp.c
+++ b/coregrind/m_libcsetjmp.c
@@ -35,6 +35,7 @@
 
 #include "pub_core_basics.h"
 #include "pub_core_libcsetjmp.h"    /* self */
+#include "pub_core_machine.h"       /* VG_PLAT_USES_PPCTOC */
 
 /* See include/pub_tool_libcsetjmp.h for background and rationale. */
 
@@ -151,7 +152,8 @@ __asm__(
 
 /* ------------ ppc64-linux ------------ */
 
-#if defined(VGP_ppc64be_linux)
+#if (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+    && defined(VG_PLAT_USES_PPCTOC)
 
 __asm__(
 ".section \".toc\",\"aw\""          "\n"
@@ -270,7 +272,8 @@ __asm__(
 ".previous"  "\n"
 );
 
-#elif defined(VGP_ppc64le_linux)
+#elif (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+      && !defined(VG_PLAT_USES_PPCTOC)
 __asm__(
 ".section \".toc\",\"aw\""          "\n"
 
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
index 31b0e1b6b..eb3e6a4e1 100644
--- a/coregrind/m_machine.c
+++ b/coregrind/m_machine.c
@@ -2035,7 +2035,8 @@ void* VG_(fnptr_to_fnentry)( void* f )
       || defined(VGP_ppc32_linux) || defined(VGP_ppc64le_linux) \
       || defined(VGP_s390x_linux) || defined(VGP_mips32_linux) \
       || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
-      || defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
+      || defined(VGP_x86_solaris) || defined(VGP_amd64_solaris) \
+      || (defined(VGP_ppc64be_linux) && !defined(VG_PLAT_USES_PPCTOC))
    return f;
 #  elif defined(VGP_ppc64be_linux)
    /* ppc64-linux uses the AIX scheme, in which f is a pointer to a
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index bf4a71284..102235dca 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -2274,7 +2274,7 @@ static void final_tidyup(ThreadId tid)
       return; /* won't do it */
    }
 
-#  if defined(VGP_ppc64be_linux)
+#  if defined(VGP_ppc64be_linux) && defined(VG_PLAT_USES_PPCTOC)
    Addr r2 = VG_(get_tocptr)(freeres_wrapper);
    if (r2 == 0) {
       VG_(message)(Vg_UserMsg, 
@@ -2306,9 +2306,11 @@ static void final_tidyup(ThreadId tid)
       directly.  However, we need to set R2 (the toc pointer)
       appropriately. */
    VG_(set_IP)(tid, freeres_wrapper);
-#  if defined(VGP_ppc64be_linux)
+#  if (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+      && defined(VG_PLAT_USES_PPCTOC)
    VG_(threads)[tid].arch.vex.guest_GPR2 = r2;
-#  elif  defined(VGP_ppc64le_linux)
+#  elif  (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+         && !defined(VG_PLAT_USES_PPCTOC)
    /* setting GPR2 but not really needed, GPR12 is needed */
    VG_(threads)[tid].arch.vex.guest_GPR2  = freeres_wrapper;
    VG_(threads)[tid].arch.vex.guest_GPR12 = freeres_wrapper;
@@ -2610,9 +2612,10 @@ asm("\n"
     "\ttrap\n"
     ".previous\n"
 );
-#elif defined(VGP_ppc64be_linux)
+#elif (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+      && defined(VG_PLAT_USES_PPCTOC)
 asm("\n"
-    /* PPC64 ELF ABI says '_start' points to a function descriptor.
+    /* PPC64 ELFv1 ABI says '_start' points to a function descriptor.
        So we must have one, and that is what goes into the .opd section. */
     "\t.align 2\n"
     "\t.global _start\n"
@@ -2656,9 +2659,9 @@ asm("\n"
     "\tnop\n"
     "\ttrap\n"
 );
-#elif defined(VGP_ppc64le_linux)
-/* Little Endian uses ELF version 2 but in the future may also
- * support other ELF versions.
+#elif (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+      && !defined(VG_PLAT_USES_PPCTOC)
+/* ELF version 2 does not use function descriptors.
  */
 asm("\n"
     "\t.align 2\n"
diff --git a/coregrind/m_sigframe/sigframe-ppc64-linux.c b/coregrind/m_sigframe/sigframe-ppc64-linux.c
index b16606c22..cc657838f 100644
--- a/coregrind/m_sigframe/sigframe-ppc64-linux.c
+++ b/coregrind/m_sigframe/sigframe-ppc64-linux.c
@@ -263,7 +263,8 @@ void VG_(sigframe_create)( ThreadId tid,
 
    /* Handler is in fact a standard ppc64-linux function descriptor, 
       so extract the function entry point and also the toc ptr to use. */
-#if defined(VGP_ppc64be_linux)
+#if (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+    && defined(VG_PLAT_USES_PPCTOC)
    SET_SIGNAL_GPR(tid, 2, (Addr) ((ULong*)handler)[1]);
    tst->arch.vex.guest_CIA = (Addr) ((ULong*)handler)[0];
 #else
diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c
index e572f17cc..52d939057 100644
--- a/coregrind/m_signals.c
+++ b/coregrind/m_signals.c
@@ -889,7 +889,9 @@ extern void my_sigreturn(void);
    "	sc\n" \
    ".previous\n"
 
-#elif defined(VGP_ppc64be_linux)
+#elif (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+      && defined(VG_PLAT_USES_PPCTOC)
+/* ELF version 1.  Used in some legacy environments on LE, and most BE. */
 #  define _MY_SIGRETURN(name) \
    ".align   2\n" \
    ".globl   my_sigreturn\n" \
@@ -904,9 +906,10 @@ extern void my_sigreturn(void);
    "	li	0, " #name "\n" \
    "	sc\n"
 
-#elif defined(VGP_ppc64le_linux)
-/* Little Endian supports ELF version 2.  In the future, it may
- * support other versions.
+#elif (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+      && !defined(VG_PLAT_USES_PPCTOC)
+/* ELF version 2.  In the future, PPC64 may support other versions.  Used by
+ * most LE environments and any BE environment running musl libc.
  */
 #  define _MY_SIGRETURN(name) \
    ".align   2\n" \
diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c
index 24f1409dd..9be4c6da9 100644
--- a/coregrind/m_stacktrace.c
+++ b/coregrind/m_stacktrace.c
@@ -726,7 +726,8 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
                                Addr fp_max_orig )
 {
    Bool  lr_is_first_RA = False;
-#  if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux)
+#  if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64be_linux) \
+      || defined(VGP_ppc64le_linux)
    Word redir_stack_size = 0;
    Word redirs_used      = 0;
 #  endif
@@ -787,7 +788,8 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
    redirs_used      = 0;
 #  endif
 
-#  if defined(VG_PLAT_USES_PPCTOC) || defined (VGP_ppc64le_linux)
+#  if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64be_linux) \
+      || defined(VGP_ppc64le_linux)
    /* Deal with bogus LR values caused by function
       interception/wrapping on ppc-TOC platforms; see comment on
       similar code a few lines further down. */
@@ -839,7 +841,8 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
         /* On ppc64-linux (ppc64-elf, really), the lr save
            slot is 2 words back from sp, whereas on ppc32-elf(?) it's
            only one word back. */
-#        if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux)
+#        if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64be_linux) \
+            || defined(VGP_ppc64le_linux)
          const Int lr_offset = 2;
 #        else
          const Int lr_offset = 1;
@@ -858,7 +861,8 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
             else
                ip = (((UWord*)fp)[lr_offset]);
 
-#           if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux)
+#           if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64be_linux) \
+               || defined(VGP_ppc64le_linux)
             /* Nasty hack to do with function replacement/wrapping on
                ppc64-linux.  If LR points to our magic return stub,
                then we are in a wrapped or intercepted function, in
diff --git a/coregrind/m_syscall.c b/coregrind/m_syscall.c
index 5948cecf5..c1cdfab27 100644
--- a/coregrind/m_syscall.c
+++ b/coregrind/m_syscall.c
@@ -470,7 +470,8 @@ asm(
 ".previous\n"
 );
 
-#elif defined(VGP_ppc64be_linux)
+#elif (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+      && defined(VG_PLAT_USES_PPCTOC)
 /* Due to the need to return 65 bits of result, this is completely
    different from the ppc32 case.  The single arg register points to a
    7-word block containing the syscall # and the 6 args.  The syscall
@@ -506,15 +507,15 @@ asm(
 "        blr\n"
 );
 
-#elif defined(VGP_ppc64le_linux)
+#elif (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+      && !defined(VG_PLAT_USES_PPCTOC)
 /* Due to the need to return 65 bits of result, this is completely
    different from the ppc32 case.  The single arg register points to a
    7-word block containing the syscall # and the 6 args.  The syscall
    result proper is put in [0] of the block, and %cr0.so is in the
    bottom bit of [1]. */
 extern void do_syscall_WRK ( ULong* argblock );
-/* Little Endian supports ELF version 2.  In the future, it may support
- * other versions as well.
+/* ELF version 2.  In the future, PPC64 may support other versions as well.
  */
 asm(
 ".align   2\n"
diff --git a/coregrind/m_syswrap/syscall-ppc64be-linux.S b/coregrind/m_syswrap/syscall-ppc64be-linux.S
index 16e9cedc0..db0d8b4aa 100644
--- a/coregrind/m_syswrap/syscall-ppc64be-linux.S
+++ b/coregrind/m_syswrap/syscall-ppc64be-linux.S
@@ -76,11 +76,24 @@
 
 .align 2
 .globl ML_(do_syscall_for_client_WRK)
+#if _CALL_ELF == 2
+.type .ML_(do_syscall_for_client_WRK),@function
+ML_(do_syscall_for_client_WRK):
+0:      addis         2,12,.TOC.-0b@ha
+        addi          2,2,.TOC.-0b@l
+        .localentry   ML_(do_syscall_for_client_WRK), .-ML_(do_syscall_for_client_WRK)
+#else
 .section ".opd","aw"
 .align 3
-ML_(do_syscall_for_client_WRK):	
+ML_(do_syscall_for_client_WRK):
 .quad .ML_(do_syscall_for_client_WRK),.TOC.@tocbase,0
 .previous
+#endif
+#if _CALL_ELF == 2
+0:      addis        2,12,.TOC.-0b@ha
+        addi         2,2,.TOC.-0b@l
+        .localentry  ML_(do_syscall_for_client_WRK), .-ML_(do_syscall_for_client_WRK)
+#endif
 .type .ML_(do_syscall_for_client_WRK),@function
 .globl .ML_(do_syscall_for_client_WRK)
 .ML_(do_syscall_for_client_WRK):
@@ -145,7 +158,9 @@ ML_(do_syscall_for_client_WRK):
 	/* failure: return 0x8000 | error code */
 7:	ori	3,3,0x8000	/* FAILURE -- ensure return value is nonzero */
         b       5b
-
+#if _CALL_ELF == 2
+        .size .ML_(do_syscall_for_client_WRK),.-.ML_(do_syscall_for_client_WRK)
+#endif
 .section .rodata
 /* export the ranges so that
    VG_(fixup_guest_state_after_syscall_interrupted) can do the
diff --git a/coregrind/m_syswrap/syswrap-ppc64-linux.c b/coregrind/m_syswrap/syswrap-ppc64-linux.c
index 6549dd1b3..4ecbe38a6 100644
--- a/coregrind/m_syswrap/syswrap-ppc64-linux.c
+++ b/coregrind/m_syswrap/syswrap-ppc64-linux.c
@@ -41,6 +41,7 @@
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
+#include "pub_core_machine.h"
 #include "pub_core_options.h"
 #include "pub_core_scheduler.h"
 #include "pub_core_sigframe.h"      // For VG_(sigframe_destroy)()
@@ -76,7 +77,8 @@ void ML_(call_on_new_stack_0_1) ( Addr stack,
    address, the second word is the TOC ptr (r2), and the third word is
    the static chain value. */
 asm(
-#if defined(VGP_ppc64be_linux)
+#if (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+    && defined(VG_PLAT_USES_PPCTOC)
 "   .align   2\n"
 "   .globl   vgModuleLocal_call_on_new_stack_0_1\n"
 "   .section \".opd\",\"aw\"\n"
@@ -126,7 +128,7 @@ asm(
 "   bctr\n\t"              // jump to dst
 "   trap\n"                // should never get here
 #else
-//  ppc64le_linux
+//  ppc64 ELFv2 Linux
 "   .align   2\n"
 "   .globl   vgModuleLocal_call_on_new_stack_0_1\n"
 "vgModuleLocal_call_on_new_stack_0_1:\n"
@@ -211,7 +213,8 @@ asm(
 
 // See priv_syswrap-linux.h for arg profile.
 asm(
-#if defined(VGP_ppc64be_linux)
+#if (defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)) \
+    && defined(VG_PLAT_USES_PPCTOC)
 "   .align   2\n"
 "   .globl   do_syscall_clone_ppc64_linux\n"
 "   .section \".opd\",\"aw\"\n"
diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S
index 0488b54bd..d00916aef 100644
--- a/coregrind/m_trampoline.S
+++ b/coregrind/m_trampoline.S
@@ -469,11 +469,11 @@ VG_(ppctoc_magic_redirect_return_stub):
 	.align 2
 	.globl VG_(ppc64_linux_REDIR_FOR_strlen)
 #if !defined VGP_ppc64be_linux || _CALL_ELF == 2
-        /* Little Endian uses ELF version 2 */
+        /* ELF version 2 */
         .type VG_(ppc64_linux_REDIR_FOR_strlen),@function
 VG_(ppc64_linux_REDIR_FOR_strlen):
 #else
-        /* Big Endian uses ELF version 1 */
+        /* ELF version 1 */
 	.section        ".opd","aw"
 	.align 3
 VG_(ppc64_linux_REDIR_FOR_strlen):
diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c
index 3602a4663..bdd1d50ee 100644
--- a/coregrind/m_translate.c
+++ b/coregrind/m_translate.c
@@ -1006,7 +1006,8 @@ static IRExpr* mkU32 ( UInt n ) {
    return IRExpr_Const(IRConst_U32(n));
 }
 
-#if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux)
+#if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64be_linux) \
+    || defined(VGP_ppc64le_linux)
 static IRExpr* mkU8 ( UChar n ) {
    return IRExpr_Const(IRConst_U8(n));
 }
@@ -1234,7 +1234,8 @@ static void gen_push_and_set_LR_R2 ( IRSB* bb, Addr new_R2_value )
 }
 #endif
 
-#if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux)
+#if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64be_linux) \
+    || defined(VGP_ppc64le_linux)
 
 static void gen_pop_R2_LR_then_bLR ( IRSB* bb )
 {
@@ -1263,7 +1264,8 @@ static void gen_pop_R2_LR_then_bLR ( IRSB* bb )
 }
 #endif
 
-#if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux)
+#if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64be_linux) \
+    || defined(VGP_ppc64le_linux)
 
 static
 Bool mk_preamble__ppctoc_magic_return_stub ( void* closureV, IRSB* bb )
@@ -1285,7 +1287,7 @@ Bool mk_preamble__ppctoc_magic_return_stub ( void* closureV, IRSB* bb )
 }
 #endif
 
-#if defined(VGP_ppc64le_linux)
+#if defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
 /* Generate code to push LR and R2 onto this thread's redir stack.
    Need to save R2 in case we redirect to a global entry point.  The
    value of R2 is not preserved when entering the global entry point.
@@ -1366,9 +1368,7 @@ Bool mk_preamble__set_NRADDR_to_zero ( void* closureV, IRSB* bb )
      gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( VG_(current_DiEpoch)(),
                                                    closure->readdr ) );
    }
-#  endif
-
-#if defined(VGP_ppc64le_linux)
+#elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
    VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
    Int offB_GPR12 = offsetof(VexGuestArchState, guest_GPR12);
    addStmtToIRSB(bb, IRStmt_Put(offB_GPR12, mkU64(closure->readdr)));
@@ -1424,7 +1424,6 @@ Bool mk_preamble__set_NRADDR_to_nraddr ( void* closureV, IRSB* bb )
    );
    gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( closure->readdr ) );
-#  endif
-#if defined(VGP_ppc64le_linux)
+#elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
    /* This saves the r2 before leaving the function.  We need to move
     * guest_NRADDR_GPR2 back to R2 on return.
     */
@@ -1648,7 +1647,8 @@ Bool VG_(translate) ( ThreadId tid,
       preamble_fn = mk_preamble__set_NRADDR_to_nraddr;
 
    /* LE we setup the LR */
-#  if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux)
+#  if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64be_linux) \
+      || defined(VGP_ppc64le_linux)
    if (nraddr == (Addr)&VG_(ppctoc_magic_redirect_return_stub)) {
       /* If entering the special return stub, this means a wrapped or
          redirected function is returning.  Make this translation one
@@ -1692,13 +1692,14 @@ Bool VG_(translate) ( ThreadId tid,
    vex_abiinfo.guest_ppc_zap_RZ_at_bl         = NULL;
 #  endif
 
-#  if defined(VGP_ppc64be_linux)
+#  if defined(VGP_ppc64be_linux) && defined(VG_PLAT_USES_PPCTOC)
    vex_abiinfo.guest_ppc_zap_RZ_at_blr        = True;
    vex_abiinfo.guest_ppc_zap_RZ_at_bl         = const_True;
    vex_abiinfo.host_ppc_calls_use_fndescrs    = True;
 #  endif
 
-#  if defined(VGP_ppc64le_linux)
+#  if (defined(VGP_ppc64be_linux) && !defined(VG_PLAT_USES_PPCTOC)) \
+      || defined(VGP_ppc64le_linux)
    vex_abiinfo.guest_ppc_zap_RZ_at_blr        = True;
    vex_abiinfo.guest_ppc_zap_RZ_at_bl         = const_True;
    vex_abiinfo.host_ppc_calls_use_fndescrs    = False;
diff --git a/coregrind/m_ume/elf.c b/coregrind/m_ume/elf.c
index 21eb52bcb..f1e6b4728 100644
--- a/coregrind/m_ume/elf.c
+++ b/coregrind/m_ume/elf.c
@@ -847,8 +847,8 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
    info->exe_base = minaddr + ebase;
    info->exe_end  = maxaddr + ebase;
 
-#if defined(VGP_ppc64be_linux)
-   /* On PPC64BE, ELF ver 1, a func ptr is represented by a TOC entry ptr.
+#if defined(VGP_ppc64be_linux) && defined(VG_PLAT_USES_PPCTOC)
+   /* On PPC64, ELF ver 1, a func ptr is represented by a TOC entry ptr.
       This TOC entry contains three words; the first word is the function
       address, the second word is the TOC ptr (r2), and the third word
       is the static chain value. */
@@ -856,8 +856,8 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info)
    info->init_toc = ((ULong*)entry)[1];
    info->init_ip  += info->interp_offset;
    info->init_toc += info->interp_offset;
-#elif defined(VGP_ppc64le_linux)
-   /* On PPC64LE, ELF ver 2. API doesn't use a func ptr */
+#elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
+   /* On PPC64, ELF ver 2. API doesn't use a func ptr */
    info->init_ip  = (Addr)entry;
    info->init_toc = 0; /* meaningless on this platform */
 #else
diff --git a/coregrind/pub_core_machine.h b/coregrind/pub_core_machine.h
index d6af843df..400148d57 100644
--- a/coregrind/pub_core_machine.h
+++ b/coregrind/pub_core_machine.h
@@ -60,12 +60,20 @@
 #  define VG_ELF_DATA2XXX     ELFDATA2MSB
 #  define VG_ELF_MACHINE      EM_PPC64
 #  define VG_ELF_CLASS        ELFCLASS64
-#  define VG_PLAT_USES_PPCTOC 1
+#  if !defined(_CALL_ELF) || _CALL_ELF == 1
+#    define VG_PLAT_USES_PPCTOC 1
+#  else
+#    undef VG_PLAT_USES_PPCTOC
+#  endif
 #elif defined(VGP_ppc64le_linux)
 #  define VG_ELF_DATA2XXX     ELFDATA2LSB
 #  define VG_ELF_MACHINE      EM_PPC64
 #  define VG_ELF_CLASS        ELFCLASS64
-#  undef VG_PLAT_USES_PPCTOC
+#  if defined(_CALL_ELF) && _CALL_ELF == 1
+#    define VG_PLAT_USES_PPCTOC 1
+#  else  // assume ELFv2 by default if no ABI is specified
+#    undef VG_PLAT_USES_PPCTOC
+#  endif
 #elif defined(VGP_arm_linux)
 #  define VG_ELF_DATA2XXX     ELFDATA2LSB
 #  define VG_ELF_MACHINE      EM_ARM
diff --git a/coregrind/vg_preloaded.c b/coregrind/vg_preloaded.c
index ad033432a..f300fbe80 100644
--- a/coregrind/vg_preloaded.c
+++ b/coregrind/vg_preloaded.c
@@ -45,6 +45,7 @@
 #include "pub_core_basics.h"
 #include "pub_core_clreq.h"
 #include "pub_core_debuginfo.h"  // Needed for pub_core_redir.h
+#include "pub_core_machine.h"    // For VG_PLAT_USES_PPCTOC
 #include "pub_core_redir.h"      // For VG_NOTIFY_ON_LOAD
 
 #if defined(VGO_linux) || defined(VGO_solaris)
@@ -103,7 +104,7 @@ void * VG_NOTIFY_ON_LOAD(ifunc_wrapper) (void)
     VALGRIND_GET_ORIG_FN(fn);
     CALL_FN_W_v(result, fn);
 
-#if defined(VGP_ppc64be_linux)
+#if defined(VGP_ppc64be_linux) && defined(VG_PLAT_USES_PPCTOC)
    /* ppc64be uses function descriptors, so get the actual function entry
       address for the client request, but return the function descriptor
       from this function. 
diff --git a/include/valgrind.h b/include/valgrind.h
index 577c8f05e..99e058ccf 100644
--- a/include/valgrind.h
+++ b/include/valgrind.h
@@ -143,12 +143,20 @@
 #  define PLAT_amd64_linux 1
 #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
 #  define PLAT_ppc32_linux 1
-#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF != 2
-/* Big Endian uses ELF version 1 */
+#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && defined(__BIG_ENDIAN__)
 #  define PLAT_ppc64be_linux 1
-#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF == 2
-/* Little Endian uses ELF version 2 */
+#  if _CALL_ELF == 2
+#    define PLAT_ppc64_linux_abi2
+#  else
+#    define PLAT_ppc64_linux_abi1
+#  endif
+#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && !defined(__BIG_ENDIAN__)
 #  define PLAT_ppc64le_linux 1
+#  if _CALL_ELF == 2
+#    define PLAT_ppc64_linux_abi2
+#  else
+#    define PLAT_ppc64_linux_abi1
+#  endif
 #elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__)
 #  define PLAT_arm_linux 1
 #elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__)
diff --git a/memcheck/mc_leakcheck.c b/memcheck/mc_leakcheck.c
index 782244481..c239f5b10 100644
--- a/memcheck/mc_leakcheck.c
+++ b/memcheck/mc_leakcheck.c
@@ -653,7 +653,7 @@ static Bool aligned_ptr_above_page0_is_vtable_addr(Addr ptr)
       if (pot_fn == 0)
          continue; // NULL fn pointer. Seems it can happen in vtable.
       seg = VG_(am_find_nsegment) (pot_fn);
-#if defined(VGA_ppc64be)
+#if defined(VGA_ppc64be) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
       // ppc64BE uses a thunk table (function descriptors), so we have one
       // more level of indirection to follow.
       if (seg == NULL
diff --git a/memcheck/mc_machine.c b/memcheck/mc_machine.c
index 5ed101fca..70c64b361 100644
--- a/memcheck/mc_machine.c
+++ b/memcheck/mc_machine.c
@@ -132,7 +132,8 @@ static Int get_otrack_shadow_offset_wrk ( Int offset, Int szB )
             return GOF(GPRn);
          by testing ox instead of o, and setting ox back 4 bytes when sz == 4.
       */
-#if defined(VGA_ppc64le)
+#if (defined(VGA_ppc64be) && (defined(_CALL_ELF) && _CALL_ELF == 2)) \
+    || defined(VGA_ppc64le)
       Int ox = o;
 #else
       Int ox = sz == 8 ? o : (o - 4);
-- 
2.18.0