summaryrefslogtreecommitdiff
path: root/packages/glibc/2.17/0061-glibc-ppc64le-39.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/glibc/2.17/0061-glibc-ppc64le-39.patch')
-rw-r--r--packages/glibc/2.17/0061-glibc-ppc64le-39.patch508
1 files changed, 508 insertions, 0 deletions
diff --git a/packages/glibc/2.17/0061-glibc-ppc64le-39.patch b/packages/glibc/2.17/0061-glibc-ppc64le-39.patch
new file mode 100644
index 0000000..f837d99
--- /dev/null
+++ b/packages/glibc/2.17/0061-glibc-ppc64le-39.patch
@@ -0,0 +1,508 @@
+# commit 696caf1d002ff059ddd20fd5eaccd76229c14850
+# Author: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+# Date: Wed Dec 4 06:51:11 2013 -0600
+#
+# PowerPC64 ELFv2 ABI 2/6: Remove function descriptors
+#
+# This patch adds support for the ELFv2 ABI feature to remove function
+# descriptors. See this GCC patch for in-depth discussion:
+# http://gcc.gnu.org/ml/gcc-patches/2013-11/msg01141.html
+#
+# This mostly involves two types of changes: updating assembler source
+# files to the new logic, and updating the dynamic loader.
+#
+# After the refactoring in the previous patch, most of the assembler source
+# changes can be handled simply by providing ELFv2 versions of the
+# macros in sysdep.h. One somewhat non-obvious change is in __GI__setjmp:
+# this used to "fall through" to the immediately following __setjmp ENTRY
+# point. This is no longer safe in the ELFv2 since ENTRY defines both
+# a global and a local entry point, and you cannot simply fall through
+# to a global entry point as it requires r12 to be set up.
+#
+# Also, makecontext needs to be updated to set up registers according to
+# the new ABI for calling into the context's start routine.
+#
+# The dynamic linker changes mostly consist of removing special code
+# to handle function descriptors. We also need to support the new PLT
+# and glink format used by the the ELFv2 linker, see:
+# https://sourceware.org/ml/binutils/2013-10/msg00376.html
+#
+# In addition, the dynamic linker now verifies that the dynamic libraries
+# it loads match its own ABI.
+#
+# The hack in VDSO_IFUNC_RET to "synthesize" a function descriptor
+# for vDSO routines is also no longer necessary for ELFv2.
+#
+diff -urN glibc-2.17-c758a686/elf/elf.h glibc-2.17-c758a686/elf/elf.h
+--- glibc-2.17-c758a686/elf/elf.h 2014-05-29 13:58:25.000000000 -0500
++++ glibc-2.17-c758a686/elf/elf.h 2014-05-29 13:58:25.000000000 -0500
+@@ -2263,6 +2263,12 @@
+ #define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */
+ #define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */
+
++/* e_flags bits specifying ABI.
++ 1 for original function descriptor using ABI,
++ 2 for revised ABI without function descriptors,
++ 0 for unspecified or not using any features affected by the differences. */
++#define EF_PPC64_ABI 3
++
+ /* PowerPC64 specific values for the Dyn d_tag field. */
+ #define DT_PPC64_GLINK (DT_LOPROC + 0)
+ #define DT_PPC64_OPD (DT_LOPROC + 1)
+diff -urN glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/crti.S glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/crti.S
+--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/crti.S 2014-05-29 13:58:25.000000000 -0500
++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/crti.S 2014-05-29 13:58:25.000000000 -0500
+@@ -64,6 +64,7 @@
+ ENTRY_2(_init)
+ .align ALIGNARG (2)
+ BODY_LABEL (_init):
++ LOCALENTRY(_init)
+ mflr 0
+ std 0, 16(r1)
+ stdu r1, -112(r1)
+@@ -81,6 +82,7 @@
+ ENTRY_2(_fini)
+ .align ALIGNARG (2)
+ BODY_LABEL (_fini):
++ LOCALENTRY(_fini)
+ mflr 0
+ std 0, 16(r1)
+ stdu r1, -112(r1)
+diff -urN glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/dl-irel.h glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/dl-irel.h
+--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/dl-irel.h 2014-05-29 13:58:25.000000000 -0500
++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/dl-irel.h 2014-05-29 13:58:25.000000000 -0500
+@@ -50,7 +50,11 @@
+ {
+ Elf64_Addr *const reloc_addr = (void *) reloc->r_offset;
+ Elf64_Addr value = elf_ifunc_invoke(reloc->r_addend);
++#if _CALL_ELF != 2
+ *(Elf64_FuncDesc *) reloc_addr = *(Elf64_FuncDesc *) value;
++#else
++ *reloc_addr = value;
++#endif
+ }
+ else
+ __libc_fatal ("unexpected reloc type in static binary");
+diff -urN glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/dl-machine.h glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/dl-machine.h
+--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/dl-machine.h 2014-05-29 13:58:25.000000000 -0500
++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/dl-machine.h 2014-05-29 14:05:46.000000000 -0500
+@@ -31,6 +31,7 @@
+ in l_info array. */
+ #define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM)
+
++#if _CALL_ELF != 2
+ /* A PowerPC64 function descriptor. The .plt (procedure linkage
+ table) and .opd (official procedure descriptor) sections are
+ arrays of these. */
+@@ -40,6 +41,7 @@
+ Elf64_Addr fd_toc;
+ Elf64_Addr fd_aux;
+ } Elf64_FuncDesc;
++#endif
+
+ #define ELF_MULT_MACHINES_SUPPORTED
+
+@@ -47,6 +49,18 @@
+ static inline int
+ elf_machine_matches_host (const Elf64_Ehdr *ehdr)
+ {
++ /* Verify that the binary matches our ABI version. */
++ if ((ehdr->e_flags & EF_PPC64_ABI) != 0)
++ {
++#if _CALL_ELF != 2
++ if ((ehdr->e_flags & EF_PPC64_ABI) != 1)
++ return 0;
++#else
++ if ((ehdr->e_flags & EF_PPC64_ABI) != 2)
++ return 0;
++#endif
++ }
++
+ return ehdr->e_machine == EM_PPC64;
+ }
+
+@@ -124,6 +138,7 @@
+ " .align 2\n" \
+ " " ENTRY_2(_start) "\n" \
+ BODY_PREFIX "_start:\n" \
++" " LOCALENTRY(_start) "\n" \
+ /* We start with the following on the stack, from top: \
+ argc (4 bytes); \
+ arguments for program (terminated by NULL); \
+@@ -165,6 +180,7 @@
+ Changing these is strongly discouraged (not least because argc is \
+ passed by value!). */ \
+ BODY_PREFIX "_dl_start_user:\n" \
++" " LOCALENTRY(_dl_start_user) "\n" \
+ /* the address of _start in r30. */ \
+ " mr 30,3\n" \
+ /* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \
+@@ -256,8 +272,22 @@
+ relocations behave "normally", ie. always use the real address
+ like PLT relocations. So always set ELF_RTYPE_CLASS_PLT. */
+
++#if _CALL_ELF != 2
+ #define elf_machine_type_class(type) \
+ (ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
++#else
++/* And now that you have read that large comment, you can disregard it
++ all for ELFv2. ELFv2 does need the special SHN_UNDEF treatment. */
++#define IS_PPC64_TLS_RELOC(R) \
++ (((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) \
++ || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA))
++
++#define elf_machine_type_class(type) \
++ ((((type) == R_PPC64_JMP_SLOT \
++ || (type) == R_PPC64_ADDR24 \
++ || IS_PPC64_TLS_RELOC (type)) * ELF_RTYPE_CLASS_PLT) \
++ | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
++#endif
+
+ /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
+ #define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
+@@ -266,8 +296,19 @@
+ #define ELF_MACHINE_NO_REL 1
+
+ /* Stuff for the PLT. */
++#if _CALL_ELF != 2
+ #define PLT_INITIAL_ENTRY_WORDS 3
++#define PLT_ENTRY_WORDS 3
+ #define GLINK_INITIAL_ENTRY_WORDS 8
++/* The first 32k entries of glink can set an index and branch using two
++ instructions; past that point, glink uses three instructions. */
++#define GLINK_ENTRY_WORDS(I) (((I) < 0x8000)? 2 : 3)
++#else
++#define PLT_INITIAL_ENTRY_WORDS 2
++#define PLT_ENTRY_WORDS 1
++#define GLINK_INITIAL_ENTRY_WORDS 8
++#define GLINK_ENTRY_WORDS(I) 1
++#endif
+
+ #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory")
+ #define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory")
+@@ -312,17 +353,12 @@
+
+ if (lazy)
+ {
+- /* The function descriptor of the appropriate trampline
+- routine is used to set the 1st and 2nd doubleword of the
+- plt_reserve. */
+- Elf64_FuncDesc *resolve_fd;
+ Elf64_Word glink_offset;
+- /* the plt_reserve area is the 1st 3 doublewords of the PLT */
+- Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
+ Elf64_Word offset;
++ Elf64_Addr dlrr;
+
+- resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve
+- : _dl_runtime_resolve);
++ dlrr = (Elf64_Addr) (profile ? _dl_profile_resolve
++ : _dl_runtime_resolve);
+ if (profile && GLRO(dl_profile) != NULL
+ && _dl_name_match_p (GLRO(dl_profile), map))
+ /* This is the object we are looking for. Say that we really
+@@ -330,20 +366,33 @@
+ GL(dl_profile_map) = map;
+
+
++#if _CALL_ELF != 2
+ /* We need to stuff the address/TOC of _dl_runtime_resolve
+ into doublewords 0 and 1 of plt_reserve. Then we need to
+ stuff the map address into doubleword 2 of plt_reserve.
+ This allows the GLINK0 code to transfer control to the
+ correct trampoline which will transfer control to fixup
+ in dl-machine.c. */
+- plt_reserve->fd_func = resolve_fd->fd_func;
+- plt_reserve->fd_toc = resolve_fd->fd_toc;
+- plt_reserve->fd_aux = (Elf64_Addr) map;
++ {
++ /* The plt_reserve area is the 1st 3 doublewords of the PLT. */
++ Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt;
++ Elf64_FuncDesc *resolve_fd = (Elf64_FuncDesc *) dlrr;
++ plt_reserve->fd_func = resolve_fd->fd_func;
++ plt_reserve->fd_toc = resolve_fd->fd_toc;
++ plt_reserve->fd_aux = (Elf64_Addr) map;
+ #ifdef RTLD_BOOTSTRAP
+- /* When we're bootstrapping, the opd entry will not have
+- been relocated yet. */
+- plt_reserve->fd_func += l_addr;
+- plt_reserve->fd_toc += l_addr;
++ /* When we're bootstrapping, the opd entry will not have
++ been relocated yet. */
++ plt_reserve->fd_func += l_addr;
++ plt_reserve->fd_toc += l_addr;
++#endif
++ }
++#else
++ /* When we don't have function descriptors, the first doubleword
++ of the PLT holds the address of _dl_runtime_resolve, and the
++ second doubleword holds the map address. */
++ plt[0] = dlrr;
++ plt[1] = (Elf64_Addr) map;
+ #endif
+
+ /* Set up the lazy PLT entries. */
+@@ -354,14 +403,8 @@
+ {
+
+ plt[offset] = (Elf64_Xword) &glink[glink_offset];
+- offset += 3;
+- /* The first 32k entries of glink can set an index and
+- branch using two instructions; Past that point,
+- glink uses three instructions. */
+- if (i < 0x8000)
+- glink_offset += 2;
+- else
+- glink_offset += 3;
++ offset += PLT_ENTRY_WORDS;
++ glink_offset += GLINK_ENTRY_WORDS (i);
+ }
+
+ /* Now, we've modified data. We need to write the changes from
+@@ -389,6 +432,7 @@
+ const Elf64_Rela *reloc,
+ Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
+ {
++#if _CALL_ELF != 2
+ Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
+ Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
+ Elf64_Addr offset = 0;
+@@ -426,6 +470,9 @@
+ plt->fd_func = rel->fd_func + offset;
+ PPC_DCBST (&plt->fd_func);
+ PPC_ISYNC;
++#else
++ *reloc_addr = finaladdr;
++#endif
+
+ return finaladdr;
+ }
+@@ -433,6 +480,7 @@
+ static inline void __attribute__ ((always_inline))
+ elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr)
+ {
++#if _CALL_ELF != 2
+ Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr;
+ Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr;
+
+@@ -443,6 +491,9 @@
+ PPC_DCBST (&plt->fd_aux);
+ PPC_DCBST (&plt->fd_toc);
+ PPC_SYNC;
++#else
++ *reloc_addr = finaladdr;
++#endif
+ }
+
+ /* Return the final value of a plt relocation. */
+@@ -512,6 +563,7 @@
+ resolve_ifunc (Elf64_Addr value,
+ const struct link_map *map, const struct link_map *sym_map)
+ {
++#if _CALL_ELF != 2
+ #ifndef RESOLVE_CONFLICT_FIND_MAP
+ /* The function we are calling may not yet have its opd entry relocated. */
+ Elf64_FuncDesc opd;
+@@ -529,6 +581,7 @@
+ value = (Elf64_Addr) &opd;
+ }
+ #endif
++#endif
+ return ((Elf64_Addr (*) (unsigned long int)) value) (GLRO(dl_hwcap));
+ }
+
+diff -urN glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/setjmp-common.S glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/setjmp-common.S
+--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/setjmp-common.S 2014-05-29 13:58:25.000000000 -0500
++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/setjmp-common.S 2014-05-29 14:00:27.000000000 -0500
+@@ -55,21 +55,22 @@
+ that saves r2 since the call won't go via a plt call stub. See
+ bugz #269. __GI__setjmp is used in csu/libc-start.c when
+ HAVE_CLEANUP_JMP_BUF is defined. */
+-ENTRY (BP_SYM (__GI__setjmp))
++ENTRY (__GI__setjmp)
+ std r2,40(r1) /* Save the callers TOC in the save area. */
+- cfi_endproc
+-END_2 (BP_SYM (__GI__setjmp))
+-/* Fall thru. */
++ CALL_MCOUNT 1
++ li r4,0 /* Set second argument to 0. */
++ b JUMPTARGET (GLUE(__sigsetjmp,_ent))
++END (__GI__setjmp)
+ #endif
+
+-ENTRY (BP_SYM (_setjmp))
++ENTRY (_setjmp)
+ CALL_MCOUNT 1
+ li r4,0 /* Set second argument to 0. */
+ b JUMPTARGET (GLUE(__sigsetjmp,_ent))
+-END (BP_SYM (_setjmp))
++END (_setjmp)
+ libc_hidden_def (_setjmp)
+
+-ENTRY (BP_SYM (__sigsetjmp))
++ENTRY (__sigsetjmp)
+ CALL_MCOUNT 2
+ JUMPTARGET(GLUE(__sigsetjmp,_ent)):
+ CHECK_BOUNDS_BOTH_WIDE_LIT (r3, r8, r9, JB_SIZE)
+@@ -215,18 +216,18 @@
+ li r3,0
+ blr
+ #elif defined SHARED
+- b JUMPTARGET (BP_SYM (__sigjmp_save))
++ b JUMPTARGET (__sigjmp_save)
+ #else
+ mflr r0
+ std r0,16(r1)
+ stdu r1,-112(r1)
+ cfi_adjust_cfa_offset(112)
+ cfi_offset(lr,16)
+- bl JUMPTARGET (BP_SYM (__sigjmp_save))
++ bl JUMPTARGET (__sigjmp_save)
+ nop
+ ld r0,112+16(r1)
+ addi r1,r1,112
+ mtlr r0
+ blr
+ #endif
+-END (BP_SYM (__sigsetjmp))
++END (__sigsetjmp)
+diff -urN glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/sysdep.h glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/sysdep.h
+--- glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/sysdep.h 2014-05-29 13:58:25.000000000 -0500
++++ glibc-2.17-c758a686/sysdeps/powerpc/powerpc64/sysdep.h 2014-05-29 13:58:25.000000000 -0500
+@@ -74,6 +74,8 @@
+ #endif
+ .endm
+
++#if _CALL_ELF != 2
++
+ /* Macro to prepare for calling via a function pointer. */
+ .macro PPC64_LOAD_FUNCPTR PTR
+ ld r12,0(\PTR)
+@@ -115,13 +117,37 @@
+ .size name,.-BODY_LABEL(name); \
+ .size BODY_LABEL(name),.-BODY_LABEL(name);
+ #endif
++#define LOCALENTRY(name)
++
++#else /* _CALL_ELF */
++
++/* Macro to prepare for calling via a function pointer. */
++ .macro PPC64_LOAD_FUNCPTR PTR
++ mr r12,\PTR
++ mtctr r12
++ .endm
++
++#define DOT_LABEL(X) X
++#define BODY_LABEL(X) X
++#define ENTRY_2(name) \
++ .globl name; \
++ .type name,@function;
++#define END_2(name) \
++ .size name,.-name;
++#define LOCALENTRY(name) \
++1: addis r2,r12,.TOC.-1b@ha; \
++ addi r2,r2,.TOC.-1b@l; \
++ .localentry name,.-name;
++
++#endif /* _CALL_ELF */
+
+ #define ENTRY(name) \
+ .section ".text"; \
+ ENTRY_2(name) \
+ .align ALIGNARG(2); \
+ BODY_LABEL(name): \
+- cfi_startproc;
++ cfi_startproc; \
++ LOCALENTRY(name)
+
+ #define EALIGN_W_0 /* No words to insert. */
+ #define EALIGN_W_1 nop
+@@ -140,7 +166,8 @@
+ .align ALIGNARG(alignt); \
+ EALIGN_W_##words; \
+ BODY_LABEL(name): \
+- cfi_startproc;
++ cfi_startproc; \
++ LOCALENTRY(name)
+
+ /* Local labels stripped out by the linker. */
+ #undef L
+@@ -295,6 +322,8 @@
+
+ #else /* !__ASSEMBLER__ */
+
++#if _CALL_ELF != 2
++
+ #define PPC64_LOAD_FUNCPTR(ptr) \
+ "ld 12,0(" #ptr ");\n" \
+ "ld 2,8(" #ptr ");\n" \
+@@ -335,5 +364,26 @@
+ ".size " #name ",.-" BODY_PREFIX #name ";\n" \
+ ".size " BODY_PREFIX #name ",.-" BODY_PREFIX #name ";"
+ #endif
++#define LOCALENTRY(name)
++
++#else /* _CALL_ELF */
++
++#define PPC64_LOAD_FUNCPTR(ptr) \
++ "mr 12," #ptr ";\n" \
++ "mtctr 12;"
++
++#define DOT_PREFIX ""
++#define BODY_PREFIX ""
++#define ENTRY_2(name) \
++ ".type " #name ",@function;\n" \
++ ".globl " #name ";"
++#define END_2(name) \
++ ".size " #name ",.-" #name ";"
++#define LOCALENTRY(name) \
++ "1: addis 2,12,.TOC.-1b@ha;\n" \
++ "addi 2,2,.TOC.-1b@l;\n" \
++ ".localentry " #name ",.-" #name ";"
++
++#endif /* _CALL_ELF */
+
+ #endif /* __ASSEMBLER__ */
+diff -urN glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h
+--- glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h 2014-05-29 13:58:24.000000000 -0500
++++ glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h 2014-05-29 13:58:25.000000000 -0500
+@@ -23,6 +23,8 @@
+
+ /* Now define our stuff. */
+
++#if _CALL_ELF != 2
++
+ static __always_inline bool
+ _dl_ppc64_is_opd_sym (const struct link_map *l, const ElfW(Sym) *sym)
+ {
+@@ -73,4 +75,6 @@
+ #define DL_ADDR_SYM_MATCH(L, SYM, MATCHSYM, ADDR) \
+ _dl_ppc64_addr_sym_match (L, SYM, MATCHSYM, ADDR)
+
++#endif
++
+ #endif /* ldsodefs.h */
+diff -urN glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/makecontext.S glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/makecontext.S
+--- glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/makecontext.S 2014-05-29 13:58:24.000000000 -0500
++++ glibc-2.17-c758a686/sysdeps/unix/sysv/linux/powerpc/powerpc64/makecontext.S 2014-05-29 13:58:25.000000000 -0500
+@@ -111,6 +111,7 @@
+
+ L(noparms):
+
++#if _CALL_ELF != 2
+ /* Load the function address and TOC from the function descriptor
+ and store them in the ucontext as NIP and r2. Store the 3rd
+ field of the function descriptor into the ucontext as r11 in case
+@@ -121,6 +122,12 @@
+ std r0,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r3)
+ std r10,(SIGCONTEXT_GP_REGS+(PT_R2*8))(r3)
+ std r9,(SIGCONTEXT_GP_REGS+(PT_R11*8))(r3)
++#else
++ /* In the ELFv2 ABI, the function pointer is already the address.
++ Store it as NIP and r12 as required by the ABI. */
++ std r4,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r3)
++ std r4,(SIGCONTEXT_GP_REGS+(PT_R12*8))(r3)
++#endif
+
+ /* If the target function returns we need to do some cleanup. We use a
+ code trick to get the address of our cleanup function into the link