summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2003-09-24 03:22:56 +0000
committerUlrich Drepper <drepper@redhat.com>2003-09-24 03:22:56 +0000
commit54ee14b3882bc7f2fcace383ee12da765e86e2ee (patch)
tree63e8a3a0e4eba8a081f0db111d6df51668ebaf3c
parent16a76cd23ce9d3924fa192395e730423e3dc8b36 (diff)
downloadglibc-54ee14b3882bc7f2fcace383ee12da765e86e2ee.tar.gz
glibc-54ee14b3882bc7f2fcace383ee12da765e86e2ee.tar.xz
glibc-54ee14b3882bc7f2fcace383ee12da765e86e2ee.zip
Update.
2003-09-23  Ulrich Drepper  <drepper@redhat.com>

	* sysdeps/unix/sysv/linux/powerpc/powerpc32/Versions [libc]
	(GLIBC_2.3.3): Add setcontext, getcontext, swapcontext, and
	makecontext.
	* sysdeps/unix/sysv/linux/powerpc/sys/ucontext.h: Correct change
	for include Altivec support for PPC32.  It was not compatible.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/ucontext_i.h: Adjust
	offsets for ucontext_t change.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S: Adjust
	for ucontext_t change.  Add compatibility code.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/makecontext.S: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext.S: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S: Likewise.
	Patch by Paul Mackerras <paulus@samba.org>.

2003-02-25  Randolph Chung  <tausq@debian.org>

	* sysdeps/hppa/Makefile: Include compat code in build.
	* sysdeps/hppa/libgcc-compat.c: New file.
	* sysdeps/hppa/Dist: Add libgcc-compat.c.
	* sysdeps/hppa/Versions [GLIBC_2.2]: Add __clz_tab.
-rw-r--r--ChangeLog23
-rw-r--r--nptl/ChangeLog18
-rw-r--r--nptl/Makefile7
-rw-r--r--nptl/allocatestack.c53
-rw-r--r--nptl/init.c2
-rw-r--r--nptl/pthreadP.h3
-rw-r--r--sysdeps/hppa/Dist1
-rw-r--r--sysdeps/hppa/Makefile11
-rw-r--r--sysdeps/hppa/Versions5
-rw-r--r--sysdeps/hppa/libgcc-compat.c43
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/Versions1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S26
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/makecontext.S44
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext.S21
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S25
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/ucontext_i.h12
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/sys/ucontext.h36
17 files changed, 294 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog
index 1c659e8b46..028de322fa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2003-09-23  Ulrich Drepper  <drepper@redhat.com>
+
+	* sysdeps/unix/sysv/linux/powerpc/powerpc32/Versions [libc]
+	(GLIBC_2.3.3): Add setcontext, getcontext, swapcontext, and
+	makecontext.
+	* sysdeps/unix/sysv/linux/powerpc/sys/ucontext.h: Correct change
+	for include Altivec support for PPC32.  It was not compatible.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc32/ucontext_i.h: Adjust
+	offsets for ucontext_t change.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S: Adjust
+	for ucontext_t change.  Add compatibility code.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc32/makecontext.S: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext.S: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S: Likewise.
+	Patch by Paul Mackerras <paulus@samba.org>.
+
+2003-02-25  Randolph Chung  <tausq@debian.org>
+
+	* sysdeps/hppa/Makefile: Include compat code in build.
+	* sysdeps/hppa/libgcc-compat.c: New file.
+	* sysdeps/hppa/Dist: Add libgcc-compat.c.
+	* sysdeps/hppa/Versions [GLIBC_2.2]: Add __clz_tab.
+
 2003-09-23  Roland McGrath  <roland@redhat.com>
 
 	* elf/rtld.c (dl_main): In rtld_is_main case, reinitialize
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 00bfbf9ad8..031c9e08cd 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,21 @@
+2003-09-23  Jakub Jelinek  <jakub@redhat.com>
+
+	* Makefile (tests): Only add tst-execstack if have-z-execstack is yes.
+
+2003-09-23  Roland McGrath  <roland@redhat.com>
+
+	* tst-execstack.c: New file.
+	* Makefile (tests): Add it.
+	($(objpfx)tst-execstack, $(objpfx)tst-execstack.out): New targets.
+	(LDFLAGS-tst-execstack): New variable.
+
+	* allocatestack.c (allocate_stack): Use GL(dl_stack_flags) to decide
+	whether to use PROT_EXEC for stack mmap.
+	(__make_stacks_executable): New function.
+	* pthreadP.h: Declare it.
+	* init.c (__pthread_initialize_minimal_internal): Set
+	GL(dl_make_stack_executable_hook) to that.
+
 2003-09-22  Ulrich Drepper  <drepper@redhat.com>
 
 	* sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Adjust for latest
