]> git.proxmox.com Git - mirror_qemu.git/commitdiff
linux-user/ppc: Add vdso
authorRichard Henderson <richard.henderson@linaro.org>
Tue, 15 Aug 2023 00:58:55 +0000 (17:58 -0700)
committerRichard Henderson <richard.henderson@linaro.org>
Mon, 30 Oct 2023 20:41:56 +0000 (13:41 -0700)
Add support in gen-vdso-elfn.c.inc for the DT_PPC64_OPT
dynamic tag: this is an integer, so does not need relocation.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12 files changed:
linux-user/elfload.c
linux-user/gen-vdso-elfn.c.inc
linux-user/ppc/Makefile.vdso [new file with mode: 0644]
linux-user/ppc/meson.build
linux-user/ppc/signal.c
linux-user/ppc/vdso-32.ld [new file with mode: 0644]
linux-user/ppc/vdso-32.so [new file with mode: 0755]
linux-user/ppc/vdso-64.ld [new file with mode: 0644]
linux-user/ppc/vdso-64.so [new file with mode: 0755]
linux-user/ppc/vdso-64le.so [new file with mode: 0755]
linux-user/ppc/vdso-asmoffset.h [new file with mode: 0644]
linux-user/ppc/vdso.S [new file with mode: 0644]

index 4e6e0059e67e47010c71369b6d7d3a61fbe85a23..26602516aa7381e6a8d3b5f30fe12e8a93bcaa3c 100644 (file)
@@ -1187,6 +1187,14 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE       4096
 
+#ifndef TARGET_PPC64
+# define VDSO_HEADER  "vdso-32.c.inc"
+#elif TARGET_BIG_ENDIAN
+# define VDSO_HEADER  "vdso-64.c.inc"
+#else
+# define VDSO_HEADER  "vdso-64le.c.inc"
+#endif
+
 #endif
 
 #ifdef TARGET_LOONGARCH64
index 7034c36d5e28abc35ace7a7a8182080671d177ba..95856eb839b516085e119f6b368907ebe1f5b886 100644 (file)
@@ -273,7 +273,14 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
                 errors++;
                 break;
 
+            case PT_LOPROC + 3:
+                if (ehdr->e_machine == EM_PPC64) {
+                    break;  /* DT_PPC64_OPT: integer bitmask */
+                }
+                goto do_default;
+
             default:
+            do_default:
                 /* This is probably something target specific. */
                 fprintf(stderr, "VDSO has unknown DYNAMIC entry (%lx)\n",
                         (unsigned long)tag);
diff --git a/linux-user/ppc/Makefile.vdso b/linux-user/ppc/Makefile.vdso
new file mode 100644 (file)
index 0000000..3ca3c6b
--- /dev/null
@@ -0,0 +1,20 @@
+include $(BUILD_DIR)/tests/tcg/ppc64-linux-user/config-target.mak
+
+SUBDIR = $(SRC_PATH)/linux-user/ppc
+VPATH += $(SUBDIR)
+
+all: $(SUBDIR)/vdso-32.so $(SUBDIR)/vdso-64.so $(SUBDIR)/vdso-64le.so
+
+LDFLAGS32 = -nostdlib -shared -Wl,-T,$(SUBDIR)/vdso-32.ld \
+            -Wl,-h,linux-vdso32.so.1 -Wl,--hash-style=both -Wl,--build-id=sha1
+LDFLAGS64 = -nostdlib -shared -Wl,-T,$(SUBDIR)/vdso-64.ld \
+            -Wl,-h,linux-vdso64.so.1 -Wl,--hash-style=both -Wl,--build-id=sha1
+
+$(SUBDIR)/vdso-32.so: vdso.S vdso-32.ld vdso-asmoffset.h
+       $(CC) -o $@ $(LDFLAGS32) -m32 $<
+
+$(SUBDIR)/vdso-64.so: vdso.S vdso-64.ld vdso-asmoffset.h
+       $(CC) -o $@ $(LDFLAGS64) -mbig-endian $<
+
+$(SUBDIR)/vdso-64le.so: vdso.S vdso-64.ld vdso-asmoffset.h
+       $(CC) -o $@ $(LDFLAGS64) -mlittle-endian $<
index 19fead7bc83b22839701ed5e0953b36efd6dad19..80cacae396b774d45cc214e3a4d41d069f1ac87f 100644 (file)
@@ -3,3 +3,15 @@ syscall_nr_generators += {
                    arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
                    output: '@BASENAME@_nr.h')
 }
