]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libgcc/generic-morestack.c
Work around Solaris ld bug linking __tls_get_addr on 64-bit x86
[thirdparty/gcc.git] / libgcc / generic-morestack.c
index 07bc2a6607353883839cd5562de3e1e3b1b6ebdc..0f6f0005f994f384468d5b60eed7067a0eb5fac7 100644 (file)
@@ -1,5 +1,5 @@
 /* Library support for -fsplit-stack.  */
-/* Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 2009-2019 Free Software Foundation, Inc.
    Contributed by Ian Lance Taylor <iant@google.com>.
 
 This file is part of GCC.
@@ -23,13 +23,16 @@ a copy of the GCC Runtime Library Exception along with this program;
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+/* powerpc 32-bit not supported.  */
+#if !defined __powerpc__ || defined __powerpc64__
+
 #include "tconfig.h"
 #include "tsystem.h"
 #include "coretypes.h"
 #include "tm.h"
 #include "libgcc_tm.h"
 
-/* If inhibit_libc is defined, we can not compile this file.  The
+/* If inhibit_libc is defined, we cannot compile this file.  The
    effect is that people will not be able to use -fsplit-stack.  That
    is much better than failing the build particularly since people
    will want to define inhibit_libc while building a compiler which
@@ -41,12 +44,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include <errno.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #include <sys/uio.h>
 
 #include "generic-morestack.h"
 
+typedef unsigned uintptr_type __attribute__ ((mode (pointer)));
+
 /* This file contains subroutines that are used by code compiled with
    -fsplit-stack.  */
 
@@ -88,14 +94,58 @@ extern void *
 __morestack_allocate_stack_space (size_t size)
   __attribute__ ((visibility ("hidden")));
 
-/* This is a function which -fsplit-stack code can call to get a list
-   of the stacks.  Since it is not called only by the compiler, it is
-   not hidden.  */
+/* These are functions which -fsplit-stack code can call.  These are
+   not called by the compiler, and are not hidden.  FIXME: These
+   should be in some header file somewhere, somehow.  */
 
 extern void *
 __splitstack_find (void *, void *, size_t *, void **, void **, void **)
   __attribute__ ((visibility ("default")));
 
+extern void
+__splitstack_block_signals (int *, int *)
+  __attribute__ ((visibility ("default")));
+
+extern void
+__splitstack_getcontext (void *context[10])
+  __attribute__ ((no_split_stack, visibility ("default")));
+
+extern void
+__splitstack_setcontext (void *context[10])
+  __attribute__ ((no_split_stack, visibility ("default")));
+
+extern void *
+__splitstack_makecontext (size_t, void *context[10], size_t *)
+  __attribute__ ((visibility ("default")));
+
+extern void *
+__splitstack_resetcontext (void *context[10], size_t *)
+  __attribute__ ((visibility ("default")));
+
+extern void
+__splitstack_releasecontext (void *context[10])
+  __attribute__ ((visibility ("default")));
+
+extern void
+__splitstack_block_signals_context (void *context[10], int *, int *)
+  __attribute__ ((visibility ("default")));
+
+extern void *
+__splitstack_find_context (void *context[10], size_t *, void **, void **,
+                          void **)
+  __attribute__ ((visibility ("default")));
+
+/* These functions must be defined by the processor specific code.  */
+
+extern void *__morestack_get_guard (void)
+  __attribute__ ((no_split_stack, visibility ("hidden")));
+
+extern void __morestack_set_guard (void *)
+  __attribute__ ((no_split_stack, visibility ("hidden")));
+
+extern void *__morestack_make_guard (void *, size_t)
+  __attribute__ ((no_split_stack, visibility ("hidden")));
+
 /* When we allocate a stack segment we put this header at the
    start.  */
 
@@ -138,8 +188,13 @@ struct initial_sp
   /* A signal mask, put here so that the thread can use it without
      needing stack space.  */
   sigset_t mask;