diff --git a/nptl/Makefile b/nptl/Makefile
index d592137caf..cf438bbdb6 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -253,6 +253,9 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
 endif
 ifeq ($(build-shared),yes)
 tests += tst-atfork2 tst-tls3 tst-tls4 tst-tls5 tst-_res1
+ifeq ($(have-z-execstack),yes)
+tests += tst-execstack
+endif
 endif
 
 modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
@@ -540,3 +543,7 @@ endif
 endif
 
 tst-exec4-ARGS = $(built-program-cmd)
+
+$(objpfx)tst-execstack: $(libdl)
+$(objpfx)tst-execstack.out: $(elf-objpfx)tst-execstack-mod.so
+LDFLAGS-tst-execstack = -Wl,-z,noexecstack
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index 6ada1fe138..dc501650b8 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -351,11 +351,12 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
     }
   else
     {
-      /* Allocate some anonymous memory.  If possible use the
-	 cache.  */
+      /* Allocate some anonymous memory.  If possible use the cache.  */
       size_t guardsize;
       size_t reqsize;
       void *mem;
+      const int prot = (PROT_READ | PROT_WRITE
+			| ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
 
 #if COLORING_INCREMENT != 0
       /* Add one more page for stack coloring.  Don't do it for stacks
@@ -392,7 +393,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	    size += pagesize_m1 + 1;
 #endif
 
-	  mem = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+	  mem = mmap (NULL, size, prot,
 		      MAP_PRIVATE | MAP_ANONYMOUS | ARCH_MAP_FLAGS, -1, 0);
 
 	  if (__builtin_expect (mem == MAP_FAILED, 0))
@@ -546,17 +547,16 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	  char *oldguard = mem + (((size - pd->guardsize) / 2) & ~pagesize_m1);
 
 	  if (oldguard < guard
-	      && mprotect (oldguard, guard - oldguard,
-			   PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+	      && mprotect (oldguard, guard - oldguard, prot) != 0)
 	    goto mprot_error;
 
 	  if (mprotect (guard + guardsize,
 			oldguard + pd->guardsize - guard - guardsize,
-			PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+			prot) != 0)
 	    goto mprot_error;
 #else
 	  if (mprotect ((char *) mem + guardsize, pd->guardsize - guardsize,
-			PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+			prot) != 0)
 	    goto mprot_error;
 #endif
 
@@ -616,6 +616,45 @@ __deallocate_stack (struct pthread *pd)
 }
 
 
+int
+internal_function
+__make_stacks_executable (void)
+{
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  const size_t pagemask = ~(__getpagesize () - 1);
+#endif
+
+  lll_lock (stack_cache_lock);
+
+  int err = 0;
+  list_t *runp;
+  list_for_each (runp, &stack_used)
+    {
+      struct pthread *const pd = list_entry (runp, struct pthread, list);
+#ifdef NEED_SEPARATE_REGISTER_STACK
+      void *stack = (pd->stackblock
+		     + (((((pd->stackblock_size - pd->guardsize) / 2)
+			  & pagemask) + pd->guardsize) & pagemask));
+      size_t len = pd->stackblock + pd->stackblock_size - stack;
+#else
+      void *stack = pd->stackblock + pd->guardsize;
+      size_t len = pd->stackblock_size - pd->guardsize;
+#endif
+      if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+	{
+	  err = errno;
+	  break;
+	}
+    }
+
+  lll_unlock (stack_cache_lock);
+
+  _dl_make_stack_executable ();
+
+  return err;
+}
+
+
 /* In case of a fork() call the memory allocation in the child will be
    the same but only one thread is running.  All stacks except that of
    the one running thread are not used anymore.  We have to recycle
diff --git a/nptl/init.c b/nptl/init.c
index 7b8b2b0c54..36b65425f5 100644
--- a/nptl/init.c
+++ b/nptl/init.c
@@ -283,6 +283,8 @@ __pthread_initialize_minimal_internal (void)
   GL(dl_load_lock).mutex.__data.__count = 0;
   while (rtld_lock_count-- > 0)
     INTUSE (__pthread_mutex_lock) (&GL(dl_load_lock).mutex);
+
+  GL(dl_make_stack_executable_hook) = &__make_stacks_executable;
 #endif
 
   GL(dl_init_static_tls) = &__pthread_init_static_tls;
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 4159ea6862..986e3788fb 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -215,6 +215,9 @@ extern void __deallocate_stack (struct pthread *pd)
    function also re-initializes the lock for the stack cache.  */
 extern void __reclaim_stacks (void) attribute_hidden;
 
+/* Make all threads's stacks executable.  */
+int __make_stacks_executable (void) internal_function attribute_hidden;
+
 /* longjmp handling.  */
 extern void __pthread_cleanup_upto (__jmp_buf target, char *targetframe);
 #if defined NOT_IN_libc && defined IS_IN_libpthread
diff --git a/sysdeps/hppa/Dist b/sysdeps/hppa/Dist
index 9fc1de291a..e26e411bc5 100644
--- a/sysdeps/hppa/Dist
+++ b/sysdeps/hppa/Dist
@@ -1,2 +1,3 @@
+libgcc-compat.c
 dl-symaddr.c
 dl-fptr.c
diff --git a/sysdeps/hppa/Makefile b/sysdeps/hppa/Makefile
index 170bd07ab3..68651f6497 100644
--- a/sysdeps/hppa/Makefile
+++ b/sysdeps/hppa/Makefile
@@ -31,3 +31,14 @@ CFLAGS-rtld.c += -mdisable-fpregs
 dl-routines += dl-symaddr dl-fptr
 rtld-routines += dl-symaddr dl-fptr
 endif
+
+ifeq ($(subdir),csu)
+ifeq (yes,$(build-shared))
+# Compatibility
+ifeq (yes,$(have-protected))
+CPPFLAGS-libgcc-compat.c = -DHAVE_DOT_HIDDEN
+endif
+sysdep_routines += libgcc-compat
+shared-only-routines += libgcc-compat
+endif
+endif
diff --git a/sysdeps/hppa/Versions b/sysdeps/hppa/Versions
index 909d50bbf5..2ae3cbdf17 100644
--- a/sysdeps/hppa/Versions
+++ b/sysdeps/hppa/Versions
@@ -5,3 +5,8 @@ ld {
     _dl_function_address;
   }
 }
+libc {
+  GLIBC_2.2 {
+    __clz_tab;
+  }
+}
diff --git a/sysdeps/hppa/libgcc-compat.c b/sysdeps/hppa/libgcc-compat.c
new file mode 100644
index 0000000000..2957eba89f
--- /dev/null
+++ b/sysdeps/hppa/libgcc-compat.c
@@ -0,0 +1,43 @@
+/* pre-.hidden libgcc compatibility
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Randolph Chung
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+#include <stdint.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_6)
+
+symbol_version (__clz_tab_internal, __clz_tab, GLIBC_2.2);
+
+typedef unsigned int UQItype  __attribute__ ((mode (QI)));
+
+const UQItype __clz_tab_internal[] =
+{
+  0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+  6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+};
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/Versions b/sysdeps/unix/sysv/linux/powerpc/powerpc32/Versions
index 92158ee1b5..d667eadbce 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/Versions
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/Versions
@@ -22,5 +22,6 @@ libc {
   }
   GLIBC_2.3.3 {
     posix_fadvise64; posix_fallocate64;
+    setcontext; getcontext; swapcontext; makecontext;
   }
 }
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S
index 9405d12cfb..3b1b3b9449 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S
@@ -18,12 +18,20 @@
    02111-1307 USA.  */
 
 #include <sysdep.h>
+#include <shlib-compat.h>
 
 #define __ASSEMBLY__
 #include <asm/ptrace.h>
 #include "ucontext_i.h"
 
 ENTRY(__getcontext)
+	/*
+	 * Since we are not attempting to save the altivec registers,
+	 * there is no need to get the register storage space
+	 * aligned on a 16-byte boundary.
+	 */
+	addi	r3,r3,_UC_REG_SPACE
+	stw	r3,_UC_REGS_PTR - _UC_REG_SPACE(r3)
 	stw	r0,_UC_GREGS+(PT_R0*4)(r3)
 	stw	r1,_UC_GREGS+(PT_R1*4)(r3)
 	mflr	r0
@@ -112,7 +120,7 @@ ENTRY(__getcontext)
 	stfd	fp31,_UC_FREGS+(31*8)(r3)
 	stfd	fp0,_UC_FREGS+(32*8)(r3)
 
-	addi	r5,r3,_UC_SIGMASK
+	addi	r5,r3,_UC_SIGMASK - _UC_REG_SPACE
 	li	r4,0
 	li	r3,SIG_BLOCK
 	bl	JUMPTARGET(sigprocmask)
@@ -123,4 +131,18 @@ ENTRY(__getcontext)
 	blr
 PSEUDO_END(__getcontext)
 
-weak_alias(__getcontext, getcontext)
+versioned_symbol (libc, __getcontext, getcontext, GLIBC_2_3_3)
+
+#if SHLIB_COMPAT (libc, GLIBC_2_1, GLIBC_2_3_3)
+
+#define _ERRNO_H	1
+#include <bits/errno.h>
+
+ENTRY (__getcontext_stub)
+	li	r3,ENOSYS
+	b	JUMPTARGET(__syscall_error)
+	END (__getcontext_stub)
+
+compat_symbol (libc, __getcontext_stub, getcontext, GLIBC_2_1)
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/makecontext.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/makecontext.S
index b875aa5de0..9cb0b874f5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/makecontext.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/makecontext.S
@@ -18,6 +18,7 @@
    02111-1307 USA.  */
 
 #include <sysdep.h>
+#include <shlib-compat.h>
 
 #define __ASSEMBLY__
 #include <asm/ptrace.h>
@@ -25,22 +26,24 @@
 
 ENTRY(__makecontext)
 	/* Set up the first 7 args to the function in its registers */
-	stw	r6,_UC_GREGS+(PT_R3*4)(r3)
-	stw	r7,_UC_GREGS+(PT_R4*4)(r3)
-	stw	r8,_UC_GREGS+(PT_R5*4)(r3)
-	stw	r9,_UC_GREGS+(PT_R6*4)(r3)
-	stw	r10,_UC_GREGS+(PT_R7*4)(r3)
+	addi	r11,r3,_UC_REG_SPACE
+	stw	r11,_UC_REGS_PTR(r3)
+	stw	r6,_UC_GREGS+(PT_R3*4)(r11)
+	stw	r7,_UC_GREGS+(PT_R4*4)(r11)
+	stw	r8,_UC_GREGS+(PT_R5*4)(r11)
+	stw	r9,_UC_GREGS+(PT_R6*4)(r11)
+	stw	r10,_UC_GREGS+(PT_R7*4)(r11)
 	lwz	r8,8(r1)
 	lwz	r9,12(r1)
-	stw	r8,_UC_GREGS+(PT_R8*4)(r3)
-	stw	r9,_UC_GREGS+(PT_R9*4)(r3)
+	stw	r8,_UC_GREGS+(PT_R8*4)(r11)
+	stw	r9,_UC_GREGS+(PT_R9*4)(r11)
 
 	/* Set the NIP to the start of the function */
-	stw	r4,_UC_GREGS+(PT_NIP*4)(r3)
+	stw	r4,_UC_GREGS+(PT_NIP*4)(r11)
 
 	/* Set the function's r31 to ucp->uc_link for the exitcode below. */
 	lwz	r7,_UC_LINK(r3)
-	stw	r7,_UC_GREGS+(PT_R31*4)(r3)
+	stw	r7,_UC_GREGS+(PT_R31*4)(r11)
 
 	/* Set the function's LR to point to the exitcode below. */
 #ifdef PIC
@@ -53,7 +56,7 @@ ENTRY(__makecontext)
 	lis	r6,L(exitcode)@ha
 	addi	r6,r6,L(exitcode)@l
 #endif
-	stw	r6,_UC_GREGS+(PT_LNK*4)(r3)
+	stw	r6,_UC_GREGS+(PT_LNK*4)(r11)
 
 	/*
 	 * Set up the stack frame for the function.
@@ -71,7 +74,7 @@ ENTRY(__makecontext)
 	cmpwi	r5,8
 	blt	2f		/* less than 8 args is easy */
 	lwz	r10,16(r1)
-	stw	r10,_UC_GREGS+(PT_R10*4)(r3)
+	stw	r10,_UC_GREGS+(PT_R10*4)(r11)
 	beq	2f		/* if exactly 8 args */
 	subi	r9,r5,3
 	subi	r5,r5,8
@@ -83,7 +86,7 @@ ENTRY(__makecontext)
 3:	lwzu	r10,4(r6)
 	stwu	r10,4(r8)
 	bdnz	3b
-2:	stw	r7,_UC_GREGS+(PT_R1*4)(r3)
+2:	stw	r7,_UC_GREGS+(PT_R1*4)(r11)
 	li	r6,0
 	stw	r6,0(r7)
 
@@ -102,4 +105,19 @@ L(exitcode):
 	b	4b
 
 END(__makecontext)
-weak_alias(__makecontext, makecontext)
+
+versioned_symbol (libc, __makecontext, makecontext, GLIBC_2_3_3)
+
+#if SHLIB_COMPAT (libc, GLIBC_2_1, GLIBC_2_3_3)
+
+#define _ERRNO_H	1
+#include <bits/errno.h>
+
+ENTRY (__makecontext_stub)
+	li	r3,ENOSYS
+	b	JUMPTARGET(__syscall_error)
+	END (__makecontext_stub)
+
+compat_symbol (libc, __makecontext_stub, makecontext, GLIBC_2_1)
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext.S
index 1539b40f01..deb946137d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/setcontext.S
@@ -18,6 +18,7 @@
    02111-1307 USA.  */
 
 #include <sysdep.h>
+#include <shlib-compat.h>
 
 #define __ASSEMBLY__
 #include <asm/ptrace.h>
@@ -28,7 +29,7 @@ ENTRY(__setcontext)
 	stwu	r1,-16(r1)
 	stw	r0,20(r1)
 	stw	r31,12(r1)
-	mr	r31,r3
+	lwz	r31,_UC_REGS_PTR(r3)
 
 	/*
 	 * If this ucontext refers to the point where we were interrupted
@@ -144,6 +145,20 @@ L(do_sigret):
 	sc
 	/* NOTREACHED */
 
-PSEUDO_END(__setcontext)
+PSEUDO_END (__setcontext)
 
-weak_alias(__setcontext, setcontext)
+versioned_symbol (libc, __setcontext, setcontext, GLIBC_2_3_3)
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_3)
+
+#define _ERRNO_H	1
+#include <bits/errno.h>
+
+ENTRY (__setcontext_stub)
+	li	r3,ENOSYS
+	b	JUMPTARGET(__syscall_error)
+	END (__setcontext_stub)
+
+compat_symbol (libc, __setcontext_stub, setcontext, GLIBC_2_0)
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S
index 88cf0dae8f..fac6802959 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S
@@ -18,6 +18,7 @@
    02111-1307 USA.  */
 
 #include <sysdep.h>
