summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fainelli <florian@openwrt.org>2013-01-09 16:17:21 +0100
committerBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2013-01-10 10:56:19 +0100
commita8dc90eaaa5e6474beac828558d969b1aafee4af (patch)
treeed22c27193dcc91697f6b8782da9a9abd08d42b1
parentdf3a5fcc8d1c3402289375c92df705e978fab58d (diff)
libc: add {get,set,swap,make}context user context manipulation functions
Add the obsolescent SUSv3 family of user context manipulating functions for arm, i386, mips, x86_64. Signed-off-by: Timon ter Braak <timonterbraak@gmail.com> Signed-off-by: Florian Fainelli <florian@openwrt.org> Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> Signed-off-by: Natanael Copa <ncopa@alpinelinux.org> Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
-rw-r--r--Rules.mak2
-rw-r--r--extra/Configs/Config.arm1
-rw-r--r--extra/Configs/Config.i3861
-rw-r--r--extra/Configs/Config.in16
-rw-r--r--extra/Configs/Config.mips1
-rw-r--r--extra/Configs/Config.x86_641
-rw-r--r--include/ucontext.h32
-rw-r--r--libc/.gitignore1
-rw-r--r--libc/sysdeps/linux/Makefile.commonarch20
-rw-r--r--libc/sysdeps/linux/arm/Makefile.arch5
-rw-r--r--libc/sysdeps/linux/arm/getcontext.S80
-rw-r--r--libc/sysdeps/linux/arm/makecontext.c73
-rw-r--r--libc/sysdeps/linux/arm/setcontext.S76
-rw-r--r--libc/sysdeps/linux/arm/swapcontext.S63
-rw-r--r--libc/sysdeps/linux/arm/ucontext_i.sym30
-rw-r--r--libc/sysdeps/linux/i386/Makefile.arch4
-rw-r--r--libc/sysdeps/linux/i386/getcontext.S84
-rw-r--r--libc/sysdeps/linux/i386/makecontext.S123
-rw-r--r--libc/sysdeps/linux/i386/setcontext.S96
-rw-r--r--libc/sysdeps/linux/i386/swapcontext.S110
-rw-r--r--libc/sysdeps/linux/i386/ucontext_i.sym30
-rw-r--r--libc/sysdeps/linux/mips/Makefile.arch4
-rw-r--r--libc/sysdeps/linux/mips/getcontext.S148
-rw-r--r--libc/sysdeps/linux/mips/kernel_rt_sigframe.h10
-rw-r--r--libc/sysdeps/linux/mips/makecontext.S188
-rw-r--r--libc/sysdeps/linux/mips/setcontext.S191
-rw-r--r--libc/sysdeps/linux/mips/swapcontext.S211
-rw-r--r--libc/sysdeps/linux/mips/ucontext_i.sym52
-rw-r--r--libc/sysdeps/linux/x86_64/Makefile.arch5
-rw-r--r--libc/sysdeps/linux/x86_64/__start_context.S49
-rw-r--r--libc/sysdeps/linux/x86_64/getcontext.S88
-rw-r--r--libc/sysdeps/linux/x86_64/makecontext.c121
-rw-r--r--libc/sysdeps/linux/x86_64/setcontext.S103
-rw-r--r--libc/sysdeps/linux/x86_64/swapcontext.S121
-rw-r--r--libc/sysdeps/linux/x86_64/ucontext_i.sym37
-rw-r--r--libpthread/nptl/sysdeps/Makefile.commonarch3
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.commonarch2
37 files changed, 2174 insertions, 8 deletions
diff --git a/Rules.mak b/Rules.mak
index 96871e1ae..8943fbf85 100644
--- a/Rules.mak
+++ b/Rules.mak
@@ -813,3 +813,5 @@ SHARED_END_FILES:=$(LIBGCC_DIR)crtendS.o $(top_builddir)lib/crtn.o
endif
LOCAL_INSTALL_PATH := install_dir
+
+PTHREAD_GENERATE_MANGLE ?= -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*\$$/\#define \1 \2/p"
diff --git a/extra/Configs/Config.arm b/extra/Configs/Config.arm
index 0bb2971a9..dc536434d 100644
--- a/extra/Configs/Config.arm
+++ b/extra/Configs/Config.arm
@@ -11,6 +11,7 @@ config FORCE_OPTIONS_FOR_ARCH
bool
default y
select ARCH_ANY_ENDIAN
+ select ARCH_HAS_UCONTEXT
config CONFIG_ARM_EABI
bool "Build for EABI"
diff --git a/extra/Configs/Config.i386 b/extra/Configs/Config.i386
index 288aa5ebe..92cee3b83 100644
--- a/extra/Configs/Config.i386
+++ b/extra/Configs/Config.i386
@@ -12,6 +12,7 @@ config FORCE_OPTIONS_FOR_ARCH
default y
select ARCH_LITTLE_ENDIAN
select ARCH_HAS_MMU
+ select ARCH_HAS_UCONTEXT
choice
prompt "Target x86 Processor Family"
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index 4bb681207..62bcd9b6c 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -261,6 +261,9 @@ config ARCH_HAS_NO_LDSO
bool
select ARCH_HAS_NO_SHARED
+config ARCH_HAS_UCONTEXT
+ bool
+
config HAVE_SHARED
bool "Enable shared libraries"
depends on !ARCH_HAS_NO_SHARED
@@ -678,6 +681,19 @@ config UCLIBC_SUSV3_LEGACY
WARNING! ABI incompatibility.
+config UCLIBC_HAS_CONTEXT_FUNCS
+ bool "Use obsolescent context control functions"
+ depends on UCLIBC_SUSV3_LEGACY && ARCH_HAS_UCONTEXT
+ help
+ Add into library the SuSv3 obsolescent functions used for context
+ control. The setcontext family allows the implementation in C of
+ advanced control flow patterns such as iterators, fibers, and
+ coroutines. They may be viewed as an advanced version of
+ setjmp/longjmp; whereas the latter allows only a single non-local jump
+ up the stack, setcontext allows the creation of multiple cooperative
+ threads of control, each with its own stack.
+ These functions are: setcontext, getcontext, makecontext, swapcontext.
+
config UCLIBC_SUSV3_LEGACY_MACROS
bool "Enable SuSv3 LEGACY macros"
help
diff --git a/extra/Configs/Config.mips b/extra/Configs/Config.mips
index 063b07cea..48e0b6489 100644
--- a/extra/Configs/Config.mips
+++ b/extra/Configs/Config.mips
@@ -11,6 +11,7 @@ config FORCE_OPTIONS_FOR_ARCH
bool
default y
select ARCH_ANY_ENDIAN
+ select ARCH_HAS_UCONTEXT
choice
prompt "Target ABI"
diff --git a/extra/Configs/Config.x86_64 b/extra/Configs/Config.x86_64
index 1b2808893..4c8c3a9bd 100644
--- a/extra/Configs/Config.x86_64
+++ b/extra/Configs/Config.x86_64
@@ -12,3 +12,4 @@ config FORCE_OPTIONS_FOR_ARCH
default y
select ARCH_LITTLE_ENDIAN
select ARCH_HAS_MMU
+ select ARCH_HAS_UCONTEXT
diff --git a/include/ucontext.h b/include/ucontext.h
index 14a12704e..f11db7794 100644
--- a/include/ucontext.h
+++ b/include/ucontext.h
@@ -15,17 +15,43 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+/* The System V ABI user-level context switching support functions
+ are marked obsolescent by SuSv3. */
+
#ifndef _UCONTEXT_H
#define _UCONTEXT_H 1
#include <features.h>
+#ifdef __UCLIBC_HAS_CONTEXT_FUNCS__
+
/* Get machine dependent definition of data structures. */
#include <sys/ucontext.h>
-/* The System V ABI user-level context switching support functions
- * are marked obsolescent by SuSv3, and are not implemented by
- * uClibc. This header is therefore empty. */
+__BEGIN_DECLS
+
+/* Get user context and store it in variable pointed to by UCP. */
+extern int getcontext (ucontext_t *__ucp) __THROW;
+
+/* Set user context from information of variable pointed to by UCP. */
+extern int setcontext (const ucontext_t *__ucp) __THROW;
+
+/* Save current context in context variable pointed to by OUCP and set
+ context from variable pointed to by UCP. */
+extern int swapcontext (ucontext_t *__restrict __oucp,
+ const ucontext_t *__restrict __ucp) __THROW;
+
+/* Manipulate user context UCP to continue with calling functions FUNC
+ and the ARGC-1 parameters following ARGC when the context is used
+ the next time in `setcontext' or `swapcontext'.
+
+ We cannot say anything about the parameters FUNC takes; `void'
+ is as good as any other choice. */
+extern void makecontext (ucontext_t *__ucp, void (*__func) (void),
+ int __argc, ...) __THROW;
+
+__END_DECLS
+#endif
#endif /* ucontext.h */
diff --git a/libc/.gitignore b/libc/.gitignore
new file mode 100644
index 000000000..f4c03059d
--- /dev/null
+++ b/libc/.gitignore
@@ -0,0 +1 @@
+ucontext_i.[chs]
diff --git a/libc/sysdeps/linux/Makefile.commonarch b/libc/sysdeps/linux/Makefile.commonarch
index c1bc5df30..ac89e7258 100644
--- a/libc/sysdeps/linux/Makefile.commonarch
+++ b/libc/sysdeps/linux/Makefile.commonarch
@@ -37,5 +37,23 @@ headers-y += $(ARCH_HEADERS_OUT)
headers_clean-y += HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT))
HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT)):
$(do_rm) $(ARCH_HEADERS_OUT)
-
endif
+
+CFLAGS-ucontext_i.c = -S
+
+$(ARCH_OUT)/ucontext_i.c: $(ARCH_DIR)/ucontext_i.sym
+ $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(ARCH_OUT)/ucontext_i.s: $(ARCH_OUT)/ucontext_i.c
+ $(compile.c)
+
+$(ARCH_OUT)/ucontext_i.h: $(ARCH_OUT)/ucontext_i.s
+ $(do_sed) $(PTHREAD_GENERATE_MANGLE) $< > $@
+
+pregen-headers-$(UCLIBC_HAS_CONTEXT_FUNCS) += $(ARCH_OUT)/ucontext_i.h
+
+headers_clean-$(UCLIBC_HAS_CONTEXT_FUNCS) += \
+ HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT)/ucontext_i)
+
+HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT)/ucontext_i):
+ $(do_rm) $(addprefix $(ARCH_OUT)/ucontext_i., c h s)
diff --git a/libc/sysdeps/linux/arm/Makefile.arch b/libc/sysdeps/linux/arm/Makefile.arch
index 5fc3e545f..36d988bfd 100644
--- a/libc/sysdeps/linux/arm/Makefile.arch
+++ b/libc/sysdeps/linux/arm/Makefile.arch
@@ -43,3 +43,8 @@ libc-static-y += $(ARCH_OUT)/aeabi_lcsts.o $(ARCH_OUT)/aeabi_math.o \
libc-nonshared-y += $(ARCH_OUT)/aeabi_lcsts.os $(ARCH_OUT)/aeabi_math.os \
$(ARCH_OUT)/aeabi_sighandlers.os $(ARCH_OUT)/aeabi_unwind_cpp_pr1.o
endif
+
+ifeq ($(UCLIBC_HAS_CONTEXT_FUNCS),y)
+CSRC += makecontext.c
+SSRC += getcontext.S setcontext.S swapcontext.S
+endif
diff --git a/libc/sysdeps/linux/arm/getcontext.S b/libc/sysdeps/linux/arm/getcontext.S
new file mode 100644
index 000000000..a987c52f3
--- /dev/null
+++ b/libc/sysdeps/linux/arm/getcontext.S
@@ -0,0 +1,80 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .syntax unified
+ .text
+
+/* int getcontext (ucontext_t *ucp) */
+
+ENTRY(__getcontext)
+ /* No need to save r0-r3, d0-d7, or d16-d31. */
+ add r1, r0, #MCONTEXT_ARM_R4
+ stmia r1, {r4-r11}
+
+ /* Save R13 separately as Thumb can't STM it. */
+ str r13, [r0, #MCONTEXT_ARM_SP]
+ str r14, [r0, #MCONTEXT_ARM_LR]
+ /* Return to LR */
+ str r14, [r0, #MCONTEXT_ARM_PC]
+ /* Return zero */
+ mov r2, #0
+ str r2, [r0, #MCONTEXT_ARM_R0]
+
+ /* Save ucontext_t * across the next call. */
+ mov r4, r0
+
+ /* __sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */
+ mov r0, #SIG_BLOCK
+ mov r1, #0
+ add r2, r4, #UCONTEXT_SIGMASK
+ bl PLTJMP(sigprocmask)
+
+#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
+# ifdef __VFP_FP__
+ /* Store the VFP registers. */
+ /* Following instruction is fstmiax ip!, {d8-d15}. */
+ stc p11, cr8, [r0], #64
+ /* Store the floating-point status register. */
+ /* Following instruction is fmrx r2, fpscr. */
+ mrc p10, 7, r1, cr1, cr0, 0
+ str r1, [r0], #4
+# endif
+#endif
+#ifdef __IWMMXT__
+ /* Save the call-preserved iWMMXt registers. */
+ /* Following instructions are wstrd wr10, [r0], #8 (etc.) */
+ stcl p1, cr10, [r0], #8
+ stcl p1, cr11, [r0], #8
+ stcl p1, cr12, [r0], #8
+ stcl p1, cr13, [r0], #8
+ stcl p1, cr14, [r0], #8
+ stcl p1, cr15, [r0], #8
+#endif
+
+ /* Restore the clobbered R4 and LR. */
+ ldr r14, [r4, #MCONTEXT_ARM_LR]
+ ldr r4, [r4, #MCONTEXT_ARM_R4]
+
+ mov r0, #0
+ DO_RET(r14)
+
+END(__getcontext)
+weak_alias(__getcontext, getcontext)
diff --git a/libc/sysdeps/linux/arm/makecontext.c b/libc/sysdeps/linux/arm/makecontext.c
new file mode 100644
index 000000000..d6ae6f0d7
--- /dev/null
+++ b/libc/sysdeps/linux/arm/makecontext.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdarg.h>
+#include <ucontext.h>
+
+/* Number of arguments that go in registers. */
+#define NREG_ARGS 4
+
+/* Take a context previously prepared via getcontext() and set to
+ call func() with the given int only args. */
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+ extern void __startcontext (void);
+ unsigned long *funcstack;
+ va_list vl;
+ unsigned long *regptr;
+ unsigned int reg;
+ int misaligned;
+
+ /* Start at the top of stack. */
+ funcstack = (unsigned long *) (ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+
+ /* Ensure the stack stays eight byte aligned. */
+ misaligned = ((unsigned long) funcstack & 4) != 0;
+
+ if ((argc > NREG_ARGS) && (argc & 1) != 0)
+ misaligned = !misaligned;
+
+ if (misaligned)
+ funcstack -= 1;
+
+ va_start (vl, argc);
+
+ /* Reserve space for the on-stack arguments. */
+ if (argc > NREG_ARGS)
+ funcstack -= (argc - NREG_ARGS);
+
+ ucp->uc_mcontext.arm_sp = (unsigned long) funcstack;
+ ucp->uc_mcontext.arm_pc = (unsigned long) func;
+
+ /* Exit to startcontext() with the next context in R4 */
+ ucp->uc_mcontext.arm_r4 = (unsigned long) ucp->uc_link;
+ ucp->uc_mcontext.arm_lr = (unsigned long) __startcontext;
+
+ /* The first four arguments go into registers. */
+ regptr = &(ucp->uc_mcontext.arm_r0);
+
+ for (reg = 0; (reg < argc) && (reg < NREG_ARGS); reg++)
+ *regptr++ = va_arg (vl, unsigned long);
+
+ /* And the remainder on the stack. */
+ for (; reg < argc; reg++)
+ *funcstack++ = va_arg (vl, unsigned long);
+
+ va_end (vl);
+}
+weak_alias (__makecontext, makecontext)
diff --git a/libc/sysdeps/linux/arm/setcontext.S b/libc/sysdeps/linux/arm/setcontext.S
new file mode 100644
index 000000000..a5c33a022
--- /dev/null
+++ b/libc/sysdeps/linux/arm/setcontext.S
@@ -0,0 +1,76 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .syntax unified
+ .text
+
+/* int setcontext (const ucontext_t *ucp) */
+
+ENTRY(__setcontext)
+ mov r4, r0
+
+#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
+# ifdef __VFP_FP__
+ /* Following instruction is vldmia r0!, {d8-d15}. */
+ ldc p11, cr8, [r0], #64
+ /* Restore the floating-point status register. */
+ ldr r1, [r0], #4
+ /* Following instruction is fmxr fpscr, r1. */
+ mcr p10, 7, r1, cr1, cr0, 0
+# endif
+#endif
+
+#ifdef __IWMMXT__
+ /* Restore the call-preserved iWMMXt registers. */
+ /* Following instructions are wldrd wr10, [r0], #8 (etc.) */
+ ldcl p1, cr10, [r0], #8
+ ldcl p1, cr11, [r0], #8
+ ldcl p1, cr12, [r0], #8
+ ldcl p1, cr13, [r0], #8
+ ldcl p1, cr14, [r0], #8
+ ldcl p1, cr15, [r0], #8
+#endif
+
+ /* Now bring back the signal status. */
+ mov r0, #SIG_SETMASK
+ add r1, r4, #UCONTEXT_SIGMASK
+ mov r2, #0
+ bl PLTJMP(sigprocmask)
+
+ /* Loading r0-r3 makes makecontext easier. */
+ add r14, r4, #MCONTEXT_ARM_R0
+ ldmia r14, {r0-r11}
+ ldr r13, [r14, #(MCONTEXT_ARM_SP - MCONTEXT_ARM_R0)]
+ add r14, r14, #(MCONTEXT_ARM_LR - MCONTEXT_ARM_R0)
+ ldmia r14, {r14, pc}
+
+END(setcontext)
+weak_alias(__setcontext, setcontext)
+
+ /* Called when a makecontext() context returns. Start the
+ context in R4 or fall through to exit(). */
+ENTRY(__startcontext)
+ movs r0, r4
+ bne PLTJMP(__setcontext)
+
+ @ New context was 0 - exit
+ b PLTJMP(_exit)
+END(__startcontext)
diff --git a/libc/sysdeps/linux/arm/swapcontext.S b/libc/sysdeps/linux/arm/swapcontext.S
new file mode 100644
index 000000000..ba6e31c4d
--- /dev/null
+++ b/libc/sysdeps/linux/arm/swapcontext.S
@@ -0,0 +1,63 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .syntax unified
+ .text
+
+/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
+
+ENTRY(swapcontext)
+
+ /* Have getcontext() do most of the work then fix up
+ LR afterwards. Save R3 to keep the stack aligned. */
+ push {r0,r1,r3,r14}
+ cfi_adjust_cfa_offset (16)
+ cfi_rel_offset (r0,0)
+ cfi_rel_offset (r1,4)
+ cfi_rel_offset (r3,8)
+ cfi_rel_offset (r14,12)
+
+ bl __getcontext
+ mov r4, r0
+
+ pop {r0,r1,r3,r14}
+ cfi_adjust_cfa_offset (-16)
+ cfi_restore (r0)
+ cfi_restore (r1)
+ cfi_restore (r3)
+ cfi_restore (r14)
+
+ /* Exit if getcontext() failed. */
+ cmp r4, #0
+ itt ne
+ movne r0, r4
+ RETINSTR(ne, r14)
+
+ /* Fix up LR and the PC. */
+ str r13,[r0, #MCONTEXT_ARM_SP]
+ str r14,[r0, #MCONTEXT_ARM_LR]
+ str r14,[r0, #MCONTEXT_ARM_PC]
+
+ /* And swap using swapcontext(). */
+ mov r0, r1
+ b __setcontext
+
+END(swapcontext)
diff --git a/libc/sysdeps/linux/arm/ucontext_i.sym b/libc/sysdeps/linux/arm/ucontext_i.sym
new file mode 100644
index 000000000..965032260
--- /dev/null
+++ b/libc/sysdeps/linux/arm/ucontext_i.sym
@@ -0,0 +1,30 @@
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/ucontext.h>
+
+SIG_BLOCK
+SIG_SETMASK
+
+-- Offsets of the fields in the ucontext_t structure.
+#define ucontext(member) offsetof (ucontext_t, member)
+#define mcontext(member) ucontext (uc_mcontext.member)
+
+UCONTEXT_FLAGS ucontext (uc_flags)
+UCONTEXT_LINK ucontext (uc_link)
+UCONTEXT_STACK ucontext (uc_stack)
+UCONTEXT_MCONTEXT ucontext (uc_mcontext)
+UCONTEXT_SIGMASK ucontext (uc_sigmask)
+
+UCONTEXT_REGSPACE ucontext (uc_regspace)
+
+MCONTEXT_TRAP_NO mcontext (trap_no)
+MCONTEXT_ERROR_CODE mcontext (error_code)
+MCONTEXT_OLDMASK mcontext (oldmask)
+MCONTEXT_ARM_R0 mcontext (arm_r0)
+MCONTEXT_ARM_R4 mcontext (arm_r4)
+MCONTEXT_ARM_SP mcontext (arm_sp)
+MCONTEXT_ARM_LR mcontext (arm_lr)
+MCONTEXT_ARM_PC mcontext (arm_pc)
+MCONTEXT_ARM_CPSR mcontext (arm_cpsr)
+MCONTEXT_FAULT_ADDRESS mcontext (fault_address)
diff --git a/libc/sysdeps/linux/i386/Makefile.arch b/libc/sysdeps/linux/i386/Makefile.arch
index a3bf32f56..e7fd28eea 100644
--- a/libc/sysdeps/linux/i386/Makefile.arch
+++ b/libc/sysdeps/linux/i386/Makefile.arch
@@ -18,3 +18,7 @@ endif
ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y)
SSRC += vfork.S clone.S
endif
+
+ifeq ($(UCLIBC_HAS_CONTEXT_FUNCS),y)
+SSRC += makecontext.S setcontext.S getcontext.S swapcontext.S
+endif
diff --git a/libc/sysdeps/linux/i386/getcontext.S b/libc/sysdeps/linux/i386/getcontext.S
new file mode 100644
index 000000000..3221b597c
--- /dev/null
+++ b/libc/sysdeps/linux/i386/getcontext.S
@@ -0,0 +1,84 @@
+/* Save current context.
+ Copyright (C) 2001-2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+
+ENTRY(__getcontext)
+ /* Load address of the context data structure. */
+ movl 4(%esp), %eax
+
+ /* Return value of getcontext. EAX is the only register whose
+ value is not preserved. */
+ movl $0, oEAX(%eax)
+
+ /* Save the 32-bit register values and the return address. */
+ movl %ecx, oECX(%eax)
+ movl %edx, oEDX(%eax)
+ movl %edi, oEDI(%eax)
+ movl %esi, oESI(%eax)
+ movl %ebp, oEBP(%eax)
+ movl (%esp), %ecx
+ movl %ecx, oEIP(%eax)
+ leal 4(%esp), %ecx /* Exclude the return address. */
+ movl %ecx, oESP(%eax)
+ movl %ebx, oEBX(%eax)
+
+ /* Save the FS segment register. We don't touch the GS register
+ since it is used for threads. */
+ xorl %edx, %edx
+ movw %fs, %dx
+ movl %edx, oFS(%eax)
+
+ /* We have separate floating-point register content memory on the
+ stack. We use the __fpregs_mem block in the context. Set the
+ links up correctly. */
+ leal oFPREGSMEM(%eax), %ecx
+ movl %ecx, oFPREGS(%eax)
+ /* Save the floating-point context. */
+ fnstenv (%ecx)
+ /* And load it right back since the processor changes the mask.
+ Intel thought this opcode to be used in interrupt handlers which
+ would block all exceptions. */
+ fldenv (%ecx)
+
+ /* Save the current signal mask. */
+ pushl %ebx
+ cfi_adjust_cfa_offset (4)
+ cfi_rel_offset (ebx, 0)
+ leal oSIGMASK(%eax), %edx
+ xorl %ecx, %ecx
+ movl $SIG_BLOCK, %ebx
+ movl $__NR_sigprocmask, %eax
+ ENTER_KERNEL
+ popl %ebx
+ cfi_adjust_cfa_offset (-4)
+ cfi_restore (ebx)
+ cmpl $-4095, %eax /* Check %eax for error. */
+ jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */
+
+ /* All done, return 0 for success. */
+ xorl %eax, %eax
+L(pseudo_end):
+ ret
+PSEUDO_END(__getcontext)
+
+weak_alias (__getcontext, getcontext)
diff --git a/libc/sysdeps/linux/i386/makecontext.S b/libc/sysdeps/linux/i386/makecontext.S
new file mode 100644
index 000000000..d12799d80
--- /dev/null
+++ b/libc/sysdeps/linux/i386/makecontext.S
@@ -0,0 +1,123 @@
+/* Create new context.
+ Copyright (C) 2001,2002,2005,2007,2008,2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+
+ENTRY(__makecontext)
+ movl 4(%esp), %eax
+
+ /* Load the address of the function we are supposed to run. */
+ movl 8(%esp), %ecx
+
+ /* Compute the address of the stack. The information comes from
+ to us_stack element. */
+ movl oSS_SP(%eax), %edx
+ movl %ecx, oEIP(%eax)
+ addl oSS_SIZE(%eax), %edx
+
+ /* Remember the number of parameters for the exit handler since
+ it has to remove them. We store the number in the EBX register
+ which the function we will call must preserve. */
+ movl 12(%esp), %ecx
+ movl %ecx, oEBX(%eax)
+
+ /* Make room on the new stack for the parameters.
+ Room for the arguments, return address (== L(exitcode)) and
+ oLINK pointer is needed. One of the pointer sizes is subtracted
+ after aligning the stack. */
+ negl %ecx
+ leal -4(%edx,%ecx,4), %edx
+ negl %ecx
+
+ /* Align the stack. */
+ andl $0xfffffff0, %edx
+ subl $4, %edx
+
+ /* Store the future stack pointer. */
+ movl %edx, oESP(%eax)
+
+ /* Put the next context on the new stack (from the uc_link
+ element). */
+ movl oLINK(%eax), %eax
+ movl %eax, 4(%edx,%ecx,4)
+
+ /* Copy all the parameters. */
+ jecxz 2f
+1: movl 12(%esp,%ecx,4), %eax
+ movl %eax, (%edx,%ecx,4)
+ decl %ecx
+ jnz 1b
+2:
+
+ /* If the function we call returns we must continue with the
+ context which is given in the uc_link element. To do this
+ set the return address for the function the user provides
+ to a little bit of helper code which does the magic (see
+ below). */
+#ifdef __PIC__
+ call 1f
+ cfi_adjust_cfa_offset (4)
+1: popl %ecx
+ cfi_adjust_cfa_offset (-4)
+ addl $L(exitcode)-1b, %ecx
+ movl %ecx, (%edx)
+#else
+ movl $L(exitcode), (%edx)
+#endif
+ /* 'makecontext' returns no value. */
+L(pseudo_end):
+ ret
+
+ /* This is the helper code which gets called if a function which
+ is registered with 'makecontext' returns. In this case we
+ have to install the context listed in the uc_link element of
+ the context 'makecontext' manipulated at the time of the
+ 'makecontext' call. If the pointer is NULL the process must
+ terminate. */
+ cfi_endproc
+L(exitcode):
+ /* This removes the parameters passed to the function given to
+ 'makecontext' from the stack. EBX contains the number of
+ parameters (see above). */
+ leal (%esp,%ebx,4), %esp
+
+#ifdef __PIC__
+ call 1f
+1: popl %ebx
+ addl $_GLOBAL_OFFSET_TABLE_+[.