+
+vdso_32_inc = gen_vdso.process('vdso-32.so', extra_args: [
+                                   '-s', '__kernel_sigtramp32',
+                                   '-r', '__kernel_sigtramp_rt32'
+                               ])
+linux_user_ss.add(when: 'TARGET_PPC', if_true: vdso_32_inc)
+
+vdso_64_inc = gen_vdso.process('vdso-64.so',
+                               extra_args: ['-r', '__kernel_sigtramp_rt64'])
+vdso_64le_inc = gen_vdso.process('vdso-64le.so',
+                                 extra_args: ['-r', '__kernel_sigtramp_rt64'])
+linux_user_ss.add(when: 'TARGET_PPC64', if_true: [vdso_64_inc, vdso_64le_inc])
index a616f20efbd835f037998b6fcff0baf7293472d8..7e7302823b00316cce34d6ff2955b3f0622ed392 100644 (file)
 #include "user-internals.h"
 #include "signal-common.h"
 #include "linux-user/trace.h"
-
-/* Size of dummy stack frame allocated when calling signal handler.
-   See arch/powerpc/include/asm/ptrace.h.  */
-#if defined(TARGET_PPC64)
-#define SIGNAL_FRAMESIZE 128
-#else
-#define SIGNAL_FRAMESIZE 64
-#endif
+#include "vdso-asmoffset.h"
 
 /* See arch/powerpc/include/asm/ucontext.h.  Only used for 32-bit PPC;
    on 64-bit PPC, sigcontext and mcontext are one and the same.  */
@@ -73,6 +66,16 @@ struct target_mcontext {
 #endif
 };
 