+#include <shlib-compat.h>
 
 #define __ASSEMBLY__
 #include <asm/ptrace.h>
@@ -25,6 +26,8 @@
 
 ENTRY(__swapcontext)
 	/* Save the current context */
+	addi	r3,r3,_UC_REG_SPACE
+	stw	r3,_UC_REGS_PTR - _UC_REG_SPACE(r3)
 	stw	r0,_UC_GREGS+(PT_R0*4)(r3)
 	stw	r1,_UC_GREGS+(PT_R1*4)(r3)
 	mflr	r0
@@ -115,7 +118,7 @@ ENTRY(__swapcontext)
 	stfd	fp31,_UC_FREGS+(31*8)(r3)
 	stfd	fp0,_UC_FREGS+(32*8)(r3)
 
-	addi	r5,r3,_UC_SIGMASK
+	addi	r5,r3,_UC_SIGMASK - _UC_REG_SPACE
 	addi	r4,r4,_UC_SIGMASK
 	li	r3,SIG_SETMASK
 	bl	JUMPTARGET(sigprocmask)
@@ -133,6 +136,8 @@ ENTRY(__swapcontext)
 	 * r0, xer, ctr.  We don't restore r2 since it will be used as
 	 * the TLS pointer.
 	 */
+	mr	r4,r31
+	lwz	r31,_UC_REGS_PTR(r31)
 	lwz	r0,_UC_GREGS+(PT_MSR*4)(r31)
 	cmpwi	r0,0
 	bne	L(do_sigret)