+  /* Non-zero if we should not block signals.  This is a reversed flag
+     so that the default zero value is the safe value.  The type is
+     uintptr_type because it replaced one of the void * pointers in
+     extra.  */
+  uintptr_type dont_block_signals;
   /* Some extra space for later extensibility.  */
-  void *extra[5];
+  void *extra[4];
 };
 
 /* A list of memory blocks allocated by dynamic stack allocation.
@@ -188,6 +243,12 @@ __thread struct initial_sp __morestack_initial_sp
 
 static sigset_t __morestack_fullmask;
 
+/* Page size, as returned from getpagesize(). Set on startup. */
+static unsigned int static_pagesize;
+
+/* Set on startup to non-zero value if SPLIT_STACK_GUARD env var is set. */
+static int use_guard_page;
+
 /* Convert an integer to a decimal string without using much stack
    space.  Return a pointer to the part of the buffer to use.  We this
    instead of sprintf because sprintf will require too much stack
@@ -265,8 +326,6 @@ __morestack_fail (const char *msg, size_t len, int err)
 static struct stack_segment *
 allocate_segment (size_t frame_size)
 {
-  static unsigned int static_pagesize;
-  static int use_guard_page;
   unsigned int pagesize;
   unsigned int overhead;
   unsigned int allocate;
@@ -274,27 +333,6 @@ allocate_segment (size_t frame_size)
   struct stack_segment *pss;
 
   pagesize = static_pagesize;
-  if (pagesize == 0)
-    {
-      unsigned int p;
-
-      pagesize = getpagesize ();
-
-#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
-      p = __sync_val_compare_and_swap (&static_pagesize, 0, pagesize);
-#else
-      /* Just hope this assignment is atomic.  */
-      static_pagesize = pagesize;
-      p = 0;
-#endif
-
-      use_guard_page = getenv ("SPLIT_STACK_GUARD") != 0;
-
-      /* FIXME: I'm not sure this assert should be in the released
-        code.  */
-      assert (p == 0 || p == pagesize);
-    }
-
   overhead = sizeof (struct stack_segment);
 
   allocate = pagesize;
@@ -326,7 +364,7 @@ allocate_segment (size_t frame_size)
     {
       void *guard;
 
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
       guard = space;
       space = (char *) space + pagesize;
 #else
@@ -339,18 +377,13 @@ allocate_segment (size_t frame_size)
 
   pss = (struct stack_segment *) space;
 
-  pss->prev = __morestack_current_segment;
+  pss->prev = NULL;
   pss->next = NULL;
   pss->size = allocate - overhead;
   pss->dynamic_allocation = NULL;
   pss->free_dynamic_allocation = NULL;
   pss->extra = NULL;
 
-  if (__morestack_current_segment != NULL)
-    __morestack_current_segment->next = pss;
-  else
-    __morestack_segments = pss;
-
   return pss;
 }
 
@@ -449,7 +482,7 @@ __generic_morestack_set_initial_sp (void *sp, size_t len)
      to the nearest 512 byte boundary.  It's not essential that we be
      precise here; getting it wrong will just leave some stack space
      unused.  */
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
   sp = (void *) ((((__UINTPTR_TYPE__) sp + 511U) / 512U) * 512U);
 #else
   sp = (void *) ((((__UINTPTR_TYPE__) sp - 511U) / 512U) * 512U);
@@ -460,8 +493,8 @@ __generic_morestack_set_initial_sp (void *sp, size_t len)
   sigemptyset (&__morestack_initial_sp.mask);
 
   sigfillset (&__morestack_fullmask);
-#ifdef __linux__
-  /* On Linux, the first two real time signals are used by the NPTL
+#if defined(__GLIBC__) && defined(__linux__)
+  /* In glibc, the first two real time signals are used by the NPTL
      threading library.  By taking them out of the set of signals, we
      avoiding copying the signal mask in pthread_sigmask.  More
      importantly, pthread_sigmask uses less stack space on x86_64.  */
@@ -502,6 +535,7 @@ __generic_morestack (size_t *pframe_size, void *old_stack, size_t param_size)
   char *to;
   void *ret;
   size_t i;