+QEMU_BUILD_BUG_ON(offsetof(struct target_mcontext, mc_fregs)
+                  != offsetof_mcontext_fregs);
+#if defined(TARGET_PPC64)
+QEMU_BUILD_BUG_ON(offsetof(struct target_mcontext, v_regs)
+                  != offsetof_mcontext_vregs_ptr);
+#else
+QEMU_BUILD_BUG_ON(offsetof(struct target_mcontext, mc_vregs)
+                  != offsetof_mcontext_vregs);
+#endif
+
 /* See arch/powerpc/include/asm/sigcontext.h.  */
 struct target_sigcontext {
     target_ulong _unused[4];
@@ -161,6 +164,7 @@ struct target_ucontext {
 #endif
 };
 
+#if !defined(TARGET_PPC64)
 /* See arch/powerpc/kernel/signal_32.c.  */
 struct target_sigframe {
     struct target_sigcontext sctx;
@@ -168,6 +172,10 @@ struct target_sigframe {
     int32_t abigap[56];
 };
 
+QEMU_BUILD_BUG_ON(offsetof(struct target_sigframe, mctx)
+                  != offsetof_sigframe_mcontext);
+#endif
+
 #if defined(TARGET_PPC64)
 
 #define TARGET_TRAMP_SIZE 6
@@ -184,6 +192,10 @@ struct target_rt_sigframe {
     char abigap[288];
 } __attribute__((aligned(16)));
 
+QEMU_BUILD_BUG_ON(offsetof(struct target_rt_sigframe,
+                           uc.tuc_sigcontext.mcontext)
+                  != offsetof_rt_sigframe_mcontext);
+
 #else
 
 struct target_rt_sigframe {
@@ -192,6 +204,9 @@ struct target_rt_sigframe {
     int32_t abigap[56];
 };
 
+QEMU_BUILD_BUG_ON(offsetof(struct target_rt_sigframe, uc.tuc_mcontext)
+                  != offsetof_rt_sigframe_mcontext);
+
 #endif
 
 #if defined(TARGET_PPC64)
diff --git a/linux-user/ppc/vdso-32.ld b/linux-user/ppc/vdso-32.ld
new file mode 100644 (file)
index 0000000..6962696
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Linker script for linux powerpc64 replacement vdso.
+ *
+ * Copyright 2023 Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+VERSION {
+        LINUX_2.6.15 {
+        global:
+                __kernel_gettimeofday;
+                __kernel_clock_gettime;
+                __kernel_clock_gettime64;
+                __kernel_clock_getres;
+                __kernel_time;
+                __kernel_sync_dicache;
+                __kernel_sigtramp32;
+                __kernel_sigtramp_rt32;
+                __kernel_getcpu;
+        local: *;
+        };
+}
+
+PHDRS {
+        phdr            PT_PHDR         FLAGS(4) PHDRS;
+        load            PT_LOAD         FLAGS(7) FILEHDR PHDRS; /* FLAGS=RWX */
+        dynamic         PT_DYNAMIC      FLAGS(4);
+        eh_frame_hdr    PT_GNU_EH_FRAME;
+        note            PT_NOTE         FLAGS(4);
+}
+
+SECTIONS {
+        . = SIZEOF_HEADERS;
+
+        /*
+         * The following, including the FILEHDRS and PHDRS, are modified
+         * when we relocate the binary.  We want them to be initially
+         * writable for the relocation; we'll force them read-only after.
+         */
+        .note           : { *(.note*) }         :load :note
+        .dynamic        : { *(.dynamic) }       :load :dynamic
+        .dynsym         : { *(.dynsym) }        :load
+        .data           : {
+                /*
+                 * There ought not be any real read-write data.
+                 * But since we manipulated the segment layout,
+                 * we have to put these sections somewhere.
+                 */
+                *(.data*)
+                *(.sdata*)
+                *(.got.plt) *(.got)
+                *(.gnu.linkonce.d.*)
+                *(.bss*)
+                *(.dynbss*)
+                *(.gnu.linkonce.b.*)
+        }
+
+        .rodata         : { *(.rodata*) }
+        .hash           : { *(.hash) }
+        .gnu.hash       : { *(.gnu.hash) }
+        .dynstr         : { *(.dynstr) }
+        .gnu.version    : { *(.gnu.version) }
+        .gnu.version_d  : { *(.gnu.version_d) }
+        .gnu.version_r  : { *(.gnu.version_r) }
+        .eh_frame_hdr   : { *(.eh_frame_hdr) }  :load :eh_frame_hdr
+        .eh_frame       : { *(.eh_frame) }      :load
+
+        .text           : { *(.text*) }         :load
+}
diff --git a/linux-user/ppc/vdso-32.so b/linux-user/ppc/vdso-32.so
new file mode 100755 (executable)
index 0000000..b19baaf
Binary files /dev/null and b/linux-user/ppc/vdso-32.so differ
diff --git a/linux-user/ppc/vdso-64.ld b/linux-user/ppc/vdso-64.ld
new file mode 100644 (file)
index 0000000..a55c65e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Linker script for linux powerpc64 replacement vdso.
+ *
+ * Copyright 2023 Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+VERSION {
+        LINUX_2.6.15 {
+        global:
+                __kernel_gettimeofday;
+                __kernel_clock_gettime;
+                __kernel_clock_getres;
+                __kernel_sync_dicache;
+                __kernel_sigtramp_rt64;
+                __kernel_getcpu;
+                __kernel_time;
+        local: *;
+        };
+}
+
+PHDRS {
+        phdr            PT_PHDR         FLAGS(4) PHDRS;
+        load            PT_LOAD         FLAGS(7) FILEHDR PHDRS; /* FLAGS=RWX */
+        dynamic         PT_DYNAMIC      FLAGS(4);
+        eh_frame_hdr    PT_GNU_EH_FRAME;
+        note            PT_NOTE         FLAGS(4);
+}
+
+SECTIONS {
+        . = SIZEOF_HEADERS;
+
+        /*
+         * The following, including the FILEHDRS and PHDRS, are modified
+         * when we relocate the binary.  We want them to be initially
+         * writable for the relocation; we'll force them read-only after.
+         */
+        .note           : { *(.note*) }         :load :note
+        .dynamic        : { *(.dynamic) }       :load :dynamic
+        .dynsym         : { *(.dynsym) }        :load
+        .data           : {
+                /*
+                 * There ought not be any real read-write data.
+                 * But since we manipulated the segment layout,
+                 * we have to put these sections somewhere.
+                 */
+                *(.data*)
+                *(.sdata*)
+                *(.got.plt) *(.got)
+                *(.gnu.linkonce.d.*)
+                *(.bss*)
+                *(.dynbss*)
+                *(.gnu.linkonce.b.*)
+        }
+
+        .rodata         : { *(.rodata*) }
+        .hash           : { *(.hash) }
+        .gnu.hash       : { *(.gnu.hash) }
+        .dynstr         : { *(.dynstr) }
+        .gnu.version    : { *(.gnu.version) }
+        .gnu.version_d  : { *(.gnu.version_d) }
+        .gnu.version_r  : { *(.gnu.version_r) }
+        .eh_frame_hdr   : { *(.eh_frame_hdr) }  :load :eh_frame_hdr
+        .eh_frame       : { *(.eh_frame) }      :load
+
+        .text           : { *(.text*) }         :load
+}
diff --git a/linux-user/ppc/vdso-64.so b/linux-user/ppc/vdso-64.so
new file mode 100755 (executable)
index 0000000..913c831
Binary files /dev/null and b/linux-user/ppc/vdso-64.so differ
diff --git a/linux-user/ppc/vdso-64le.so b/linux-user/ppc/vdso-64le.so
new file mode 100755 (executable)
index 0000000..258a03b
Binary files /dev/null and b/linux-user/ppc/vdso-64le.so differ
diff --git a/linux-user/ppc/vdso-asmoffset.h b/linux-user/ppc/vdso-asmoffset.h
new file mode 100644 (file)
index 0000000..6844c8c
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Size of dummy stack frame allocated when calling signal handler.
+ * See arch/powerpc/include/asm/ptrace.h.
+ */
+#ifdef TARGET_ABI32
+# define SIGNAL_FRAMESIZE                   64
+#else
+# define SIGNAL_FRAMESIZE                   128
+#endif
+
+#ifdef TARGET_ABI32
+# define offsetof_sigframe_mcontext         0x20
+# define offsetof_rt_sigframe_mcontext      0x140
+# define offsetof_mcontext_fregs            0xc0
+# define offsetof_mcontext_vregs            0x1d0
+#else
+# define offsetof_rt_sigframe_mcontext      0xe8
+# define offsetof_mcontext_fregs            0x180
+# define offsetof_mcontext_vregs_ptr        0x288
+#endif
diff --git a/linux-user/ppc/vdso.S b/linux-user/ppc/vdso.S
new file mode 100644 (file)
index 0000000..689010d
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * PowerPC linux replacement vdso.
+ *
+ * Copyright 2023 Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <asm/unistd.h>
+#include <asm/errno.h>
+
+#ifndef _ARCH_PPC64
+# define TARGET_ABI32
+#endif
+#include "vdso-asmoffset.h"
+
+
+       .text
+
+.macro endf name
+       .globl  \name
+       .size   \name, .-\name
+       /* For PPC64, functions have special linkage; we export pointers. */
+#ifndef _ARCH_PPC64
+       .type   \name, @function
+#endif
+.endm
+
+.macro raw_syscall nr
+       addi    0, 0, \nr
+       sc
+.endm
+
+.macro vdso_syscall name, nr
+\name:
+       raw_syscall \nr
+       blr
+endf   \name
+.endm
+
+       .cfi_startproc
+
+vdso_syscall __kernel_gettimeofday, __NR_gettimeofday
+vdso_syscall __kernel_clock_gettime, __NR_clock_gettime
+vdso_syscall __kernel_clock_getres, __NR_clock_getres
+vdso_syscall __kernel_getcpu, __NR_getcpu
+vdso_syscall __kernel_time, __NR_time
+
+#ifdef __NR_clock_gettime64
+vdso_syscall __kernel_clock_gettime64, __NR_clock_gettime64
+#endif
+
+__kernel_sync_dicache:
+       /* qemu does not need to flush caches */
+       blr
+endf   __kernel_sync_dicache
+
+       .cfi_endproc
+
+/*
+ * TODO: __kernel_get_tbfreq
+ * This is probably a constant for QEMU.
+ */
+
+/*
+ * Start the unwind info at least one instruction before the signal
+ * trampoline, because the unwinder will assume we are returning
+ * after a call site.
+ */
+
+       .cfi_startproc simple
+       .cfi_signal_frame
+
+#ifdef _ARCH_PPC64
+# define __kernel_sigtramp_rt  __kernel_sigtramp_rt64
+# define sizeof_reg    8
+#else
+# define __kernel_sigtramp_rt  __kernel_sigtramp_rt32
+# define sizeof_reg    4
+#endif
+#define sizeof_freg    8
+#define sizeof_vreg    16
+
+       .cfi_def_cfa    1, SIGNAL_FRAMESIZE + offsetof_rt_sigframe_mcontext
+
+       /* Return address */
+       .cfi_return_column 67
+       .cfi_offset     67, 32 * sizeof_reg             /* nip */
+
+       /* Integer registers */
+       .cfi_offset     0, 0 * sizeof_reg
+       .cfi_offset     1, 1 * sizeof_reg
+       .cfi_offset     2, 2 * sizeof_reg
+       .cfi_offset     3, 3 * sizeof_reg
+       .cfi_offset     4, 4 * sizeof_reg
+       .cfi_offset     5, 5 * sizeof_reg
+       .cfi_offset     6, 6 * sizeof_reg
+       .cfi_offset     7, 7 * sizeof_reg
+       .cfi_offset     8, 8 * sizeof_reg
+       .cfi_offset     9, 9 * sizeof_reg
+       .cfi_offset     10, 10 * sizeof_reg
+       .cfi_offset     11, 11 * sizeof_reg
+       .cfi_offset     12, 12 * sizeof_reg
+       .cfi_offset     13, 13 * sizeof_reg
+       .cfi_offset     14, 14 * sizeof_reg
+       .cfi_offset     15, 15 * sizeof_reg
+       .cfi_offset     16, 16 * sizeof_reg
+       .cfi_offset     17, 17 * sizeof_reg
+       .cfi_offset     18, 18 * sizeof_reg
+       .cfi_offset     19, 19 * sizeof_reg
+       .cfi_offset     20, 20 * sizeof_reg
+       .cfi_offset     21, 21 * sizeof_reg
+       .cfi_offset     22, 22 * sizeof_reg
+       .cfi_offset     23, 23 * sizeof_reg
+       .cfi_offset     24, 24 * sizeof_reg
+       .cfi_offset     25, 25 * sizeof_reg
+       .cfi_offset     26, 26 * sizeof_reg
+       .cfi_offset     27, 27 * sizeof_reg
+       .cfi_offset     28, 28 * sizeof_reg
+       .cfi_offset     29, 29 * sizeof_reg
+       .cfi_offset     30, 30 * sizeof_reg
+       .cfi_offset     31, 31 * sizeof_reg
+       .cfi_offset     65, 36 * sizeof_reg             /* lr */
+       .cfi_offset     70, 38 * sizeof_reg             /* ccr */
+
+       /* Floating point registers */
+       .cfi_offset     32, offsetof_mcontext_fregs
+       .cfi_offset     33, offsetof_mcontext_fregs + 1 * sizeof_freg
+       .cfi_offset     34, offsetof_mcontext_fregs + 2 * sizeof_freg
+       .cfi_offset     35, offsetof_mcontext_fregs + 3 * sizeof_freg
+       .cfi_offset     36, offsetof_mcontext_fregs + 4 * sizeof_freg
+       .cfi_offset     37, offsetof_mcontext_fregs + 5 * sizeof_freg
+       .cfi_offset     38, offsetof_mcontext_fregs + 6 * sizeof_freg
+       .cfi_offset     39, offsetof_mcontext_fregs + 7 * sizeof_freg
+       .cfi_offset     40, offsetof_mcontext_fregs + 8 * sizeof_freg
+       .cfi_offset     41, offsetof_mcontext_fregs + 9 * sizeof_freg
+       .cfi_offset     42, offsetof_mcontext_fregs + 10 * sizeof_freg
+       .cfi_offset     43, offsetof_mcontext_fregs + 11 * sizeof_freg
+       .cfi_offset     44, offsetof_mcontext_fregs + 12 * sizeof_freg
+       .cfi_offset     45, offsetof_mcontext_fregs + 13 * sizeof_freg
+       .cfi_offset     46, offsetof_mcontext_fregs + 14 * sizeof_freg
+       .cfi_offset     47, offsetof_mcontext_fregs + 15 * sizeof_freg
+       .cfi_offset     48, offsetof_mcontext_fregs + 16 * sizeof_freg
+       .cfi_offset     49, offsetof_mcontext_fregs + 17 * sizeof_freg
+       .cfi_offset     50, offsetof_mcontext_fregs + 18 * sizeof_freg
+       .cfi_offset     51, offsetof_mcontext_fregs + 19 * sizeof_freg
+       .cfi_offset     52, offsetof_mcontext_fregs + 20 * sizeof_freg
+       .cfi_offset     53, offsetof_mcontext_fregs + 21 * sizeof_freg
+       .cfi_offset     54, offsetof_mcontext_fregs + 22 * sizeof_freg
+       .cfi_offset     55, offsetof_mcontext_fregs + 23 * sizeof_freg
+       .cfi_offset     56, offsetof_mcontext_fregs + 24 * sizeof_freg
+       .cfi_offset     57, offsetof_mcontext_fregs + 25 * sizeof_freg
+       .cfi_offset     58, offsetof_mcontext_fregs + 26 * sizeof_freg
+       .cfi_offset     59, offsetof_mcontext_fregs + 27 * sizeof_freg
+       .cfi_offset     60, offsetof_mcontext_fregs + 28 * sizeof_freg
+       .cfi_offset     61, offsetof_mcontext_fregs + 29 * sizeof_freg
+       .cfi_offset     62, offsetof_mcontext_fregs + 30 * sizeof_freg
+       .cfi_offset     63, offsetof_mcontext_fregs + 31 * sizeof_freg
+
+       /*
+        * Unlike the kernel, unconditionally represent the Altivec/VSX regs.
+        * The space within the stack frame is always available, and most of
+        * our supported processors have them enabled.  The only complication
+        * for PPC64 is the misalignment, so that we have to use indirection.
+        */
+.macro save_vreg_ofs reg, ofs
+#ifdef _ARCH_PPC64
+       /*
+        * vreg = *(cfa + offsetof(v_regs)) + ofs
+         *
+         * The CFA is input to the expression on the stack, so:
+        * DW_CFA_expression reg, length (7),
+         *   DW_OP_plus_uconst (0x23), vreg_ptr, DW_OP_deref (0x06),
+        *   DW_OP_plus_uconst (0x23), ofs
+        */
+       .cfi_escape 0x10, 77 + \reg, 7, 0x23, (offsetof_mcontext_vregs_ptr & 0x7f) + 0x80, offsetof_mcontext_vregs_ptr >> 7, 0x06, 0x23, (\ofs & 0x7f) | 0x80, \ofs >> 7
+#else
+       .cfi_offset 77 + \reg, offsetof_mcontext_vregs + \ofs
+#endif
+.endm
+
+.macro save_vreg reg
+       save_vreg_ofs \reg, (\reg * sizeof_vreg)
+.endm
+
+       save_vreg   0
+       save_vreg   1
+       save_vreg   2
+       save_vreg   3
+       save_vreg   4
+       save_vreg   5
+       save_vreg   6
+       save_vreg   7
+       save_vreg   8
+       save_vreg   9
+       save_vreg  10
+       save_vreg  11
+       save_vreg  12
+       save_vreg  13
+       save_vreg  14
+       save_vreg  15
+       save_vreg  16
+       save_vreg  17
+       save_vreg  18
+       save_vreg  19
+       save_vreg  20
+       save_vreg  21
+       save_vreg  22
+       save_vreg  23
+       save_vreg  24
+       save_vreg  25
+       save_vreg  26
+       save_vreg  27
+       save_vreg  28
+       save_vreg  29
+       save_vreg  30
+       save_vreg  31
+       save_vreg  32
+       save_vreg_ofs 33, (32 * sizeof_vreg + 12)
+
+       nop
+
+__kernel_sigtramp_rt:
+       raw_syscall __NR_rt_sigreturn
+endf   __kernel_sigtramp_rt
+
+#ifndef _ARCH_PPC64
+       /*
+        * The non-rt sigreturn has the same layout at a different offset.
+        * Move the CFA and leave all othe other descriptions the same.
+        */
+       .cfi_def_cfa    1, SIGNAL_FRAMESIZE + offsetof_sigframe_mcontext
+       nop
+__kernel_sigtramp32:
+       raw_syscall __NR_sigreturn
+endf   __kernel_sigtramp32
+#endif
+
+       .cfi_endproc