@@ -223,11 +228,25 @@ L(error_exit):
 	blr
 
 L(do_sigret):
-	addi	r1,r31,-0xd0
+	addi	r1,r4,-0xd0
 	li	r0,SYS_ify(rt_sigreturn)
 	sc
 	/* NOTREACHED */
 
 PSEUDO_END(__swapcontext)
 
-weak_alias(__swapcontext, swapcontext)
+versioned_symbol (libc, __swapcontext, swapcontext, GLIBC_2_3_3)
+
+#if SHLIB_COMPAT (libc, GLIBC_2_1, GLIBC_2_3_3)
+
+#define _ERRNO_H	1
+#include <bits/errno.h>
+
+ENTRY (__swapcontext_stub)
+	li	r3,ENOSYS
+	b	JUMPTARGET(__syscall_error)
+	END (__swapcontext_stub)
+
+compat_symbol (libc, __swapcontext_stub, swapcontext, GLIBC_2_1)
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ucontext_i.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ucontext_i.h
index e88a025d6a..1ae082a3ef 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ucontext_i.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ucontext_i.h
@@ -24,7 +24,11 @@
 #define _UC_LINK	4
 #define _UC_STACK_SP	8
 #define _UC_STACK_SIZE	16
-#define _UC_SIGMASK	64
-#define _UC_GREGS	192
-#define _UC_FREGS	384
-#define _UC_VREGS	656
+#define _UC_REGS_PTR	48
+#define _UC_SIGMASK	52
+#define _UC_REG_SPACE	180
+
+/* offsets within mcontext_t */
+#define _UC_GREGS	0
+#define _UC_FREGS	192
+#define _UC_VREGS	464
diff --git a/sysdeps/unix/sysv/linux/powerpc/sys/ucontext.h b/sysdeps/unix/sysv/linux/powerpc/sys/ucontext.h
index 9ce93c8197..4bb8bb26d0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/sys/ucontext.h
+++ b/sysdeps/unix/sysv/linux/powerpc/sys/ucontext.h
@@ -74,14 +74,40 @@ typedef struct ucontext
     struct ucontext *uc_link;
     stack_t uc_stack;
 #if __WORDSIZE == 32