+  size_t aligned;
 
   current = __morestack_current_segment;
 
@@ -513,7 +547,11 @@ __generic_morestack (size_t *pframe_size, void *old_stack, size_t param_size)
   current = *pp;
 
   if (current == NULL)
-    current = allocate_segment (frame_size + param_size);
+    {
+      current = allocate_segment (frame_size + param_size);
+      current->prev = __morestack_current_segment;
+      *pp = current;
+    }
 
   current->old_stack = old_stack;
 
@@ -529,15 +567,19 @@ __generic_morestack (size_t *pframe_size, void *old_stack, size_t param_size)
 
   *pframe_size = current->size - param_size;
 
-#ifdef STACK_GROWS_DOWNWARD
+  /* Align the returned stack to a 32-byte boundary.  */
+  aligned = (param_size + 31) & ~ (size_t) 31;
+
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
   {
     char *bottom = (char *) (current + 1) + current->size;
-    to = bottom - param_size;
-    ret = bottom - param_size;
+    to = bottom - aligned;
+    ret = bottom - aligned;
   }
 #else
   to = current + 1;
-  ret = (char *) (current + 1) + param_size;
+  to += aligned - param_size;
+  ret = (char *) (current + 1) + aligned;
 #endif
 
   /* We don't call memcpy to avoid worrying about the dynamic linker
@@ -572,7 +614,7 @@ __generic_releasestack (size_t *pavailable)
 
   if (current != NULL)
     {
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
       *pavailable = (char *) old_stack - (char *) (current + 1);
 #else
       *pavailable = (char *) (current + 1) + current->size - (char *) old_stack;
@@ -583,7 +625,7 @@ __generic_releasestack (size_t *pavailable)
       size_t used;
 
       /* We have popped back to the original stack.  */
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
       if ((char *) old_stack >= (char *) __morestack_initial_sp.sp)
        used = 0;
       else
@@ -614,7 +656,9 @@ extern int pthread_sigmask (int, const sigset_t *, sigset_t *)
 void
 __morestack_block_signals (void)
 {
-  if (pthread_sigmask)
+  if (__morestack_initial_sp.dont_block_signals)
+    ;
+  else if (pthread_sigmask)
     pthread_sigmask (SIG_BLOCK, &__morestack_fullmask,
                     &__morestack_initial_sp.mask);
   else
@@ -627,7 +671,9 @@ __morestack_block_signals (void)
 void
 __morestack_unblock_signals (void)
 {
-  if (pthread_sigmask)
+  if (__morestack_initial_sp.dont_block_signals)
+    ;
+  else if (pthread_sigmask)
     pthread_sigmask (SIG_SETMASK, &__morestack_initial_sp.mask, NULL);
   else
     sigprocmask (SIG_SETMASK, &__morestack_initial_sp.mask, NULL);
@@ -718,7 +764,7 @@ __generic_findstack (void *stack)
          && (char *) pss + pss->size > (char *) stack)
        {
          __morestack_current_segment = pss;
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
          return (char *) stack - (char *) (pss + 1);
 #else
          return (char *) (pss + 1) + pss->size - (char *) stack;
@@ -727,7 +773,11 @@ __generic_findstack (void *stack)
     }
 
   /* We have popped back to the original stack.  */
-#ifdef STACK_GROWS_DOWNWARD
+
+  if (__morestack_initial_sp.sp == NULL)
+    return 0;
+
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
   if ((char *) stack >= (char *) __morestack_initial_sp.sp)
     used = 0;
   else
@@ -748,7 +798,10 @@ __generic_findstack (void *stack)
 /* This function is called at program startup time to make sure that
    mmap, munmap, and getpagesize are resolved if linking dynamically.
    We want to resolve them while we have enough stack for them, rather
-   than calling into the dynamic linker while low on stack space.  */
+   than calling into the dynamic linker while low on stack space.
+   Similarly, invoke getenv here to check for split-stack related control
+   variables, since doing do as part of the __morestack path can result
+   in unwanted use of SSE/AVX registers (see GCC PR 86213). */
 
 void
 __morestack_load_mmap (void)
@@ -758,7 +811,12 @@ __morestack_load_mmap (void)
      TLS accessor function is resolved.  */
   mmap (__morestack_current_segment, 0, PROT_READ, MAP_ANONYMOUS, -1, 0);
   mprotect (NULL, 0, 0);
-  munmap (0, getpagesize ());
+  munmap (0, static_pagesize);
+
+  /* Initialize these values here, so as to avoid dynamic linker
+     activity as part of a __morestack call. */
+  static_pagesize = getpagesize();
+  use_guard_page = getenv ("SPLIT_STACK_GUARD") != 0;
 }
 
 /* This function may be used to iterate over the stack segments.
@@ -796,13 +854,16 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
   void *ret;
   char *nsp;
 
-  if (segment_arg == (void *) 1)
+  if (segment_arg == (void *) (uintptr_type) 1)
     {
       char *isp = (char *) *initial_sp;
 
-      *next_segment = (void *) 2;
+      if (isp == NULL)
+       return NULL;
+
+      *next_segment = (void *) (uintptr_type) 2;
       *next_sp = NULL;
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
       if ((char *) sp >= isp)
        return NULL;
       *len = (char *) isp - (char *) sp;
@@ -814,7 +875,7 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
       return (void *) isp;
 #endif
     }
-  else if (segment_arg == (void *) 2)
+  else if (segment_arg == (void *) (uintptr_type) 2)
     return NULL;
   else if (segment_arg != NULL)
     segment = (struct stack_segment *) segment_arg;
@@ -826,8 +887,8 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
       while (1)
        {
          if (segment == NULL)
-           return __splitstack_find ((void *) 1, sp, len, next_segment,
-                                     next_sp, initial_sp);
+           return __splitstack_find ((void *) (uintptr_type) 1, sp, len,
+                                     next_segment, next_sp, initial_sp);
          if ((char *) sp >= (char *) (segment + 1)
              && (char *) sp <= (char *) (segment + 1) + segment->size)
            break;
@@ -836,7 +897,7 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
     }
 
   if (segment->prev == NULL)
-    *next_segment = (void *) 1;
+    *next_segment = (void *) (uintptr_type) 1;
   else
     *next_segment = segment->prev;
 
@@ -857,17 +918,30 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
 
   nsp = (char *) segment->old_stack;
 
+  if (nsp == NULL)
+    {
+      /* We've reached the top of the stack.  */
+      *next_segment = (void *) (uintptr_type) 2;
+    }
+  else
+    {
 #if defined (__x86_64__)
-  nsp -= 12 * sizeof (void *);
+      nsp -= 12 * sizeof (void *);
 #elif defined (__i386__)
-  nsp -= 6 * sizeof (void *);
+      nsp -= 6 * sizeof (void *);
+#elif defined __powerpc64__
+#elif defined __s390x__
+      nsp -= 2 * 160;
+#elif defined __s390__
+      nsp -= 2 * 96;
 #else
 #error "unrecognized target"
 #endif
 
-  *next_sp = (void *) nsp;
+      *next_sp = (void *) nsp;
+    }
 
-#ifdef STACK_GROWS_DOWNWARD
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
   *len = (char *) (segment + 1) + segment->size - (char *) sp;
   ret = (void *) sp;
 #else
@@ -878,4 +952,221 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
   return ret;
 }
 