-    /* These fields are for backwards compatibility. */
+    /*
+     * These fields are set up this way to maximize source and
+     * binary compatibility with code written for the old
+     * ucontext_t definition, which didn't include space for the
+     * registers.
+     *
+     * Different versions of the kernel have stored the registers on
+     * signal delivery at different offsets from the ucontext struct.
+     * Programs should thus use the uc_mcontext.uc_regs pointer to
+     * find where the registers are actually stored.  The registers
+     * will be stored within the ucontext_t struct but not necessarily
+     * at a fixed address.  As a side-effect, this lets us achieve
+     * 16-byte alignment for the register storage space if the
+     * Altivec registers are to be saved, without requiring 16-byte
+     * alignment on the whole ucontext_t.
+     *
+     * The uc_mcontext.regs field is included for source compatibility
+     * with programs written against the older ucontext_t definition,
+     * and its name should therefore not change.  The uc_pad field
+     * is for binary compatibility with programs compiled against the
+     * old ucontext_t; it ensures that uc_mcontext.regs and uc_sigmask
+     * are at the same offset as previously.
+     */
     int uc_pad[7];
-    mcontext_t *uc_regs;
-    unsigned int uc_oldsigmask[2];
-    int uc_pad2;
-#endif
+    union uc_regs_ptr {
+      struct pt_regs *regs;
+      mcontext_t *uc_regs;
+    } uc_mcontext;
+    sigset_t    uc_sigmask;
+    char uc_reg_space[sizeof(mcontext_t) + 12];  /* last for extensibility */
+#else /* 64-bit */
     sigset_t    uc_sigmask;
     mcontext_t  uc_mcontext;  /* last for extensibility */
+#endif
   } ucontext_t;
 
 #endif /* sys/ucontext.h */