+/* Tell the split stack code whether it has to block signals while
+   manipulating the stack.  This is for programs in which some threads
+   block all signals.  If a thread already blocks signals, there is no
+   need for the split stack code to block them as well.  If NEW is not
+   NULL, then if *NEW is non-zero signals will be blocked while
+   splitting the stack, otherwise they will not.  If OLD is not NULL,
+   *OLD will be set to the old value.  */
+
+void
+__splitstack_block_signals (int *new, int *old)
+{
+  if (old != NULL)
+    *old = __morestack_initial_sp.dont_block_signals ? 0 : 1;
+  if (new != NULL)
+    __morestack_initial_sp.dont_block_signals = *new ? 0 : 1;
+}
+
+/* The offsets into the arrays used by __splitstack_getcontext and
+   __splitstack_setcontext.  */
+
+enum __splitstack_context_offsets
+{
+  MORESTACK_SEGMENTS = 0,
+  CURRENT_SEGMENT = 1,
+  CURRENT_STACK = 2,
+  STACK_GUARD = 3,
+  INITIAL_SP = 4,
+  INITIAL_SP_LEN = 5,
+  BLOCK_SIGNALS = 6,
+
+  NUMBER_OFFSETS = 10
+};
+
+/* Get the current split stack context.  This may be used for
+   coroutine switching, similar to getcontext.  The argument should
+   have at least 10 void *pointers for extensibility, although we
+   don't currently use all of them.  This would normally be called
+   immediately before a call to getcontext or swapcontext or
+   setjmp.  */
+
+void
+__splitstack_getcontext (void *context[NUMBER_OFFSETS])
+{
+  memset (context, 0, NUMBER_OFFSETS * sizeof (void *));
+  context[MORESTACK_SEGMENTS] = (void *) __morestack_segments;
+  context[CURRENT_SEGMENT] = (void *) __morestack_current_segment;
+  context[CURRENT_STACK] = (void *) &context;
+  context[STACK_GUARD] = __morestack_get_guard ();
+  context[INITIAL_SP] = (void *) __morestack_initial_sp.sp;
+  context[INITIAL_SP_LEN] = (void *) (uintptr_type) __morestack_initial_sp.len;
+  context[BLOCK_SIGNALS] = (void *) __morestack_initial_sp.dont_block_signals;
+}
+
+/* Set the current split stack context.  The argument should be a
+   context previously passed to __splitstack_getcontext.  This would
+   normally be called immediately after a call to getcontext or
+   swapcontext or setjmp if something jumped to it.  */
+
+void
+__splitstack_setcontext (void *context[NUMBER_OFFSETS])
+{
+  __morestack_segments = (struct stack_segment *) context[MORESTACK_SEGMENTS];
+  __morestack_current_segment =
+    (struct stack_segment *) context[CURRENT_SEGMENT];
+  __morestack_set_guard (context[STACK_GUARD]);
+  __morestack_initial_sp.sp = context[INITIAL_SP];
+  __morestack_initial_sp.len = (size_t) context[INITIAL_SP_LEN];
+  __morestack_initial_sp.dont_block_signals =
+    (uintptr_type) context[BLOCK_SIGNALS];
+}
+
+/* Create a new split stack context.  This will allocate a new stack
+   segment which may be used by a coroutine.  STACK_SIZE is the
+   minimum size of the new stack.  The caller is responsible for
+   actually setting the stack pointer.  This would normally be called
+   before a call to makecontext, and the returned stack pointer and
+   size would be used to set the uc_stack field.  A function called
+   via makecontext on a stack created by __splitstack_makecontext may
+   not return.  Note that the returned pointer points to the lowest
+   address in the stack space, and thus may not be the value to which
+   to set the stack pointer.  */
+
+void *
+__splitstack_makecontext (size_t stack_size, void *context[NUMBER_OFFSETS],
+                         size_t *size)
+{
+  struct stack_segment *segment;
+  void *initial_sp;
+
+  memset (context, 0, NUMBER_OFFSETS * sizeof (void *));
+  segment = allocate_segment (stack_size);
+  context[MORESTACK_SEGMENTS] = segment;
+  context[CURRENT_SEGMENT] = segment;
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
+  initial_sp = (void *) ((char *) (segment + 1) + segment->size);
+#else
+  initial_sp = (void *) (segment + 1);
+#endif
+  context[STACK_GUARD] = __morestack_make_guard (initial_sp, segment->size);
+  context[INITIAL_SP] = NULL;
+  context[INITIAL_SP_LEN] = 0;
+  *size = segment->size;
+  return (void *) (segment + 1);
+}
+
+/* Given an existing split stack context, reset it back to the start
+   of the stack.  Return the stack pointer and size, appropriate for
+   use with makecontext.  This may be used if a coroutine exits, in
+   order to reuse the stack segments for a new coroutine.  */
+
+void *
+__splitstack_resetcontext (void *context[10], size_t *size)
+{
+  struct stack_segment *segment;
+  void *initial_sp;
+  size_t initial_size;
+  void *ret;
+
+  /* Reset the context assuming that MORESTACK_SEGMENTS, INITIAL_SP
+     and INITIAL_SP_LEN are correct.  */
+
+  segment = context[MORESTACK_SEGMENTS];
+  context[CURRENT_SEGMENT] = segment;
+  context[CURRENT_STACK] = NULL;
+  if (segment == NULL)
+    {
+      initial_sp = context[INITIAL_SP];
+      initial_size = (uintptr_type) context[INITIAL_SP_LEN];
+      ret = initial_sp;
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
+      ret = (void *) ((char *) ret - initial_size);
+#endif
+    }
+  else
+    {
+#ifdef __LIBGCC_STACK_GROWS_DOWNWARD__
+      initial_sp = (void *) ((char *) (segment + 1) + segment->size);
+#else
+      initial_sp = (void *) (segment + 1);
+#endif
+      initial_size = segment->size;
+      ret = (void *) (segment + 1);
+    }
+  context[STACK_GUARD] = __morestack_make_guard (initial_sp, initial_size);
+  context[BLOCK_SIGNALS] = NULL;
+  *size = initial_size;
+  return ret;
+}
+
+/* Release all the memory associated with a splitstack context.  This
+   may be used if a coroutine exits and the associated stack should be
+   freed.  */
+
+void
+__splitstack_releasecontext (void *context[10])
+{
+  __morestack_release_segments (((struct stack_segment **)
+                                &context[MORESTACK_SEGMENTS]),
+                               1);
+}
+
+/* Like __splitstack_block_signals, but operating on CONTEXT, rather
+   than on the current state.  */
+
+void
+__splitstack_block_signals_context (void *context[NUMBER_OFFSETS], int *new,
+                                   int *old)
+{
+  if (old != NULL)
+    *old = ((uintptr_type) context[BLOCK_SIGNALS]) != 0 ? 0 : 1;
+  if (new != NULL)
+    context[BLOCK_SIGNALS] = (void *) (uintptr_type) (*new ? 0 : 1);
+}
+
+/* Find the stack segments associated with a split stack context.
+   This will return the address of the first stack segment and set
+   *STACK_SIZE to its size.  It will set next_segment, next_sp, and
+   initial_sp which may be passed to __splitstack_find to find the
+   remaining segments.  */
+
+void *
+__splitstack_find_context (void *context[NUMBER_OFFSETS], size_t *stack_size,
+                          void **next_segment, void **next_sp,
+                          void **initial_sp)
+{
+  void *sp;
+  struct stack_segment *segment;
+
+  *initial_sp = context[INITIAL_SP];
+
+  sp = context[CURRENT_STACK];
+  if (sp == NULL)
+    {
+      /* Most likely this context was created but was never used.  The
+        value 2 is a code used by __splitstack_find to mean that we
+        have reached the end of the list of stacks.  */
+      *next_segment = (void *) (uintptr_type) 2;
+      *next_sp = NULL;
+      *initial_sp = NULL;
+      return NULL;
+    }
+
+  segment = context[CURRENT_SEGMENT];
+  if (segment == NULL)
+    {
+      /* Most likely this context was saved by a thread which was not
+        created using __splistack_makecontext and which has never
+        split the stack.  The value 1 is a code used by
+        __splitstack_find to look at the initial stack.  */
+      segment = (struct stack_segment *) (uintptr_type) 1;
+    }
+
+  return __splitstack_find (segment, sp, stack_size, next_segment, next_sp,
+                           initial_sp);
+}
+
 #endif /* !defined (inhibit_libc) */
+#endif /* not powerpc 32-bit */