summaryrefslogtreecommitdiff
path: root/toolchain/uclibc
diff options
context:
space:
mode:
Diffstat (limited to 'toolchain/uclibc')
-rw-r--r--toolchain/uclibc/Makefile1
-rw-r--r--toolchain/uclibc/patches/uclibc-git-20140613.patch (renamed from toolchain/uclibc/patches/uclibc-git-20140602.patch)241
-rw-r--r--toolchain/uclibc/patches/xxx-xtensa-nptl.patch3515
3 files changed, 3725 insertions, 32 deletions
diff --git a/toolchain/uclibc/Makefile b/toolchain/uclibc/Makefile
index 7184d6220..7346b965e 100644
--- a/toolchain/uclibc/Makefile
+++ b/toolchain/uclibc/Makefile
@@ -9,6 +9,7 @@ include Makefile.inc
include ${TOPDIR}/mk/buildhlp.mk
TARGET_CFLAGS:=$(filter-out -flto,$(TARGET_CFLAGS))
+TARGET_CFLAGS:=$(filter-out -mtext-section-literals,$(TARGET_CFLAGS))
ifeq (${ADK_MAKE_PARALLEL},y)
UCLIBC_MAKEOPTS+= -j${ADK_MAKE_JOBS}
diff --git a/toolchain/uclibc/patches/uclibc-git-20140602.patch b/toolchain/uclibc/patches/uclibc-git-20140613.patch
index 28b5f0c82..725bf8cda 100644
--- a/toolchain/uclibc/patches/uclibc-git-20140602.patch
+++ b/toolchain/uclibc/patches/uclibc-git-20140613.patch
@@ -33284,8 +33284,16 @@ diff -Nur uClibc-0.9.33.2/ldso/ldso/arm/aeabi_read_tp.S uClibc-git/ldso/ldso/arm
diff -Nur uClibc-0.9.33.2/ldso/ldso/arm/dl-startup.h uClibc-git/ldso/ldso/arm/dl-startup.h
--- uClibc-0.9.33.2/ldso/ldso/arm/dl-startup.h 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/ldso/ldso/arm/dl-startup.h 2014-06-02 17:40:33.926711497 +0200
-@@ -14,6 +14,7 @@
++++ uClibc-git/ldso/ldso/arm/dl-startup.h 2014-06-13 18:29:20.810293291 +0200
+@@ -7,13 +7,14 @@
+ */
+
+ #include <features.h>
+-#include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ #if !defined(__thumb__)
+ __asm__(
" .text\n"
" .globl _start\n"
" .type _start,%function\n"
@@ -33325,8 +33333,16 @@ diff -Nur uClibc-0.9.33.2/ldso/ldso/arm/elfinterp.c uClibc-git/ldso/ldso/arm/elf
{
diff -Nur uClibc-0.9.33.2/ldso/ldso/arm/resolve.S uClibc-git/ldso/ldso/arm/resolve.S
--- uClibc-0.9.33.2/ldso/ldso/arm/resolve.S 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/ldso/ldso/arm/resolve.S 2014-06-02 17:40:33.926711497 +0200
-@@ -101,7 +101,7 @@
++++ uClibc-git/ldso/ldso/arm/resolve.S 2014-06-13 18:29:20.834293397 +0200
+@@ -92,6 +92,7 @@
+
+ #include <sys/syscall.h>
+ #include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ #include <features.h>
+
+@@ -101,7 +102,7 @@
.text
.align 4 @ 16 byte boundary and there are 32 bytes below (arm case)
@@ -47267,10 +47283,32 @@ diff -Nur uClibc-0.9.33.2/libc/string/arc/strlen.S uClibc-git/libc/string/arc/st
+ sub_s.ne r1,r1,r1
+END(strlen)
+libc_hidden_def(strlen)
+diff -Nur uClibc-0.9.33.2/libc/string/arm/memcmp.S uClibc-git/libc/string/arm/memcmp.S
+--- uClibc-0.9.33.2/libc/string/arm/memcmp.S 2012-05-15 09:20:09.000000000 +0200
++++ uClibc-git/libc/string/arm/memcmp.S 2014-06-13 18:29:20.834293397 +0200
+@@ -31,6 +31,7 @@
+
+ #include <features.h>
+ #include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ .text
+ .global memcmp
+diff -Nur uClibc-0.9.33.2/libc/string/arm/_memcpy.S uClibc-git/libc/string/arm/_memcpy.S
+--- uClibc-0.9.33.2/libc/string/arm/_memcpy.S 2012-05-15 09:20:09.000000000 +0200
++++ uClibc-git/libc/string/arm/_memcpy.S 2014-06-13 18:29:20.834293397 +0200
+@@ -40,6 +40,7 @@
+ #include <features.h>
+ #include <endian.h>
+ #include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ #if !defined(THUMB1_ONLY)
+ /*
diff -Nur uClibc-0.9.33.2/libc/string/arm/memset.S uClibc-git/libc/string/arm/memset.S
--- uClibc-0.9.33.2/libc/string/arm/memset.S 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/string/arm/memset.S 2014-06-02 17:40:34.182712914 +0200
-@@ -13,9 +13,8 @@
++++ uClibc-git/libc/string/arm/memset.S 2014-06-13 18:29:20.834293397 +0200
+@@ -13,13 +13,13 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
@@ -47282,10 +47320,26 @@ diff -Nur uClibc-0.9.33.2/libc/string/arm/memset.S uClibc-git/libc/string/arm/me
#include <features.h>
#include <sys/syscall.h>
+ #include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ .text
+ .global memset
+diff -Nur uClibc-0.9.33.2/libc/string/arm/strcmp.S uClibc-git/libc/string/arm/strcmp.S
+--- uClibc-0.9.33.2/libc/string/arm/strcmp.S 2012-05-15 09:20:09.000000000 +0200
++++ uClibc-git/libc/string/arm/strcmp.S 2014-06-13 18:29:20.838293415 +0200
+@@ -31,6 +31,7 @@
+
+ #include <features.h>
+ #include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ .text
+ .global strcmp
diff -Nur uClibc-0.9.33.2/libc/string/arm/strlen.S uClibc-git/libc/string/arm/strlen.S
--- uClibc-0.9.33.2/libc/string/arm/strlen.S 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/string/arm/strlen.S 2014-06-02 17:40:34.182712914 +0200
-@@ -13,9 +13,8 @@
++++ uClibc-git/libc/string/arm/strlen.S 2014-06-13 18:29:20.838293415 +0200
+@@ -13,14 +13,14 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
@@ -47297,6 +47351,12 @@ diff -Nur uClibc-0.9.33.2/libc/string/arm/strlen.S uClibc-git/libc/string/arm/st
#include <features.h>
#include <endian.h>
+ #include <sys/syscall.h>
+ #include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ /* size_t strlen(const char *S)
+ * entry: r0 -> string
diff -Nur uClibc-0.9.33.2/libc/string/avr32/Makefile uClibc-git/libc/string/avr32/Makefile
--- uClibc-0.9.33.2/libc/string/avr32/Makefile 2012-05-15 09:20:09.000000000 +0200
+++ uClibc-git/libc/string/avr32/Makefile 2014-06-02 17:40:34.182712914 +0200
@@ -53640,7 +53700,7 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/aeabi_unwind_cpp_pr1.c uClibc-g
-fexceptions, we end up with references to this personality
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/bits/arm_asm.h uClibc-git/libc/sysdeps/linux/arm/bits/arm_asm.h
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/bits/arm_asm.h 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/sysdeps/linux/arm/bits/arm_asm.h 2014-06-02 17:40:34.282713468 +0200
++++ uClibc-git/libc/sysdeps/linux/arm/bits/arm_asm.h 2014-06-13 18:29:20.838293415 +0200
@@ -3,8 +3,10 @@
#define _ARM_ASM_H
@@ -53652,6 +53712,57 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/bits/arm_asm.h uClibc-git/libc/
#define IT(t, cond) i##t cond
#else
/* XXX: This can be removed if/when we require an assembler that supports
+@@ -24,12 +26,4 @@
+ #define THUMB1_ONLY 1
+ #endif
+
+-#if defined(__USE_BX__)
+-# if ( defined (__ARM_ARCH_2__) || defined (__ARM_ARCH_3__) \
+- || defined (__ARM_ARCH_3M__) || defined (__ARM_ARCH_4__) \
+- )
+-# error Use of BX was requested, but is not available on the target processor.
+-# endif /* ARCH level */
+-#endif /* __USE_BX__ */
+-
+ #endif /* _ARM_ASM_H */
+diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/bits/arm_bx.h uClibc-git/libc/sysdeps/linux/arm/bits/arm_bx.h
+--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/bits/arm_bx.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-git/libc/sysdeps/linux/arm/bits/arm_bx.h 2014-06-13 18:29:20.838293415 +0200
+@@ -0,0 +1,34 @@
++/* Copyright (C) 2013 Yann E. MORIN <yann.morin.1998@free.fr>
++ *
++ * This file 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.
++ *
++ * This file 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/>.
++ */
++
++#ifndef _ARM_BX_H
++#define _ARM_BX_H
++
++/* We need features.h first */
++#if !defined _FEATURES_H
++#error Please include features.h first
++#endif /* features.h not yet included */
++
++#if defined(__USE_BX__)
++# if ( defined (__ARM_ARCH_2__) || defined (__ARM_ARCH_3__) \
++ || defined (__ARM_ARCH_3M__) || defined (__ARM_ARCH_4__) \
++ )
++# error Use of BX was requested, but is not available on the target processor.
++# endif /* ARCH level */
++#endif /* __USE_BX__ */
++
++#endif /* _ARM_BX_H */
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/bits/armsigctx.h uClibc-git/libc/sysdeps/linux/arm/bits/armsigctx.h
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/bits/armsigctx.h 2012-05-15 09:20:09.000000000 +0200
+++ uClibc-git/libc/sysdeps/linux/arm/bits/armsigctx.h 2014-06-02 17:40:34.282713468 +0200
@@ -53947,7 +54058,7 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/bsd-_setjmp.S uClibc-git/libc/s
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/clone.S uClibc-git/libc/sysdeps/linux/arm/clone.S
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/clone.S 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/sysdeps/linux/arm/clone.S 2014-06-02 17:40:34.306713601 +0200
++++ uClibc-git/libc/sysdeps/linux/arm/clone.S 2014-06-13 18:29:20.838293415 +0200
@@ -13,9 +13,8 @@
Lesser General Public License for more details.
@@ -53960,11 +54071,20 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/clone.S uClibc-git/libc/sysdeps
/* clone() is even more special than fork() as it mucks with stacks
and invokes a function in the right context after its all over. */
-@@ -111,8 +110,8 @@
+@@ -25,6 +24,7 @@
+ #include <bits/errno.h>
+ #include <sys/syscall.h>
+ #include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ #if defined(__NR_clone)
+ /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
+@@ -111,8 +111,9 @@
ldr r4, [sp, #12]
DO_CALL (clone)
movs a1, a1
- blt __error
++ IT(t, ne)
ldmnefd sp!, {r4}
+ blt __error
IT(t, ne)
@@ -54191,8 +54311,8 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/jmpbuf-unwind.h uClibc-git/libc
+#endif
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/__longjmp.S uClibc-git/libc/sysdeps/linux/arm/__longjmp.S
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/__longjmp.S 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/sysdeps/linux/arm/__longjmp.S 2014-06-02 17:40:34.266713379 +0200
-@@ -13,16 +13,11 @@
++++ uClibc-git/libc/sysdeps/linux/arm/__longjmp.S 2014-06-13 18:29:20.838293415 +0200
+@@ -13,16 +13,12 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
@@ -54208,6 +54328,7 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/__longjmp.S uClibc-git/libc/sys
-#define _ASM
-#include <bits/setjmp.h>
-
++#include <bits/arm_bx.h>
.global __longjmp
.type __longjmp,%function
@@ -54362,8 +54483,8 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/Makefile.arch uClibc-git/libc/s
+ )
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/mmap64.S uClibc-git/libc/sysdeps/linux/arm/mmap64.S
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/mmap64.S 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/sysdeps/linux/arm/mmap64.S 2014-06-02 17:40:34.306713601 +0200
-@@ -12,17 +12,16 @@
++++ uClibc-git/libc/sysdeps/linux/arm/mmap64.S 2014-06-13 18:29:20.838293415 +0200
+@@ -12,17 +12,17 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
@@ -54379,6 +54500,7 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/mmap64.S uClibc-git/libc/sysdep
#include <bits/errno.h>
#include <sys/syscall.h>
#include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
-#if defined __UCLIBC_HAS_LFS__ && defined __NR_mmap2
+#ifdef __NR_mmap2
@@ -54873,8 +54995,8 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/sys/user.h uClibc-git/libc/sysd
#define _SYS_USER_H 1
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/syscall-eabi.S uClibc-git/libc/sysdeps/linux/arm/syscall-eabi.S
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/syscall-eabi.S 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/sysdeps/linux/arm/syscall-eabi.S 2014-06-02 17:40:34.310713623 +0200
-@@ -12,9 +12,8 @@
++++ uClibc-git/libc/sysdeps/linux/arm/syscall-eabi.S 2014-06-13 18:29:20.838293415 +0200
+@@ -12,12 +12,12 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
@@ -54886,10 +55008,14 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/syscall-eabi.S uClibc-git/libc/
#include <sys/syscall.h>
#include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ /* In the EABI syscall interface, we don't need a special syscall to
+ implement syscall(). It won't work reliably with 64-bit arguments
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/sysdep.h uClibc-git/libc/sysdeps/linux/arm/sysdep.h
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/sysdep.h 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/sysdeps/linux/arm/sysdep.h 2014-06-02 17:40:34.310713623 +0200
-@@ -13,9 +13,8 @@
++++ uClibc-git/libc/sysdeps/linux/arm/sysdep.h 2014-06-13 18:29:20.838293415 +0200
+@@ -13,15 +13,14 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
@@ -54901,6 +55027,13 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/sysdep.h uClibc-git/libc/sysdep
#ifndef _LINUX_ARM_SYSDEP_H
#define _LINUX_ARM_SYSDEP_H 1
+
+ #include <common/sysdep.h>
+-#include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ #include <sys/syscall.h>
+ /* For Linux we can use the system call table in the header file
@@ -157,6 +156,7 @@
#define PSEUDO_END_ERRVAL(name) \
END (name)
@@ -54969,8 +55102,16 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/unwind.h uClibc-git/libc/sysdep
ABI defined objects, and GNU support routines. */
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/arm/vfork.S uClibc-git/libc/sysdeps/linux/arm/vfork.S
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/vfork.S 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/sysdeps/linux/arm/vfork.S 2014-06-02 17:40:34.310713623 +0200
-@@ -104,5 +104,5 @@
++++ uClibc-git/libc/sysdeps/linux/arm/vfork.S 2014-06-13 18:29:20.838293415 +0200
+@@ -7,6 +7,7 @@
+
+ #include <features.h>
+ #include <bits/arm_asm.h>
++#include <bits/arm_bx.h>
+
+ #define _ERRNO_H
+ #include <bits/errno.h>
+@@ -104,5 +105,5 @@
.size __vfork,.-__vfork
weak_alias(__vfork,vfork)
@@ -83209,7 +83350,7 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/x86_64/setjmp.S uClibc-git/libc/sys
.type __sigsetjmp,%function
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/x86_64/sigaction.c uClibc-git/libc/sysdeps/linux/x86_64/sigaction.c
--- uClibc-0.9.33.2/libc/sysdeps/linux/x86_64/sigaction.c 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libc/sysdeps/linux/x86_64/sigaction.c 2014-06-02 17:40:34.686715704 +0200
++++ uClibc-git/libc/sysdeps/linux/x86_64/sigaction.c 2014-06-13 18:29:20.838293415 +0200
@@ -13,9 +13,8 @@
Lesser General Public License for more details.
@@ -83232,6 +83373,27 @@ diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/x86_64/sigaction.c uClibc-git/libc/
#ifdef __NR_rt_sigaction
/* Using the hidden attribute here does not change the code but it
+@@ -115,11 +111,19 @@
+ signal handlers work right. Important are both the names
+ (__restore_rt) and the exact instruction sequence.
+ If you ever feel the need to make any changes, please notify the
+- appropriate GDB maintainer. */
++ appropriate GDB maintainer.
++
++ The unwind information starts a byte before __restore_rt, so that
++ it is found when unwinding, to get an address the unwinder assumes
++ will be in the middle of a call instruction. See the Linux kernel
++ (the i386 vsyscall, in particular) for an explanation of the complex
++ unwind information used here in order to get the traditional CFA.
++ */
+
+ #define RESTORE(name, syscall) RESTORE2(name, syscall)
+ #define RESTORE2(name, syscall) \
+ __asm__ ( \
++ "nop\n" \
+ ".text\n" \
+ "__" #name ":\n" \
+ " movq $" #syscall ", %rax\n" \
diff -Nur uClibc-0.9.33.2/libc/sysdeps/linux/x86_64/__start_context.S uClibc-git/libc/sysdeps/linux/x86_64/__start_context.S
--- uClibc-0.9.33.2/libc/sysdeps/linux/x86_64/__start_context.S 1970-01-01 01:00:00.000000000 +0100
+++ uClibc-git/libc/sysdeps/linux/x86_64/__start_context.S 2014-06-02 17:40:34.682715682 +0200
@@ -101011,7 +101173,7 @@ diff -Nur uClibc-0.9.33.2/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthr
#include <lowlevellock.h>
diff -Nur uClibc-0.9.33.2/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
--- uClibc-0.9.33.2/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S 2014-06-02 17:40:35.098717984 +0200
++++ uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S 2014-06-13 18:29:20.838293415 +0200
@@ -13,9 +13,8 @@
Lesser General Public License for more details.
@@ -101024,6 +101186,14 @@ diff -Nur uClibc-0.9.33.2/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthr
#include <sysdep.h>
#include <lowlevellock.h>
+@@ -23,6 +22,7 @@
+ #include <pthread-errnos.h>
+ #include <pthread-pi-defines.h>
+ #include <bits/kernel-features.h>
++#include <tcb-offsets.h>
+
+
+ .text
diff -Nur uClibc-0.9.33.2/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
--- uClibc-0.9.33.2/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S 2012-05-15 09:20:09.000000000 +0200
+++ uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S 2014-06-02 17:40:35.098717984 +0200
@@ -107277,7 +107447,7 @@ diff -Nur uClibc-0.9.33.2/Makefile.help uClibc-git/Makefile.help
@echo ' PREFIX= - Prepended prefix'
diff -Nur uClibc-0.9.33.2/Makefile.in uClibc-git/Makefile.in
--- uClibc-0.9.33.2/Makefile.in 2012-05-15 09:20:09.000000000 +0200
-+++ uClibc-git/Makefile.in 2014-06-02 17:40:33.670710081 +0200
++++ uClibc-git/Makefile.in 2014-06-13 18:29:20.642292552 +0200
@@ -8,18 +8,8 @@
#--------------------------------------------------------------
# You shouldn't need to mess with anything beyond this point...
@@ -107439,7 +107609,7 @@ diff -Nur uClibc-0.9.33.2/Makefile.in uClibc-git/Makefile.in
DEVEL_PREFIX=/usr/ \
HOSTCC="$(HOSTCC)" \
install
-@@ -210,16 +225,27 @@
+@@ -210,21 +225,34 @@
# a "y" here means the feature is enabled and so we should *not* rm it.
# if the option expands to nothing though, we can punt the headers.
HEADERS_RM- := \
@@ -107467,7 +107637,14 @@ diff -Nur uClibc-0.9.33.2/Makefile.in uClibc-git/Makefile.in
bits/uClibc_uintmaxtostr.h \
bits/uClibc_uwchar.h \
bits/uClibc_va_copy.h \
-@@ -259,18 +285,23 @@
+ bits/sigcontextinfo.h \
+ bits/stackinfo.h \
++ atomic.h \
++ bits/atomic.h \
+ tls.h \
+ rpc/des_crypt.h \
+ rpc/key_prot.h \
+@@ -259,18 +287,23 @@
HEADERS_RM-$(UCLIBC_HAS_REGEX) += regex.h regexp.h
HEADERS_RM-$(UCLIBC_HAS_RPC) += rpc
HEADERS_RM-$(UCLIBC_HAS_SHADOW) += shadow.h
@@ -107493,7 +107670,7 @@ diff -Nur uClibc-0.9.33.2/Makefile.in uClibc-git/Makefile.in
bits/inotify.h \
sys/inotify.h \
sys/kdaemon.h \
-@@ -288,11 +319,13 @@
+@@ -288,11 +321,13 @@
sys/sysinfo.h \
bits/timerfd.h \
sys/timerfd.h \
@@ -107507,7 +107684,7 @@ diff -Nur uClibc-0.9.33.2/Makefile.in uClibc-git/Makefile.in
ifneq ($(findstring install,$(MAKECMDGOALS)),)
$(addprefix $(PREFIX)$(DEVEL_PREFIX),include $(MULTILIB_DIR)):
-@@ -303,7 +336,9 @@
+@@ -303,7 +338,9 @@
$(do_mkdir)
endif
endif
@@ -107518,7 +107695,7 @@ diff -Nur uClibc-0.9.33.2/Makefile.in uClibc-git/Makefile.in
@$(call disp_install,"include -> $(PREFIX)$(DEVEL_PREFIX)include")
$(Q)top_builddir=$(top_builddir) \
$(top_srcdir)extra/scripts/install_headers.sh \
-@@ -346,12 +381,7 @@
+@@ -346,12 +383,7 @@
else
-$(INSTALL) -m 755 $(top_builddir)lib/libc.so $(PREFIX)$(DEVEL_PREFIX)$(MULTILIB_DIR)/
endif
@@ -107532,7 +107709,7 @@ diff -Nur uClibc-0.9.33.2/Makefile.in uClibc-git/Makefile.in
ifeq ($(UCLIBC_HAS_THREADS),y)
ifneq ($(LINUXTHREADS_OLD),y)
ifeq ($(HARDWIRED_ABSPATH),y)
-@@ -422,49 +452,55 @@
+@@ -422,49 +454,55 @@
install_hostutils: hostutils
$(Q)$(MAKE) CROSS_COMPILE="$(CROSS_COMPILE)" CC="$(CC)" HOSTCC="$(HOSTCC)" DOTHOST=.host -C utils utils_install
@@ -107611,7 +107788,7 @@ diff -Nur uClibc-0.9.33.2/Makefile.in uClibc-git/Makefile.in
menuconfig-clean-y:
$(Q)$(MAKE) -C extra/config CLEAN_extra/config
-@@ -484,11 +520,11 @@
+@@ -484,11 +522,11 @@
$(Q)$(RM) $(top_builddir)extra/scripts/unifdef
$(Q)$(RM) -r $(LOCAL_INSTALL_PATH)
@@ -107626,7 +107803,7 @@ diff -Nur uClibc-0.9.33.2/Makefile.in uClibc-git/Makefile.in
dist release:
$(RM) ../uClibc-$(VERSION).tar
-@@ -499,7 +535,9 @@
+@@ -499,7 +537,9 @@
du -b ../uClibc-$(VERSION).tar.{bz2,xz}
test check: test_compile
diff --git a/toolchain/uclibc/patches/xxx-xtensa-nptl.patch b/toolchain/uclibc/patches/xxx-xtensa-nptl.patch
new file mode 100644
index 000000000..16241e161
--- /dev/null
+++ b/toolchain/uclibc/patches/xxx-xtensa-nptl.patch
@@ -0,0 +1,3515 @@
+diff -Nur uClibc-git/include/elf.h uClibc-xtensa/include/elf.h
+--- uClibc-git/include/elf.h 2014-06-02 17:40:33.826710944 +0200
++++ uClibc-xtensa/include/elf.h 2014-06-03 16:03:19.065886532 +0200
+@@ -3072,8 +3071,11 @@
+ #define R_XTENSA_SLOT12_ALT 47
+ #define R_XTENSA_SLOT13_ALT 48
+ #define R_XTENSA_SLOT14_ALT 49
++#define R_XTENSA_TLSDESC_FN 50
++#define R_XTENSA_TLSDESC_ARG 51
++#define R_XTENSA_TLS_TPOFF 53
+ /* Keep this the last entry. */
+-#define R_XTENSA_NUM 50
++#define R_XTENSA_NUM 54
+
+ /* C6X specific relocs */
+ #define R_C6000_NONE 0
+diff -Nur uClibc-git/include/link.h uClibc-xtensa/include/link.h
+--- uClibc-git/include/link.h 2014-06-02 17:40:33.846711055 +0200
++++ uClibc-xtensa/include/link.h 2014-06-03 15:28:27.185347373 +0200
+@@ -132,6 +132,8 @@
+ size_t l_tls_modid;
+ /* Nonzero if _dl_init_static_tls should be called for this module */
+ unsigned int l_need_tls_init:1;
++ /* Address of TLS descriptor hash table. */
++ void *l_tlsdesc_table;
+ #endif
+ #endif
+ };
+diff -Nur uClibc-git/ldso/include/dl-hash.h uClibc-xtensa/ldso/include/dl-hash.h
+--- uClibc-git/ldso/include/dl-hash.h 2014-06-02 17:40:33.902711365 +0200
++++ uClibc-xtensa/ldso/include/dl-hash.h 2014-06-03 15:29:09.505536959 +0200
+@@ -70,6 +70,8 @@
+ size_t l_tls_modid;
+ /* Nonzero if _dl_init_static_tls should be called for this module */
+ unsigned int l_need_tls_init:1;
++ /* Address of TLS descriptor hash table. */
++ void *l_tlsdesc_table;
+ #endif
+
+ ElfW(Addr) mapaddr;
+diff -Nur uClibc-git/ldso/include/inline-hashtab.h uClibc-xtensa/ldso/include/inline-hashtab.h
+--- uClibc-git/ldso/include/inline-hashtab.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/ldso/include/inline-hashtab.h 2014-06-03 11:57:42.031052092 +0200
+@@ -0,0 +1,265 @@
++/*
++ * The hashcode handling code below is heavily inspired in libiberty's
++ * hashtab code, but with most adaptation points and support for
++ * deleting elements removed.
++ *
++ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
++ * Contributed by Vladimir Makarov (vmakarov@cygnus.com).
++ */
++
++#ifndef INLINE_HASHTAB_H
++# define INLINE_HASHTAB_H 1
++
++static __always_inline unsigned long
++higher_prime_number(unsigned long n)
++{
++ /* These are primes that are near, but slightly smaller than, a power of two. */
++ static const unsigned long primes[] = {
++ 7,
++ 13,
++ 31,
++ 61,
++ 127,
++ 251,
++ 509,
++ 1021,
++ 2039,
++ 4093,
++ 8191,
++ 16381,
++ 32749,
++ 65521,
++ 131071,
++ 262139,
++ 524287,
++ 1048573,
++ 2097143,
++ 4194301,
++ 8388593,
++ 16777213,
++ 33554393,
++ 67108859,
++ 134217689,
++ 268435399,
++ 536870909,
++ 1073741789,
++ /* 4294967291 */
++ ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
++ };
++ const unsigned long *low = &primes[0];
++ const unsigned long *high = &primes[ARRAY_SIZE(primes)];
++
++ while (low != high) {
++ const unsigned long *mid = low + (high - low) / 2;
++ if (n > *mid)
++ low = mid + 1;
++ else
++ high = mid;
++ }
++
++#if 0
++ /* If we've run out of primes, abort. */
++ if (n > *low) {
++ fprintf(stderr, "Cannot find prime bigger than %lu\n", n);
++ abort();
++ }
++#endif
++
++ return *low;
++}
++
++struct funcdesc_ht
++{
++ /* Table itself */
++ void **entries;
++
++ /* Current size (in entries) of the hash table */
++ size_t size;
++
++ /* Current number of elements */
++ size_t n_elements;
++};
++
++static __always_inline struct funcdesc_ht *
++htab_create(void)
++{
++ struct funcdesc_ht *ht = _dl_malloc(sizeof(*ht));
++ size_t ent_size;
++
++ if (!ht)
++ return NULL;
++ ht->size = 3;
++ ent_size = sizeof(void *) * ht->size;
++ ht->entries = _dl_malloc(ent_size);
++ if (!ht->entries)
++ return NULL;
++
++ ht->n_elements = 0;
++ _dl_memset(ht->entries, 0, ent_size);
++
++ return ht;
++}
++
++/*
++ * This is only called from _dl_loadaddr_unmap, so it's safe to call
++ * _dl_free(). See the discussion below.
++ */
++static __always_inline void
++htab_delete(struct funcdesc_ht *htab)
++{
++ size_t i;
++
++ for (i = htab->size - 1; i >= 0; i--)
++ if (htab->entries[i])
++ _dl_free(htab->entries[i]);
++
++ _dl_free(htab->entries);
++ _dl_free(htab);
++}
++
++/*
++ * Similar to htab_find_slot, but without several unwanted side effects:
++ * - Does not call htab->eq_f when it finds an existing entry.
++ * - Does not change the count of elements/searches/collisions in the
++ * hash table.
++ * This function also assumes there are no deleted entries in the table.
++ * HASH is the hash value for the element to be inserted.
++ */
++static __always_inline void **
++find_empty_slot_for_expand(struct funcdesc_ht *htab, int hash)
++{
++ size_t size = htab->size;
++ unsigned int index = hash % size;
++ void **slot = htab->entries + index;
++ int hash2;
++
++ if (!*slot)
++ return slot;
++
++ hash2 = 1 + hash % (size - 2);
++ for (;;) {
++ index += hash2;
++ if (index >= size)
++ index -= size;
++
++ slot = htab->entries + index;
++ if (!*slot)
++ return slot;
++ }
++}
++
++/*
++ * The following function changes size of memory allocated for the
++ * entries and repeatedly inserts the table elements. The occupancy
++ * of the table after the call will be about 50%. Naturally the hash
++ * table must already exist. Remember also that the place of the
++ * table entries is changed. If memory allocation failures are allowed,
++ * this function will return zero, indicating that the table could not be
++ * expanded. If all goes well, it will return a non-zero value.
++ */
++static __always_inline int
++htab_expand(struct funcdesc_ht *htab, int (*hash_fn) (void *))
++{
++ void **oentries;
++ void **olimit;
++ void **p;
++ void **nentries;
++ size_t nsize;
++
++ oentries = htab->entries;
++ olimit = oentries + htab->size;
++
++ /*
++ * Resize only when table after removal of unused elements is either
++ * too full or too empty.
++ */
++ if (htab->n_elements * 2 > htab->size)
++ nsize = higher_prime_number(htab->n_elements * 2);
++ else
++ nsize = htab->size;
++
++ nentries = _dl_malloc(sizeof(*nentries) * nsize);
++ _dl_memset(nentries, 0, sizeof(*nentries) * nsize);
++ if (nentries == NULL)
++ return 0;
++ htab->entries = nentries;
++ htab->size = nsize;
++
++ p = oentries;
++ do {
++ if (*p)
++ *find_empty_slot_for_expand(htab, hash_fn(*p)) = *p;
++ p++;
++ } while (p < olimit);
++
++#if 0
++ /*
++ * We can't tell whether this was allocated by the _dl_malloc()
++ * built into ld.so or malloc() in the main executable or libc,
++ * and calling free() for something that wasn't malloc()ed could
++ * do Very Bad Things (TM). Take the conservative approach
++ * here, potentially wasting as much memory as actually used by
++ * the hash table, even if multiple growths occur. That's not
++ * so bad as to require some overengineered solution that would
++ * enable us to keep track of how it was allocated.
++ */
++ _dl_free(oentries);
++#endif
++ return 1;
++}
++
++/*
++ * This function searches for a hash table slot containing an entry
++ * equal to the given element. To delete an entry, call this with
++ * INSERT = 0, then call htab_clear_slot on the slot returned (possibly
++ * after doing some checks). To insert an entry, call this with
++ * INSERT = 1, then write the value you want into the returned slot.
++ * When inserting an entry, NULL may be returned if memory allocation
++ * fails.
++ */
++static __always_inline void **
++htab_find_slot(struct funcdesc_ht *htab, void *ptr, int insert,
++ int (*hash_fn)(void *), int (*eq_fn)(void *, void *))
++{
++ unsigned int index;
++ int hash, hash2;
++ size_t size;
++ void **entry;
++
++ if (htab->size * 3 <= htab->n_elements * 4 &&
++ htab_expand(htab, hash_fn) == 0)
++ return NULL;
++
++ hash = hash_fn(ptr);
++
++ size = htab->size;
++ index = hash % size;
++
++ entry = &htab->entries[index];
++ if (!*entry)
++ goto empty_entry;
++ else if (eq_fn(*entry, ptr))
++ return entry;
++
++ hash2 = 1 + hash % (size - 2);
++ for (;;) {
++ index += hash2;
++ if (index >= size)
++ index -= size;
++
++ entry = &htab->entries[index];
++ if (!*entry)
++ goto empty_entry;
++ else if (eq_fn(*entry, ptr))
++ return entry;
++ }
++
++ empty_entry:
++ if (!insert)
++ return NULL;
++
++ htab->n_elements++;
++ return entry;
++}
++
++#endif
+diff -Nur uClibc-git/ldso/include/ldsodefs.h uClibc-xtensa/ldso/include/ldsodefs.h
+--- uClibc-git/ldso/include/ldsodefs.h 2014-06-02 17:40:33.922711475 +0200
++++ uClibc-xtensa/ldso/include/ldsodefs.h 2014-06-03 16:10:51.175659505 +0200
+@@ -62,13 +62,18 @@
+
+ extern void _dl_allocate_static_tls (struct link_map *map)
+ internal_function attribute_hidden;
++extern int _dl_try_allocate_static_tls (struct link_map* map)
++ internal_function attribute_hidden;
+
+ /* Taken from glibc/elf/dl-reloc.c */
+ #define CHECK_STATIC_TLS(sym_map) \
+ do { \
+- if (unlikely((sym_map)->l_tls_offset == NO_TLS_OFFSET)) \
++ if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET, 0)) \
+ _dl_allocate_static_tls (sym_map); \
+ } while (0)
++#define TRY_STATIC_TLS(sym_map) \
++ (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \
++ || _dl_try_allocate_static_tls (sym_map) == 0)
+
+ /* These are internal entry points to the two halves of _dl_allocate_tls,
+ only used within rtld.c itself at startup time. */
+diff -Nur uClibc-git/ldso/include/tlsdeschtab.h uClibc-xtensa/ldso/include/tlsdeschtab.h
+--- uClibc-git/ldso/include/tlsdeschtab.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/ldso/include/tlsdeschtab.h 2014-06-03 14:58:29.681335708 +0200
+@@ -0,0 +1,119 @@
++/* Hash table for TLS descriptors.
++ Copyright (C) 2005-2013 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Alexandre Oliva <aoliva@redhat.com>
++
++ uClibc port by Baruch Siach <baruch@tkos.co.il>
++
++ 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/>. */
++
++#ifndef TLSDESCHTAB_H
++# define TLSDESCHTAB_H 1
++
++# ifdef SHARED
++
++# include <inline-hashtab.h>
++
++inline static int
++hash_tlsdesc (void *p)
++{
++ struct tlsdesc_dynamic_arg *td = p;
++
++ /* We know all entries are for the same module, so ti_offset is the
++ only distinguishing entry. */
++ return td->tlsinfo.ti_offset;
++}
++
++inline static int
++eq_tlsdesc (void *p, void *q)
++{
++ struct tlsdesc_dynamic_arg *tdp = p, *tdq = q;
++
++ return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset;
++}
++
++inline static int
++map_generation (struct link_map *map)
++{
++ size_t idx = map->l_tls_modid;
++ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
++
++ /* Find the place in the dtv slotinfo list. */
++ do
++ {
++ /* Does it fit in the array of this list element? */
++ if (idx < listp->len)
++ {
++ /* We should never get here for a module in static TLS, so
++ we can assume that, if the generation count is zero, we
++ still haven't determined the generation count for this
++ module. */
++ if (listp->slotinfo[idx].gen)
++ return listp->slotinfo[idx].gen;
++ else
++ break;
++ }
++ idx -= listp->len;
++ listp = listp->next;
++ }
++ while (listp != NULL);
++
++ /* If we get to this point, the module still hasn't been assigned an
++ entry in the dtv slotinfo data structures, and it will when we're
++ done with relocations. At that point, the module will get a
++ generation number that is one past the current generation, so
++ return exactly that. */
++ return GL(dl_tls_generation) + 1;
++}
++
++void *
++internal_function
++_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
++{
++ struct funcdesc_ht *ht;
++ void **entry;
++ struct tlsdesc_dynamic_arg *td, test;
++
++ ht = map->l_tlsdesc_table;
++ if (! ht)
++ {
++ ht = htab_create ();
++ if (! ht)
++ return 0;
++ map->l_tlsdesc_table = ht;
++ }
++
++ test.tlsinfo.ti_module = map->l_tls_modid;
++ test.tlsinfo.ti_offset = ti_offset;
++ entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc);
++ if (*entry)
++ {
++ td = *entry;
++ return td;
++ }
++
++ *entry = td = _dl_malloc (sizeof (struct tlsdesc_dynamic_arg));
++ /* This may be higher than the map's generation, but it doesn't
++ matter much. Worst case, we'll have one extra DTV update per
++ thread. */
++ td->gen_count = map_generation (map);
++ td->tlsinfo = test.tlsinfo;
++
++ return td;
++}
++
++# endif /* SHARED */
++
++#endif
+diff -Nur uClibc-git/ldso/ldso/dl-tls.c uClibc-xtensa/ldso/ldso/dl-tls.c
+--- uClibc-git/ldso/ldso/dl-tls.c 2014-06-02 17:40:33.946711608 +0200
++++ uClibc-xtensa/ldso/ldso/dl-tls.c 2014-06-03 16:10:28.547570023 +0200
+@@ -100,20 +100,16 @@
+ * the static TLS area already allocated for each running thread. If this
+ * object's TLS segment is too big to fit, we fail. If it fits,
+ * we set MAP->l_tls_offset and return.
+- * This function intentionally does not return any value but signals error
+- * directly, as static TLS should be rare and code handling it should
+- * not be inlined as much as possible.
+ */
+-void
+-internal_function __attribute_noinline__
+-_dl_allocate_static_tls (struct link_map *map)
++int
++internal_function
++_dl_try_allocate_static_tls (struct link_map* map)
+ {
+ /* If the alignment requirements are too high fail. */
+ if (map->l_tls_align > _dl_tls_static_align)
+ {
+ fail:
+- _dl_dprintf(2, "cannot allocate memory in static TLS block");
+- _dl_exit(30);
++ return -1;
+ }
+
+ # ifdef TLS_TCB_AT_TP
+@@ -169,6 +165,23 @@
+ }
+ else
+ map->l_need_tls_init = 1;
++
++ return 0;
++}
++
++/*
++ * This function intentionally does not return any value but signals error
++ * directly, as static TLS should be rare and code handling it should
++ * not be inlined as much as possible.
++ */
++void
++internal_function __attribute_noinline__
++_dl_allocate_static_tls (struct link_map *map)
++{
++ if (_dl_try_allocate_static_tls (map)) {
++ _dl_dprintf(2, "cannot allocate memory in static TLS block");
++ _dl_exit(30);
++ }
+ }
+
+ #ifdef SHARED
+diff -Nur uClibc-git/ldso/ldso/fdpic/dl-inlines.h uClibc-xtensa/ldso/ldso/fdpic/dl-inlines.h
+--- uClibc-git/ldso/ldso/fdpic/dl-inlines.h 2014-06-02 17:40:33.950711630 +0200
++++ uClibc-xtensa/ldso/ldso/fdpic/dl-inlines.h 2014-06-03 11:57:43.263058897 +0200
+@@ -5,6 +5,8 @@
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
++#include <inline-hashtab.h>
++
+ /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete load map. */
+ static __always_inline void
+ __dl_init_loadaddr_map(struct elf32_fdpic_loadaddr *loadaddr, Elf32_Addr dl_boot_got_pointer,
+@@ -143,269 +145,18 @@
+ return 0;
+ }
+
+-/*
+- * The hashcode handling code below is heavily inspired in libiberty's
+- * hashtab code, but with most adaptation points and support for
+- * deleting elements removed.
+- *
+- * Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+- * Contributed by Vladimir Makarov (vmakarov@cygnus.com).
+- */
+-static __always_inline unsigned long
+-higher_prime_number(unsigned long n)
+-{
+- /* These are primes that are near, but slightly smaller than, a power of two. */
+- static const unsigned long primes[] = {
+- 7,
+- 13,
+- 31,
+- 61,
+- 127,
+- 251,
+- 509,
+- 1021,
+- 2039,
+- 4093,
+- 8191,
+- 16381,
+- 32749,
+- 65521,
+- 131071,
+- 262139,
+- 524287,
+- 1048573,
+- 2097143,
+- 4194301,
+- 8388593,
+- 16777213,
+- 33554393,
+- 67108859,
+- 134217689,
+- 268435399,
+- 536870909,
+- 1073741789,
+- /* 4294967291 */
+- ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
+- };
+- const unsigned long *low = &primes[0];
+- const unsigned long *high = &primes[ARRAY_SIZE(primes)];
+-
+- while (low != high) {
+- const unsigned long *mid = low + (high - low) / 2;
+- if (n > *mid)
+- low = mid + 1;
+- else
+- high = mid;
+- }
+-
+-#if 0
+- /* If we've run out of primes, abort. */
+- if (n > *low) {
+- fprintf(stderr, "Cannot find prime bigger than %lu\n", n);
+- abort();
+- }
+-#endif
+-
+- return *low;
+-}
+-
+-struct funcdesc_ht
+-{
+- /* Table itself */
+- struct funcdesc_value **entries;
+-
+- /* Current size (in entries) of the hash table */
+- size_t size;
+-
+- /* Current number of elements */
+- size_t n_elements;
+-};
+-
+-static __always_inline int
+-hash_pointer(const void *p)
++static int
++hash_pointer(void *p)
+ {
+ return (int) ((long)p >> 3);
+ }
+
+-static __always_inline struct funcdesc_ht *
+-htab_create(void)
+-{
+- struct funcdesc_ht *ht = _dl_malloc(sizeof(*ht));
+- size_t ent_size;
+-
+- if (!ht)
+- return NULL;
+- ht->size = 3;
+- ent_size = sizeof(struct funcdesc_ht_value *) * ht->size;
+- ht->entries = _dl_malloc(ent_size);
+- if (!ht->entries)
+- return NULL;
+-
+- ht->n_elements = 0;
+- _dl_memset(ht->entries, 0, ent_size);
+-
+- return ht;
+-}
+-
+-/*
+- * This is only called from _dl_loadaddr_unmap, so it's safe to call
+- * _dl_free(). See the discussion below.
+- */
+-static __always_inline void
+-htab_delete(struct funcdesc_ht *htab)
+-{
+- size_t i;
+-
+- for (i = htab->size - 1; i >= 0; i--)
+- if (htab->entries[i])
+- _dl_free(htab->entries[i]);
+-
+- _dl_free(htab->entries);
+- _dl_free(htab);
+-}
+-
+-/*
+- * Similar to htab_find_slot, but without several unwanted side effects:
+- * - Does not call htab->eq_f when it finds an existing entry.
+- * - Does not change the count of elements/searches/collisions in the
+- * hash table.
+- * This function also assumes there are no deleted entries in the table.
+- * HASH is the hash value for the element to be inserted.
+- */
+-static __always_inline struct funcdesc_value **
+-find_empty_slot_for_expand(struct funcdesc_ht *htab, int hash)
++static int
++eq_pointer(void *p, void *q)
+ {
+- size_t size = htab->size;
+- unsigned int index = hash % size;
+- struct funcdesc_value **slot = htab->entries + index;
+- int hash2;
+-
+- if (!*slot)
+- return slot;
+-
+- hash2 = 1 + hash % (size - 2);
+- for (;;) {
+- index += hash2;
+- if (index >= size)
+- index -= size;
+-
+- slot = htab->entries + index;
+- if (!*slot)
+- return slot;
+- }
+-}
+-
+-/*
+- * The following function changes size of memory allocated for the
+- * entries and repeatedly inserts the table elements. The occupancy
+- * of the table after the call will be about 50%. Naturally the hash
+- * table must already exist. Remember also that the place of the
+- * table entries is changed. If memory allocation failures are allowed,
+- * this function will return zero, indicating that the table could not be
+- * expanded. If all goes well, it will return a non-zero value.
+- */
+-static __always_inline int
+-htab_expand(struct funcdesc_ht *htab)
+-{
+- struct funcdesc_value **oentries;
+- struct funcdesc_value **olimit;
+- struct funcdesc_value **p;
+- struct funcdesc_value **nentries;
+- size_t nsize;
+-
+- oentries = htab->entries;
+- olimit = oentries + htab->size;
+-
+- /*
+- * Resize only when table after removal of unused elements is either
+- * too full or too empty.
+- */
+- if (htab->n_elements * 2 > htab->size)
+- nsize = higher_prime_number(htab->n_elements * 2);
+- else
+- nsize = htab->size;
+-
+- nentries = _dl_malloc(sizeof(*nentries) * nsize);
+- _dl_memset(nentries, 0, sizeof(*nentries) * nsize);
+- if (nentries == NULL)
+- return 0;
+- htab->entries = nentries;
+- htab->size = nsize;
+-
+- p = oentries;
+- do {
+- if (*p)
+- *find_empty_slot_for_expand(htab, hash_pointer((*p)->entry_point)) = *p;
+- p++;
+- } while (p < olimit);
+-
+-#if 0
+- /*
+- * We can't tell whether this was allocated by the _dl_malloc()
+- * built into ld.so or malloc() in the main executable or libc,
+- * and calling free() for something that wasn't malloc()ed could
+- * do Very Bad Things (TM). Take the conservative approach
+- * here, potentially wasting as much memory as actually used by
+- * the hash table, even if multiple growths occur. That's not
+- * so bad as to require some overengineered solution that would
+- * enable us to keep track of how it was allocated.
+- */
+- _dl_free(oentries);
+-#endif
+- return 1;
+-}
+-
+-/*
+- * This function searches for a hash table slot containing an entry
+- * equal to the given element. To delete an entry, call this with
+- * INSERT = 0, then call htab_clear_slot on the slot returned (possibly
+- * after doing some checks). To insert an entry, call this with
+- * INSERT = 1, then write the value you want into the returned slot.
+- * When inserting an entry, NULL may be returned if memory allocation
+- * fails.
+- */
+-static __always_inline struct funcdesc_value **
+-htab_find_slot(struct funcdesc_ht *htab, void *ptr, int insert)
+-{
+- unsigned int index;
+- int hash, hash2;
+- size_t size;
+- struct funcdesc_value **entry;
+-
+- if (htab->size * 3 <= htab->n_elements * 4 &&
+- htab_expand(htab) == 0)
+- return NULL;
+-
+- hash = hash_pointer(ptr);
+-
+- size = htab->size;
+- index = hash % size;
+-
+- entry = &htab->entries[index];
+- if (!*entry)
+- goto empty_entry;
+- else if ((*entry)->entry_point == ptr)
+- return entry;
+-
+- hash2 = 1 + hash % (size - 2);
+- for (;;) {
+- index += hash2;
+- if (index >= size)
+- index -= size;
+-
+- entry = &htab->entries[index];
+- if (!*entry)
+- goto empty_entry;
+- else if ((*entry)->entry_point == ptr)
+- return entry;
+- }
+-
+- empty_entry:
+- if (!insert)
+- return NULL;
++ struct funcdesc_value *entry = p;
+
+- htab->n_elements++;
+- return entry;
++ return entry->entry_point == q;
+ }
+
+ void *
+@@ -424,7 +175,7 @@
+ tpnt->funcdesc_ht = ht;
+ }
+
+- entry = htab_find_slot(ht, entry_point, 1);
++ entry = htab_find_slot(ht, entry_point, 1, hash_pointer, eq_pointer);
+ if (*entry) {
+ _dl_assert((*entry)->entry_point == entry_point);
+ return _dl_stabilize_funcdesc(*entry);
+@@ -459,7 +210,8 @@
+ if (fd->got_value != rpnt->loadaddr.got_value)
+ continue;
+
+- address = htab_find_slot(rpnt->funcdesc_ht, (void *)fd->entry_point, 0);
++ address = htab_find_slot(rpnt->funcdesc_ht, (void *)fd->entry_point, 0,
++ hash_pointer, eq_pointer);
+
+ if (address && *(struct funcdesc_value *const*)address == fd) {
+ address = (*(struct funcdesc_value *const*)address)->entry_point;
+diff -Nur uClibc-git/ldso/ldso/xtensa/dl-debug.h uClibc-xtensa/ldso/ldso/xtensa/dl-debug.h
+--- uClibc-git/ldso/ldso/xtensa/dl-debug.h 2014-06-02 17:40:33.958711675 +0200
++++ uClibc-xtensa/ldso/ldso/xtensa/dl-debug.h 2014-06-03 12:22:20.032058866 +0200
+@@ -8,54 +8,31 @@
+
+ static const char * const _dl_reltypes_tab[] =
+ {
+- "R_XTENSA_NONE",
+- "R_XTENSA_32",
+- "R_XTENSA_RTLD",
+- "R_XTENSA_GLOB_DAT",
+- "R_XTENSA_JMP_SLOT",
+- "R_XTENSA_RELATIVE",
+- "R_XTENSA_PLT",
+- "R_XTENSA_UNUSED7",
+- "R_XTENSA_OP0",
+- "R_XTENSA_OP1",
+- "R_XTENSA_OP2",
+- "R_XTENSA_ASM_EXPAND",
+- "R_XTENSA_ASM_SIMPLIFY",
+- "R_XTENSA_UNUSED13",
+- "R_XTENSA_UNUSED14",
+- "R_XTENSA_GNU_VTINHERIT",
+- "R_XTENSA_GNU_VTENTRY",
+- "R_XTENSA_DIFF8",
+- "R_XTENSA_DIFF16",
+- "R_XTENSA_DIFF32",
+- "R_XTENSA_SLOT0_OP",
+- "R_XTENSA_SLOT1_OP",
+- "R_XTENSA_SLOT2_OP",
+- "R_XTENSA_SLOT3_OP",
+- "R_XTENSA_SLOT4_OP",
+- "R_XTENSA_SLOT5_OP",
+- "R_XTENSA_SLOT6_OP",
+- "R_XTENSA_SLOT7_OP",
+- "R_XTENSA_SLOT8_OP",
+- "R_XTENSA_SLOT9_OP",
+- "R_XTENSA_SLOT10_OP",
+- "R_XTENSA_SLOT11_OP",
+- "R_XTENSA_SLOT12_OP",
+- "R_XTENSA_SLOT13_OP",
+- "R_XTENSA_SLOT14_OP",
+- "R_XTENSA_SLOT0_ALT",
+- "R_XTENSA_SLOT1_ALT",
+- "R_XTENSA_SLOT2_ALT",
+- "R_XTENSA_SLOT3_ALT",
+- "R_XTENSA_SLOT4_ALT",
+- "R_XTENSA_SLOT5_ALT",
+- "R_XTENSA_SLOT6_ALT",
+- "R_XTENSA_SLOT7_ALT",
+- "R_XTENSA_SLOT8_ALT",
+- "R_XTENSA_SLOT9_ALT",
+- "R_XTENSA_SLOT10_ALT",
+- "R_XTENSA_SLOT11_ALT",
+- "R_XTENSA_SLOT12_ALT",
+- "R_XTENSA_SLOT13_ALT",
+- "R_XTENSA_SLOT14_ALT"
++ [0] "R_XTENSA_NONE", "R_XTENSA_32",
++ [2] "R_XTENSA_RTLD", "R_XTENSA_GLOB_DAT",
++ [4] "R_XTENSA_JMP_SLOT", "R_XTENSA_RELATIVE",
++ [6] "R_XTENSA_PLT", "R_XTENSA_UNUSED7",
++ [8] "R_XTENSA_OP0", "R_XTENSA_OP1",
++ [10] "R_XTENSA_OP2", "R_XTENSA_ASM_EXPAND",
++ [12] "R_XTENSA_ASM_SIMPLIFY", "R_XTENSA_UNUSED13",
++ [14] "R_XTENSA_UNUSED14", "R_XTENSA_GNU_VTINHERIT",
++ [16] "R_XTENSA_GNU_VTENTRY", "R_XTENSA_DIFF8",
++ [18] "R_XTENSA_DIFF16", "R_XTENSA_DIFF32",
++ [20] "R_XTENSA_SLOT0_OP", "R_XTENSA_SLOT1_OP",
++ [22] "R_XTENSA_SLOT2_OP", "R_XTENSA_SLOT3_OP",
++ [24] "R_XTENSA_SLOT4_OP", "R_XTENSA_SLOT5_OP",
++ [26] "R_XTENSA_SLOT6_OP", "R_XTENSA_SLOT7_OP",
++ [28] "R_XTENSA_SLOT8_OP", "R_XTENSA_SLOT9_OP",
++ [30] "R_XTENSA_SLOT10_OP", "R_XTENSA_SLOT11_OP",
++ [32] "R_XTENSA_SLOT12_OP", "R_XTENSA_SLOT13_OP",
++ [34] "R_XTENSA_SLOT14_OP", "R_XTENSA_SLOT0_ALT",
++ [36] "R_XTENSA_SLOT1_ALT", "R_XTENSA_SLOT2_ALT",
++ [38] "R_XTENSA_SLOT3_ALT", "R_XTENSA_SLOT4_ALT",
++ [40] "R_XTENSA_SLOT5_ALT", "R_XTENSA_SLOT6_ALT",
++ [42] "R_XTENSA_SLOT7_ALT", "R_XTENSA_SLOT8_ALT",
++ [44] "R_XTENSA_SLOT9_ALT", "R_XTENSA_SLOT10_ALT",
++ [46] "R_XTENSA_SLOT11_ALT", "R_XTENSA_SLOT12_ALT",
++ [48] "R_XTENSA_SLOT13_ALT", "R_XTENSA_SLOT14_ALT",
++ [50] "R_XTENSA_TLSDESC_FN", "R_XTENSA_TLSDESC_ARG",
++ [52] "R_XTENSA_TLS_TPOFF"
+ };
+diff -Nur uClibc-git/ldso/ldso/xtensa/dl-startup.h uClibc-xtensa/ldso/ldso/xtensa/dl-startup.h
+--- uClibc-git/ldso/ldso/xtensa/dl-startup.h 2014-06-02 17:40:33.958711675 +0200
++++ uClibc-xtensa/ldso/ldso/xtensa/dl-startup.h 2014-06-03 12:22:20.112059404 +0200
+@@ -11,7 +11,6 @@
+ __asm__ (
+ " .text\n"
+ " .align 4\n"
+- " .literal_position\n"
+ " .global _start\n"
+ " .type _start, @function\n"
+ " .hidden _start\n"
+diff -Nur uClibc-git/ldso/ldso/xtensa/dl-sysdep.h uClibc-xtensa/ldso/ldso/xtensa/dl-sysdep.h
+--- uClibc-git/ldso/ldso/xtensa/dl-sysdep.h 2014-06-02 17:40:33.958711675 +0200
++++ uClibc-xtensa/ldso/ldso/xtensa/dl-sysdep.h 2014-06-03 12:22:20.340060933 +0200
+@@ -78,10 +78,13 @@
+ struct elf_resolve;
+ extern unsigned long _dl_linux_resolver (struct elf_resolve *, int);
+
+-/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
+- undefined references should not be allowed to define the value. */
++/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
++ TLS variable, so undefined references should not be allowed to define
++ the value. */
+ #define elf_machine_type_class(type) \
+- (((type) == R_XTENSA_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)
++ (((type) == R_XTENSA_JMP_SLOT || (type) == R_XTENSA_TLS_TPOFF \
++ || (type) == R_XTENSA_TLSDESC_FN || (type) == R_XTENSA_TLSDESC_ARG) \
++ * ELF_RTYPE_CLASS_PLT)
+
+ /* Return the link-time address of _DYNAMIC. */
+ static __always_inline Elf32_Addr
+diff -Nur uClibc-git/ldso/ldso/xtensa/dl-tlsdesc.S uClibc-xtensa/ldso/ldso/xtensa/dl-tlsdesc.S
+--- uClibc-git/ldso/ldso/xtensa/dl-tlsdesc.S 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/ldso/ldso/xtensa/dl-tlsdesc.S 2014-06-03 12:22:20.340060933 +0200
+@@ -0,0 +1,96 @@
++/* Thread-local storage handling in the ELF dynamic linker. Xtensa version.
++ Copyright (C) 2012-2013 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 <tls.h>
++#include "tlsdesc.h"
++
++
++ .text
++ .align 4
++ .hidden _dl_tlsdesc_return
++ .global _dl_tlsdesc_return
++ .type _dl_tlsdesc_return, @function
++_dl_tlsdesc_return:
++ entry a1, 16
++ rur.threadptr a3
++ add a2, a2, a3
++ retw
++ .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
++
++#ifdef SHARED
++
++
++ /* This function is used for symbols that need dynamic TLS.
++
++ The argument passed to this function points to the TLS descriptor.
++
++ The assembly code that follows is a rendition of the following
++ C code, hand-optimized a little bit.
++
++ ptrdiff_t
++ _dl_tlsdesc_dynamic(struct tlsdesc_dynamic_arg *td)
++ {
++ dtv_t *dtv = (dtv_t *)THREAD_DTV();
++ if (td->gen_count <= dtv[0].counter
++ && dtv[td->tlsinfo.ti_module].pointer.val
++ != TLS_DTV_UNALLOCATED)
++ return dtv[td->tlsinfo.ti_module].pointer.val
++ + td->tlsinfo.ti_offset - __builtin_thread_pointer();
++ return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer();
++ }
++ */
++
++ .align 4
++ .hidden _dl_tlsdesc_dynamic
++ .global _dl_tlsdesc_dynamic
++ .type _dl_tlsdesc_dynamic, @function
++_dl_tlsdesc_dynamic:
++ entry a1, 32
++
++ /* dtv_t *dtv = (dtv_t *)THREAD_DTV(); */
++ rur.threadptr a3
++ l32i a4, a3, 0
++
++ /* if (td->gen_count <= dtv[0].counter */
++ l32i a6, a2, TLSDESC_GEN_COUNT
++ l32i a7, a4, 0
++ blt a7, a6, .Lslow
++
++ /* && dtv[td->tlsinfo.ti_module].pointer.val != TLS_DTV_UNALLOCATED) */
++ l32i a6, a2, TLSDESC_MODID
++ addx8 a6, a3, a6
++ l32i a6, a6, 0
++ beqi a6, -1, .Lslow
++
++ /* return dtv[td->tlsinfo.ti_module].pointer.val
++ + td->tlsinfo.ti_offset - __builtin_thread_pointer(); */
++ l32i a6, a2, TLSDESC_MODOFF
++ sub a2, a6, a3
++ retw
++
++ /* return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer(); */
++.Lslow:
++ mov a10, a2
++ movi a8, __tls_get_addr
++ callx8 a8
++ sub a2, a10, a3
++ retw
++ .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
++
++#endif /* SHARED */
+diff -Nur uClibc-git/ldso/ldso/xtensa/elfinterp.c uClibc-xtensa/ldso/ldso/xtensa/elfinterp.c
+--- uClibc-git/ldso/ldso/xtensa/elfinterp.c 2014-06-02 17:40:33.958711675 +0200
++++ uClibc-xtensa/ldso/ldso/xtensa/elfinterp.c 2014-06-03 12:22:20.340060933 +0200
+@@ -31,6 +31,8 @@
+ */
+
+ #include "ldso.h"
++#include "dl-tls.h"
++#include "tlsdeschtab.h"
+
+ unsigned long
+ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
+@@ -146,6 +148,9 @@
+ int reloc_type;
+ int symtab_index;
+ char *symname;
++#if defined USE_TLS && USE_TLS
++ struct elf_resolve *tls_tpnt = NULL;
++#endif
+ struct symbol_ref sym_ref;
+ ElfW(Addr) *reloc_addr;
+ ElfW(Addr) symbol_addr;
+@@ -172,15 +177,22 @@
+ * here, so all bases should be covered.
+ */
+ if (unlikely (!symbol_addr &&
++ ELF_ST_TYPE (sym_ref.sym->st_info) != STT_TLS &&
+ ELF_ST_BIND (sym_ref.sym->st_info) != STB_WEAK)) {
+- _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
+- _dl_progname, symname);
+- _dl_exit (1);
++ return 1;
+ }
+ if (_dl_trace_prelink) {
+ _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
+ &sym_ref, elf_machine_type_class(reloc_type));
+ }
++#if defined USE_TLS && USE_TLS
++ tls_tpnt = sym_ref.tpnt;
++#endif
++ } else {
++ symbol_addr =symtab[symtab_index].st_value;
++#if defined USE_TLS && USE_TLS
++ tls_tpnt = tpnt;
++#endif
+ }
+
+ #if defined (__SUPPORT_LD_DEBUG__)
+@@ -198,8 +210,8 @@
+
+ case R_XTENSA_RTLD:
+ if (rpnt->r_addend == 1) {
+- /* Grab the function pointer stashed at the beginning of the
+- GOT by the GOT_INIT function. */
++ /* Grab the function pointer stashed at the beginning
++ of the GOT by the GOT_INIT function. */
+ *reloc_addr = *(ElfW(Addr) *) tpnt->dynamic_info[DT_PLTGOT];
+ } else if (rpnt->r_addend == 2) {
+ /* Store the link map for the object. */
+@@ -213,6 +225,35 @@
+ *reloc_addr += tpnt->loadaddr + rpnt->r_addend;
+ break;
+
++#if defined USE_TLS && USE_TLS
++ case R_XTENSA_TLS_TPOFF:
++ CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
++ *reloc_addr = symbol_addr + tls_tpnt->l_tls_offset + rpnt->r_addend;
++ break;
++ case R_XTENSA_TLSDESC_FN:
++#ifndef SHARED
++ CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
++#else
++ if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt))
++ *reloc_addr = (ElfW(Addr)) _dl_tlsdesc_dynamic;
++ else
++#endif
++ *reloc_addr = (ElfW(Addr)) _dl_tlsdesc_return;
++ break;
++ case R_XTENSA_TLSDESC_ARG:
++#ifndef SHARED
++ CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
++#else
++ if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt))
++ *reloc_addr = (ElfW(Addr))
++ _dl_make_tlsdesc_dynamic((struct link_map *) tls_tpnt,
++ symbol_addr + *reloc_addr);
++ else
++#endif
++ *reloc_addr += symbol_addr + tls_tpnt->l_tls_offset;
++ break;
++#endif
++
+ default:
+ return -1; /* Calls _dl_exit(1). */
+ }
+diff -Nur uClibc-git/ldso/ldso/xtensa/resolve.S uClibc-xtensa/ldso/ldso/xtensa/resolve.S
+--- uClibc-git/ldso/ldso/xtensa/resolve.S 2014-06-02 17:40:33.958711675 +0200
++++ uClibc-xtensa/ldso/ldso/xtensa/resolve.S 2014-06-03 12:22:20.344060961 +0200
+@@ -27,7 +27,6 @@
+
+ .text
+ .align 4
+- .literal_position
+ .global _dl_linux_resolve
+ .type _dl_linux_resolve, @function
+ _dl_linux_resolve:
+diff -Nur uClibc-git/libc/sysdeps/linux/xtensa/clone.S uClibc-xtensa/libc/sysdeps/linux/xtensa/clone.S
+--- uClibc-git/libc/sysdeps/linux/xtensa/clone.S 2014-06-02 17:40:34.722715903 +0200
++++ uClibc-xtensa/libc/sysdeps/linux/xtensa/clone.S 2014-06-03 12:04:16.669187814 +0200
+@@ -1,34 +1,38 @@
+-/* Copyright (C) 2001, 2005, 2007 Free Software Foundation, Inc.
++/* Copyright (C) 2001, 2005 Free Software Foundation, Inc.
+
+ 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.
++ modify it under the terms of the GNU Library General Public License as
++ published by the Free Software Foundation; either version 2 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.
++ Library 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/>. */
++ You should have received a copy of the GNU Library General Public
++ License along with the GNU C Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA. */
+
+ /* clone is even more special than fork as it mucks with stacks
+- and invokes a function in the right context after it's all over. */
++ and invokes a function in the right context after its all over. */
+
+-#include "sysdep.h"
+-#include <sys/syscall.h>
++#include <features.h>
++#include <sysdep.h>
+ #define _ERRNO_H 1
+ #include <bits/errno.h>
+-
+-/* int clone (a2 = int (*fn)(void *arg),
+- a3 = void *child_stack,
+- a4 = int flags,
+- a5 = void *arg,
+- a6 = pid_t *ptid,
+- a7 = struct user_desc *tls,
+- 16(sp) = pid_t *ctid) */
++#ifdef RESET_PID
++#include <tls.h>
++#endif
++#define __ASSEMBLY__
++#include <linux/sched.h>
++
++/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
++ a2 a3 a4 a5
++ pid_t *ptid, struct user_desc *tls, pid_t *ctid)
++ a6 a7 16(sp)
++*/
+
+ .text
+ ENTRY (__clone)
+@@ -39,7 +43,7 @@
+
+ /* a2 and a3 are candidates for destruction by system-call return
+ parameters. We don't need the stack pointer after the system
+- call. We trust that the kernel will preserve a7, a9, and a6. */
++ call. We trust that the kernel will preserve a6, a7 and a9. */
+
+ mov a9, a5 /* save function argument */
+ mov a5, a7
+@@ -48,19 +52,18 @@
+ mov a6, a4
+ mov a4, a8
+ l32i a8, a1, 16 /* child_tid */
+- movi a2, SYS_ify (clone)
++ movi a2, SYS_ify(clone)
++
++ /* syscall(NR_clone,clone_flags, usp, parent_tid, child_tls, child_tid)
++ a2 a6 a3 a4 a5 a8
++ */
+
+- /* syscall (a2 = NR_clone,
+- a6 = clone_flags,
+- a3 = usp,
+- a4 = parent_tid,
+- a5 = child_tls,
+- a8 = child_tid) */
+ syscall
+ bltz a2, SYSCALL_ERROR_LABEL
+ beqz a2, .Lthread_start
+
+- /* Fall through for parent. */
++ /* fall through for parent */
++
+ .Lpseudo_end:
+ retw
+
+@@ -69,32 +72,38 @@
+ j SYSCALL_ERROR_LABEL
+
+ .Lthread_start:
+- /* Start child thread. */
+- movi a0, 0 /* terminate the stack frame */
++
++#if CLONE_THREAD != 0x00010000 || CLONE_VM != 0x00000100
++# error invalid values for CLONE_THREAD or CLONE_VM
++#endif
+
+ #ifdef RESET_PID
+- /* Check and see if we need to reset the PID. */
+- bbsi.l a6, 16, 1f /* CLONE_THREAD = 0x00010000 */
++ bbsi.l a6, 16, .Lskip_restore_pid /* CLONE_THREAD = 0x00010000 */
+ movi a2, -1
+- bbsi.l a6, 8, 2f /* CLONE_VM = 0x00000100 */
+- movi a2, SYS_ify (getpid)
++ bbsi a6, 8, .Lgotpid /* CLONE_VM = 0x00000100 */
++ movi a2, SYS_ify(getpid)
+ syscall
+-2: rur a3, THREADPTR
+- movi a4, PID_OFFSET
+- add a4, a4, a3
+- s32i a2, a4, 0
+- movi a4, TID_OFFSET
+- add a4, a4, a3
+- s32i a2, a3, 0
+-1:
+-#endif /* RESET_PID */
++.Lgotpid:
++ rur a3, threadptr
++ movi a0, TLS_PRE_TCB_SIZE
++ sub a3, a3, a0
++ s32i a2, a3, PID
++ s32i a2, a3, TID
++.Lskip_restore_pid:
++#endif
+
++ /* start child thread */
++ movi a0, 0 /* terminate the stack frame */
+ mov a6, a9 /* load up the 'arg' parameter */
+ callx4 a7 /* call the user's function */
+
+ /* Call _exit. Note that any return parameter from the user's
+- function in a6 is seen as inputs to _exit. */
+- movi a2, JUMPTARGET(_exit)
++ function in a6 is seen as inputs to _exit. */
++#ifdef PIC
++ movi a2, _exit@PLT
++#else
++ movi a2, _exit
++#endif
+ callx4 a2
+
+ PSEUDO_END (__clone)
+diff -Nur uClibc-git/libc/sysdeps/linux/xtensa/fork.c uClibc-xtensa/libc/sysdeps/linux/xtensa/fork.c
+--- uClibc-git/libc/sysdeps/linux/xtensa/fork.c 2014-06-02 17:40:34.726715926 +0200
++++ uClibc-xtensa/libc/sysdeps/linux/xtensa/fork.c 2014-06-03 12:04:16.669187814 +0200
+@@ -20,6 +20,10 @@
+ {
+ return (pid_t) INLINE_SYSCALL(clone, 2, SIGCHLD, 0);
+ }
+-lt_strong_alias(fork)
+-lt_libc_hidden(fork)
++# ifdef __UCLIBC_HAS_THREADS__
++strong_alias(fork,__libc_fork)
++libc_hidden_weak(fork)
++# else
++libc_hidden_def(fork)
++# endif
+ #endif
+diff -Nur uClibc-git/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h uClibc-xtensa/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h
+--- uClibc-git/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h 2014-06-02 17:40:34.726715926 +0200
++++ uClibc-xtensa/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h 2014-06-03 12:04:16.669187814 +0200
+@@ -1,25 +1,23 @@
+-/* Copyright (C) 1997, 1998, 2007 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/>. */
+-
+-/* Test if longjmp to JMPBUF would unwind the frame containing a local
+- variable at ADDRESS. */
+-
++/*
++ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
++ *
++ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
++ */
+ #include <setjmp.h>
+ #include <jmpbuf-offsets.h>
+
++/* Test if longjmp to JMPBUF would unwind the frame
++ containing a local variable at ADDRESS. */
+ #define _JMPBUF_UNWINDS(jmpbuf, address) \
+ ((void *) (address) < (void *) (jmpbuf)[JB_SP])
++
++#ifdef __UCLIBC_HAS_THREADS_NATIVE__
++#include <stdint.h>
++#include <unwind.h>
++
++#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
++ _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
++
++#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
++ ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj))
++#endif
+diff -Nur uClibc-git/libc/sysdeps/linux/xtensa/Makefile.arch uClibc-xtensa/libc/sysdeps/linux/xtensa/Makefile.arch
+--- uClibc-git/libc/sysdeps/linux/xtensa/Makefile.arch 2014-06-02 17:40:34.686715704 +0200
++++ uClibc-xtensa/libc/sysdeps/linux/xtensa/Makefile.arch 2014-06-03 12:04:16.669187814 +0200
+@@ -5,7 +5,10 @@
+ # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ #
+
+-CSRC-y := brk.c fork.c sigaction.c __syscall_error.c
++CSRC-y := brk.c sigaction.c __syscall_error.c
+
+ SSRC-y := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S \
+ sigrestorer.S syscall.S mmap.S windowspill.S __longjmp.S vfork.S
++
++CSRC-$(if $(UCLIBC_HAS_THREADS_NATIVE),,y) += fork.c
++SSRC-$(if $(UCLIBC_HAS_THREADS_NATIVE),,y) += clone.S
+diff -Nur uClibc-git/libc/sysdeps/linux/xtensa/sys/ptrace.h uClibc-xtensa/libc/sysdeps/linux/xtensa/sys/ptrace.h
+--- uClibc-git/libc/sysdeps/linux/xtensa/sys/ptrace.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libc/sysdeps/linux/xtensa/sys/ptrace.h 2014-06-03 11:58:41.563379928 +0200
+@@ -0,0 +1,155 @@
++/* `ptrace' debugger support interface. Linux version.
++ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007
++ 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/>. */
++
++#ifndef _SYS_PTRACE_H
++#define _SYS_PTRACE_H 1
++
++#include <features.h>
++
++/* Kludge away careless namespace pollution from the kernel. */
++
++#undef PTRACE_GETREGS
++#undef PTRACE_SETREGS
++#undef PTRACE_GETFPREGS
++#undef PTRACE_SETFPREGS
++#undef PTRACE_GETFPREGSIZE
++
++
++__BEGIN_DECLS
++
++/* Type of the REQUEST argument to `ptrace.' */
++enum __ptrace_request
++{
++ /* Indicate that the process making this request should be traced.
++ All signals received by this process can be intercepted by its
++ parent, and its parent can use the other `ptrace' requests. */
++ PTRACE_TRACEME = 0,
++#define PT_TRACE_ME PTRACE_TRACEME
++
++ /* Return the word in the process's text space at address ADDR. */
++ PTRACE_PEEKTEXT = 1,
++#define PT_READ_I PTRACE_PEEKTEXT
++
++ /* Return the word in the process's data space at address ADDR. */
++ PTRACE_PEEKDATA = 2,
++#define PT_READ_D PTRACE_PEEKDATA
++
++ /* Return the word in the process's user area at offset ADDR. */
++ PTRACE_PEEKUSER = 3,
++#define PT_READ_U PTRACE_PEEKUSER
++
++ /* Write the word DATA into the process's text space at address ADDR. */
++ PTRACE_POKETEXT = 4,
++#define PT_WRITE_I PTRACE_POKETEXT
++
++ /* Write the word DATA into the process's data space at address ADDR. */
++ PTRACE_POKEDATA = 5,
++#define PT_WRITE_D PTRACE_POKEDATA
++
++ /* Write the word DATA into the process's user area at offset ADDR. */
++ PTRACE_POKEUSER = 6,
++#define PT_WRITE_U PTRACE_POKEUSER
++
++ /* Continue the process. */
++ PTRACE_CONT = 7,
++#define PT_CONTINUE PTRACE_CONT
++
++ /* Kill the process. */
++ PTRACE_KILL = 8,
++#define PT_KILL PTRACE_KILL
++
++ /* Single step the process.
++ This is not supported on all machines. */
++ PTRACE_SINGLESTEP = 9,
++#define PT_STEP PTRACE_SINGLESTEP
++
++ /* Get all general purpose registers used by a processes.
++ This is not supported on all machines. */
++ PTRACE_GETREGS = 12,
++#define PT_GETREGS PTRACE_GETREGS
++
++ /* Set all general purpose registers used by a processes.
++ This is not supported on all machines. */
++ PTRACE_SETREGS = 13,
++#define PT_SETREGS PTRACE_SETREGS
++
++ /* Get all floating point registers used by a processes.
++ This is not supported on all machines. */
++ PTRACE_GETFPREGS = 14,
++#define PT_GETFPREGS PTRACE_GETFPREGS
++
++ /* Set all floating point registers used by a processes.
++ This is not supported on all machines. */
++ PTRACE_SETFPREGS = 15,
++#define PT_SETFPREGS PTRACE_SETFPREGS
++
++ /* Attach to a process that is already running. */
++ PTRACE_ATTACH = 16,
++#define PT_ATTACH PTRACE_ATTACH
++
++ /* Detach from a process attached to with PTRACE_ATTACH. */
++ PTRACE_DETACH = 17,
++#define PT_DETACH PTRACE_DETACH
++
++ /* Get size required for the buffer holding the floating point registers.
++ This is not supported on all machines. */
++ PTRACE_GETFPREGSIZE = 18,
++#define PT_GETFPREGSIZE PTRACE_GETFPREGSIZE
++
++ /* Continue and stop at the next (return from) syscall. */
++ PTRACE_SYSCALL = 24
++#define PT_SYSCALL PTRACE_SYSCALL
++};
++
++/* Options set using PTRACE_SETOPTIONS. */
++enum __ptrace_setoptions {
++ PTRACE_O_TRACESYSGOOD = 0x00000001,
++ PTRACE_O_TRACEFORK = 0x00000002,
++ PTRACE_O_TRACEVFORK = 0x00000004,
++ PTRACE_O_TRACECLONE = 0x00000008,
++ PTRACE_O_TRACEEXEC = 0x00000010,
++ PTRACE_O_TRACEVFORKDONE = 0x00000020,
++ PTRACE_O_TRACEEXIT = 0x00000040,
++ PTRACE_O_MASK = 0x0000007f
++};
++
++/* Wait extended result codes for the above trace options. */
++enum __ptrace_eventcodes {
++ PTRACE_EVENT_FORK = 1,
++ PTRACE_EVENT_VFORK = 2,
++ PTRACE_EVENT_CLONE = 3,
++ PTRACE_EVENT_EXEC = 4,
++ PTRACE_EVENT_VFORK_DONE = 5,
++ PTRACE_EVENT_EXIT = 6
++};
++
++/* Perform process tracing functions. REQUEST is one of the values
++ above, and determines the action to be taken.
++ For all requests except PTRACE_TRACEME, PID specifies the process to be
++ traced.
++
++ PID and the other arguments described above for the various requests should
++ appear (those that are used for the particular request) as:
++ pid_t PID, void *ADDR, int DATA, void *ADDR2
++ after REQUEST. */
++extern long int ptrace (enum __ptrace_request __request, ...) __THROW;
++
++__END_DECLS
++
++#endif /* _SYS_PTRACE_H */
+diff -Nur uClibc-git/libc/sysdeps/linux/xtensa/sysdep.h uClibc-xtensa/libc/sysdeps/linux/xtensa/sysdep.h
+--- uClibc-git/libc/sysdeps/linux/xtensa/sysdep.h 2014-06-02 17:40:34.726715926 +0200
++++ uClibc-xtensa/libc/sysdeps/linux/xtensa/sysdep.h 2014-06-03 15:24:57.308410770 +0200
+@@ -16,6 +16,10 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#ifndef _LINUX_XTENSA_SYSDEP_H
++#define _LINUX_XTENSA_SYSDEP_H 1
++
++#include <common/sysdep.h>
+ #include <sys/syscall.h>
+
+ #ifdef __ASSEMBLER__
+@@ -24,12 +28,6 @@
+ #define ASM_TYPE_DIRECTIVE(name, typearg) .type name, typearg
+ #define ASM_SIZE_DIRECTIVE(name) .size name, . - name
+
+-#ifdef __STDC__
+-#define C_LABEL(name) name :
+-#else
+-#define C_LABEL(name) name/**/:
+-#endif
+-
+ #define ENTRY(name) \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
+ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name), @function); \
+@@ -52,6 +50,15 @@
+ #undef END
+ #define END(name) ASM_SIZE_DIRECTIVE(name)
+
++/* Local label name for asm code. */
++#ifndef L
++# ifdef HAVE_ELF
++# define L(name) .L##name
++# else
++# define L(name) name
++# endif
++#endif
++
+ /* Define a macro for this directive so it can be removed in a few places. */
+ #define LITERAL_POSITION .literal_position
+
+@@ -123,19 +130,7 @@
+ #define PSEUDO_END_ERRVAL(name) \
+ END (name)
+
+-#undef ret_ERRVAL
+-#define ret_ERRVAL retw
+-
+-#if defined RTLD_PRIVATE_ERRNO
+-# define SYSCALL_ERROR_HANDLER \
+-0: movi a4, rtld_errno; \
+- neg a2, a2; \
+- s32i a2, a4, 0; \
+- movi a2, -1; \
+- j .Lpseudo_end;
+-
+-#elif defined _LIBC_REENTRANT
+-
++#if defined _LIBC_REENTRANT
+ # if defined USE___THREAD
+ # ifndef NOT_IN_libc
+ # define SYSCALL_ERROR_ERRNO __libc_errno
+@@ -170,3 +165,9 @@
+ #endif /* _LIBC_REENTRANT */
+
+ #endif /* __ASSEMBLER__ */
++
++/* Pointer mangling is not yet supported for Xtensa. */
++#define PTR_MANGLE(var) (void) (var)
++#define PTR_DEMANGLE(var) (void) (var)
++
++#endif /* _LINUX_XTENSA_SYSDEP_H */
+diff -Nur uClibc-git/libc/sysdeps/linux/xtensa/vfork.S uClibc-xtensa/libc/sysdeps/linux/xtensa/vfork.S
+--- uClibc-git/libc/sysdeps/linux/xtensa/vfork.S 2014-06-02 17:40:34.726715926 +0200
++++ uClibc-xtensa/libc/sysdeps/linux/xtensa/vfork.S 2014-06-03 12:04:16.669187814 +0200
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
++/* Copyright (C) 2005-2013 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
+@@ -19,72 +19,67 @@
+ #include <sys/syscall.h>
+ #define _SIGNAL_H
+ #include <bits/signum.h>
++#define __ASSEMBLY__
++#include <linux/sched.h>
+
+
+-/* Clone the calling process, but without copying the whole address space.
++/*
++ Clone the calling process, but without copying the whole address space.
+ The calling process is suspended until the new process exits or is
+ replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
+ and the process ID of the new process to the old process.
+
+ Note that it is important that we don't create a new stack frame for the
+- caller. */
++ caller.
+
+-
+-/* The following are defined in linux/sched.h, which unfortunately
+- is not safe for inclusion in an assembly file. */
+-#define CLONE_VM 0x00000100 /* set if VM shared between processes */
+-#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to
+- wake it up on mm_release */
++*/
+
+ #ifndef SAVE_PID
+-#define SAVE_PID
++#define SAVE_PID(a,b,c,d)
+ #endif
+-
+ #ifndef RESTORE_PID
+-#define RESTORE_PID
++#define RESTORE_PID(a,b,c)
++#endif
++#ifndef RESTORE_PID12
++#define RESTORE_PID12(a,b,c)
+ #endif
+
++/*
++ pid_t vfork(void);
++ Implemented as __clone_syscall(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)
++ */
+
+-/* pid_t vfork(void);
+- Implemented as __clone_syscall(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) */
+
+ HIDDEN_ENTRY (__vfork)
++ .literal .Ljumptable, 0, .L4, .L8, .L12
+
+- movi a6, .Ljumptable
+- extui a2, a0, 30, 2 /* call-size: call4/8/12 = 1/2/3 */
+- addx4 a4, a2, a6 /* find return address in jumptable */
+- l32i a4, a4, 0
+- add a4, a4, a6
+-
++ mov a3, a0 # move return address out of the way
++ movi a0, .Ljumptable
++ extui a2, a3, 30, 2 # call-size: call4/8/12 = 1/2/3
++ addx4 a0, a2, a0 # find return address in jumptable
+ slli a2, a2, 30
+- xor a3, a0, a2 /* remove call-size from return addr */
+- extui a5, a4, 30, 2 /* get high bits of jump target */
+- slli a5, a5, 30
+- or a3, a3, a5 /* stuff them into the return address */
+- xor a4, a4, a5 /* clear high bits of jump target */
+- or a0, a4, a2 /* create temporary return address */
+- retw /* "return" to .L4, .L8, or .L12 */
+-
+- .align 4
+-.Ljumptable:
+- .word 0
+- .word .L4 - .Ljumptable
+- .word .L8 - .Ljumptable
+- .word .L12 - .Ljumptable
++ l32i a0, a0, 0
++
++ xor a3, a3, a2 # remove call-size from return address
++ or a0, a0, a2 # create temporary return address
++ retw
+
+ /* a7: return address */
++
+ .L4: mov a12, a2
+ mov a13, a3
+
+- SAVE_PID
++ SAVE_PID(a5,a15,a2,a3)
+
+- /* Use syscall 'clone'. Set new stack pointer to the same address. */
+- movi a2, SYS_ify (clone)
++ /* use syscall 'clone' and set new stack pointer to the same address */
++
++ movi a2, SYS_ify(clone)
+ movi a3, 0
+ movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD
++
+ syscall
+
+- RESTORE_PID
++ RESTORE_PID(a5,a15,a2)
+
+ movi a5, -4096
+
+@@ -94,22 +89,24 @@
+
+ bgeu a6, a5, 1f
+ jx a7
+-1: call4 .Lerr /* returns to original caller */
+
++1: call4 .Lerr
+
+ /* a11: return address */
++
+ .L8: mov a12, a2
+ mov a13, a3
+ mov a14, a6
+
+- SAVE_PID
++ SAVE_PID(a9,a15,a2,a3)
+
+- movi a2, SYS_ify (clone)
++ movi a2, SYS_ify(clone)
+ movi a3, 0
+ movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD
++
+ syscall
+
+- RESTORE_PID
++ RESTORE_PID(a9,a15,a2)
+
+ movi a9, -4096
+
+@@ -120,22 +117,25 @@
+
+ bgeu a10, a9, 1f
+ jx a11
+-1: call8 .Lerr /* returns to original caller */
++
++1: call8 .Lerr
+
+
+ /* a15: return address */
++
+ .L12: mov a12, a2
+ mov a13, a3
+ mov a14, a6
+
+- SAVE_PID
++ SAVE_PID (a2,a3,a2,a6)
+
+- movi a2, SYS_ify (clone)
++ movi a2, SYS_ify(clone)
+ movi a3, 0
+ movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD
++
+ syscall
+
+- RESTORE_PID
++ RESTORE_PID12(a3,a6,a15)
+
+ mov a3, a13
+ movi a13, -4096
+@@ -147,18 +147,18 @@
+
+ bgeu a14, a13, 1f
+ jx a15
+-1: call12 .Lerr /* returns to original caller */
+
++1: call12 .Lerr
+
+ .align 4
++
+ .Lerr: entry a1, 16
+
+- /* Restore the return address. */
+- extui a4, a0, 30, 2 /* get the call-size bits */
++ /* Restore return address */
++
++ extui a4, a0, 30, 2
+ slli a4, a4, 30
+- slli a3, a3, 2 /* clear high bits of target address */
+- srli a3, a3, 2
+- or a0, a3, a4 /* combine them */
++ or a0, a3, a4
+
+ PSEUDO_END (__vfork)
+ .Lpseudo_end:
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c 2014-06-02 17:40:35.102718006 +0200
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c 2014-06-03 12:35:45.097932730 +0200
+@@ -22,8 +22,6 @@
+ #include <lowlevellock.h>
+ #include <sys/time.h>
+ #include <tls.h>
+-#include <tcb-offsets.h>
+-
+
+ void
+ __lll_lock_wait_private (int *futex)
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/pthreadtypes.h uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/pthreadtypes.h
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/pthreadtypes.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/pthreadtypes.h 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,184 @@
++/* Copyright (C) 2002-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/>. */
++
++#ifndef _BITS_PTHREADTYPES_H
++#define _BITS_PTHREADTYPES_H 1
++
++#include <endian.h>
++
++#define __SIZEOF_PTHREAD_ATTR_T 36
++#define __SIZEOF_PTHREAD_MUTEX_T 24
++#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
++#define __SIZEOF_PTHREAD_COND_T 48
++#define __SIZEOF_PTHREAD_COND_COMPAT_T 12
++#define __SIZEOF_PTHREAD_CONDATTR_T 4
++#define __SIZEOF_PTHREAD_RWLOCK_T 32
++#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
++#define __SIZEOF_PTHREAD_BARRIER_T 20
++#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
++
++
++/* Thread identifiers. The structure of the attribute type is not
++ exposed on purpose. */
++typedef unsigned long int pthread_t;
++
++
++union pthread_attr_t
++{
++ char __size[__SIZEOF_PTHREAD_ATTR_T];
++ long int __align;
++};
++#ifndef __have_pthread_attr_t
++typedef union pthread_attr_t pthread_attr_t;
++# define __have_pthread_attr_t 1
++#endif
++
++
++typedef struct __pthread_internal_slist
++{
++ struct __pthread_internal_slist *__next;
++} __pthread_slist_t;
++
++
++/* Data structures for mutex handling. The structure of the attribute
++ type is not exposed on purpose. */
++typedef union
++{
++ struct __pthread_mutex_s
++ {
++ int __lock;
++ unsigned int __count;
++ int __owner;
++ /* KIND must stay at this position in the structure to maintain
++ binary compatibility. */
++ int __kind;
++ unsigned int __nusers;
++ __extension__ union
++ {
++ int __spins;
++ __pthread_slist_t __list;
++ };
++ } __data;
++ char __size[__SIZEOF_PTHREAD_MUTEX_T];
++ long int __align;
++} pthread_mutex_t;
++
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
++ long int __align;
++} pthread_mutexattr_t;
++
++
++/* Data structure for conditional variable handling. The structure of
++ the attribute type is not exposed on purpose. */
++typedef union
++{
++ struct
++ {
++ int __lock;
++ unsigned int __futex;
++ __extension__ unsigned long long int __total_seq;
++ __extension__ unsigned long long int __wakeup_seq;
++ __extension__ unsigned long long int __woken_seq;
++ void *__mutex;
++ unsigned int __nwaiters;
++ unsigned int __broadcast_seq;
++ } __data;
++ char __size[__SIZEOF_PTHREAD_COND_T];
++ __extension__ long long int __align;
++} pthread_cond_t;
++
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_CONDATTR_T];
++ long int __align;
++} pthread_condattr_t;
++
++
++/* Keys for thread-specific data */
++typedef unsigned int pthread_key_t;
++
++
++/* Once-only execution */
++typedef int pthread_once_t;
++
++
++#if defined __USE_UNIX98 || defined __USE_XOPEN2K
++/* Data structure for read-write lock variable handling. The
++ structure of the attribute type is not exposed on purpose. */
++typedef union
++{
++ struct
++ {
++ int __lock;
++ unsigned int __nr_readers;
++ unsigned int __readers_wakeup;
++ unsigned int __writer_wakeup;
++ unsigned int __nr_readers_queued;
++ unsigned int __nr_writers_queued;
++#if __BYTE_ORDER == __BIG_ENDIAN
++ unsigned char __pad1;
++ unsigned char __pad2;
++ unsigned char __shared;
++ /* FLAGS must stay at this position in the structure to maintain
++ binary compatibility. */
++ unsigned char __flags;
++#else
++ /* FLAGS must stay at this position in the structure to maintain
++ binary compatibility. */
++ unsigned char __flags;
++ unsigned char __shared;
++ unsigned char __pad1;
++ unsigned char __pad2;
++#endif
++ int __writer;
++ } __data;
++ char __size[__SIZEOF_PTHREAD_RWLOCK_T];
++ long int __align;
++} pthread_rwlock_t;
++
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
++ long int __align;
++} pthread_rwlockattr_t;
++#endif
++
++
++#ifdef __USE_XOPEN2K
++/* POSIX spinlock data type. */
++typedef volatile int pthread_spinlock_t;
++
++
++/* POSIX barriers data type. The structure of the type is
++ deliberately not exposed. */
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_BARRIER_T];
++ long int __align;
++} pthread_barrier_t;
++
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
++ int __align;
++} pthread_barrierattr_t;
++#endif
++
++
++#endif /* bits/pthreadtypes.h */
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/semaphore.h uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/semaphore.h
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/semaphore.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/semaphore.h 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,35 @@
++/* 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _SEMAPHORE_H
++# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
++#endif
++
++
++#define __SIZEOF_SEM_T 16
++
++
++/* Value returned if `sem_open' failed. */
++#define SEM_FAILED ((sem_t *) 0)
++
++
++typedef union
++{
++ char __size[__SIZEOF_SEM_T];
++ long int __align;
++} sem_t;
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/clone.S uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/clone.S
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/clone.S 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/clone.S 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,3 @@
++#define RESET_PID
++#include <tcb-offsets.h>
++#include <libc/sysdeps/linux/xtensa/clone.S>
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/createthread.c uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/createthread.c
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/createthread.c 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/createthread.c 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,24 @@
++/* 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* Value passed to 'clone' for initialization of the thread register. */
++#define TLS_VALUE (pd + 1)
++
++
++/* Get the real implementation. */
++#include <sysdeps/pthread/createthread.c>
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/fork.c uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/fork.c
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/fork.c 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/fork.c 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,29 @@
++/* Copyright (C) 2013 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 <sched.h>
++#include <signal.h>
++#include <sysdep.h>
++#include <tls.h>
++
++
++#define ARCH_FORK() \
++ INLINE_SYSCALL (clone, 5, \
++ CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \
++ NULL, NULL, &THREAD_SELF->tid)
++
++#include "../fork.c"
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.c uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.c
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.c 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.c 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,132 @@
++/* low level locking for pthread library. Generic futex-using version.
++ Copyright (C) 2003-2013 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 <errno.h>
++#include <sysdep.h>
++#include <lowlevellock.h>
++#include <sys/time.h>
++
++void
++__lll_lock_wait_private (int *futex)
++{
++ do
++ {
++ int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1);
++ if (oldval != 0)
++ lll_futex_wait (futex, 2, LLL_PRIVATE);
++ }
++ while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0);
++}
++
++
++/* These functions don't get included in libc.so */
++#ifdef IS_IN_libpthread
++void
++__lll_lock_wait (int *futex, int private)
++{
++ do
++ {
++ int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1);
++ if (oldval != 0)
++ lll_futex_wait (futex, 2, private);
++ }
++ while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0);
++}
++
++
++int
++__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private)
++{
++ struct timespec rt;
++
++ /* Reject invalid timeouts. */
++ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
++ return EINVAL;
++
++ /* Upgrade the lock. */
++ if (atomic_exchange_acq (futex, 2) == 0)
++ return 0;
++
++ do
++ {
++ struct timeval tv;
++
++ /* Get the current time. */
++ (void) __gettimeofday (&tv, NULL);
++
++ /* Compute relative timeout. */
++ rt.tv_sec = abstime->tv_sec - tv.tv_sec;
++ rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
++ if (rt.tv_nsec < 0)
++ {
++ rt.tv_nsec += 1000000000;
++ --rt.tv_sec;
++ }
++
++ /* Already timed out? */
++ if (rt.tv_sec < 0)
++ return ETIMEDOUT;
++
++ // XYZ: Lost the lock to check whether it was private.
++ lll_futex_timed_wait (futex, 2, &rt, private);
++ }
++ while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0);
++
++ return 0;
++}
++
++
++int
++__lll_timedwait_tid (int *tidp, const struct timespec *abstime)
++{
++ int tid;
++
++ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
++ return EINVAL;
++
++ /* Repeat until thread terminated. */
++ while ((tid = *tidp) != 0)
++ {
++ struct timeval tv;
++ struct timespec rt;
++
++ /* Get the current time. */
++ (void) __gettimeofday (&tv, NULL);
++
++ /* Compute relative timeout. */
++ rt.tv_sec = abstime->tv_sec - tv.tv_sec;
++ rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
++ if (rt.tv_nsec < 0)
++ {
++ rt.tv_nsec += 1000000000;
++ --rt.tv_sec;
++ }
++
++ /* Already timed out? */
++ if (rt.tv_sec < 0)
++ return ETIMEDOUT;
++
++ /* Wait until thread terminates. */
++ // XYZ: Lost the lock to check whether it was private.
++ if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT)
++ return ETIMEDOUT;
++ }
++
++ return 0;
++}
++#endif
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.h uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.h
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.h 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,293 @@
++/* Copyright (C) 2005-2013 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/>. */
++
++#ifndef _LOWLEVELLOCK_H
++#define _LOWLEVELLOCK_H 1
++
++#include <time.h>
++#include <sys/param.h>
++#include <bits/pthreadtypes.h>
++#include <atomic.h>
++#include <sysdep.h>
++#include <bits/kernel-features.h>
++
++#define FUTEX_WAIT 0
++#define FUTEX_WAKE 1
++#define FUTEX_REQUEUE 3
++#define FUTEX_CMP_REQUEUE 4
++#define FUTEX_WAKE_OP 5
++#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1)
++#define FUTEX_LOCK_PI 6
++#define FUTEX_UNLOCK_PI 7
++#define FUTEX_TRYLOCK_PI 8
++#define FUTEX_WAIT_BITSET 9
++#define FUTEX_WAKE_BITSET 10
++#define FUTEX_PRIVATE_FLAG 128
++#define FUTEX_CLOCK_REALTIME 256
++
++#define FUTEX_BITSET_MATCH_ANY 0xffffffff
++
++/* Values for 'private' parameter of locking macros. Yes, the
++ definition seems to be backwards. But it is not. The bit will be
++ reversed before passing to the system call. */
++#define LLL_PRIVATE 0
++#define LLL_SHARED FUTEX_PRIVATE_FLAG
++
++
++#if !defined NOT_IN_libc || defined IS_IN_rtld
++/* In libc.so or ld.so all futexes are private. */
++# ifdef __ASSUME_PRIVATE_FUTEX
++# define __lll_private_flag(fl, private) \
++ ((fl) | FUTEX_PRIVATE_FLAG)
++# else
++# define __lll_private_flag(fl, private) \
++ ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
++# endif
++#else
++# ifdef __ASSUME_PRIVATE_FUTEX
++# define __lll_private_flag(fl, private) \
++ (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
++# else
++# define __lll_private_flag(fl, private) \
++ (__builtin_constant_p (private) \
++ ? ((private) == 0 \
++ ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \
++ : (fl)) \
++ : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \
++ & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
++# endif
++#endif
++
++
++#define lll_futex_wait(futexp, val, private) \
++ lll_futex_timed_wait(futexp, val, NULL, private)
++
++#define lll_futex_timed_wait(futexp, val, timespec, private) \
++ ({ \
++ INTERNAL_SYSCALL_DECL (__err); \
++ long int __ret; \
++ __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
++ __lll_private_flag (FUTEX_WAIT, private), \
++ (val), (timespec)); \
++ __ret; \
++ })
++
++#define lll_futex_timed_wait_bitset(futexp, val, timespec, clockbit, private) \
++ ({ \
++ INTERNAL_SYSCALL_DECL (__err); \
++ long int __ret; \
++ int __op = FUTEX_WAIT_BITSET | clockbit; \
++ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
++ __lll_private_flag (__op, private), \
++ (val), (timespec), NULL /* Unused. */, \
++ FUTEX_BITSET_MATCH_ANY); \
++ __ret; \
++ })
++
++#define lll_futex_wake(futexp, nr, private) \
++ ({ \
++ INTERNAL_SYSCALL_DECL (__err); \
++ long int __ret; \
++ __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
++ __lll_private_flag (FUTEX_WAKE, private), \
++ (nr), 0); \
++ __ret; \
++ })
++
++#define lll_robust_dead(futexv, private) \
++ do \
++ { \
++ int *__futexp = &(futexv); \
++ atomic_or (__futexp, FUTEX_OWNER_DIED); \
++ lll_futex_wake (__futexp, 1, private); \
++ } \
++ while (0)
++
++/* Returns non-zero if error happened, zero if success. */
++#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
++ ({ \
++ INTERNAL_SYSCALL_DECL (__err); \
++ long int __ret; \
++ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
++ __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
++ (nr_wake), (nr_move), (mutex), (val)); \
++ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
++ })
++
++
++/* Returns non-zero if error happened, zero if success. */
++#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
++ ({ \
++ INTERNAL_SYSCALL_DECL (__err); \
++ long int __ret; \
++ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
++ __lll_private_flag (FUTEX_WAKE_OP, private), \
++ (nr_wake), (nr_wake2), (futexp2), \
++ FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \
++ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
++ })
++
++
++#define lll_trylock(lock) \
++ atomic_compare_and_exchange_val_acq(&(lock), 1, 0)
++
++#define lll_cond_trylock(lock) \
++ atomic_compare_and_exchange_val_acq(&(lock), 2, 0)
++
++#define __lll_robust_trylock(futex, id) \
++ (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0)
++#define lll_robust_trylock(lock, id) \
++ __lll_robust_trylock (&(lock), id)
++
++extern void __lll_lock_wait_private (int *futex) attribute_hidden;
++extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
++extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
++
++#define __lll_lock(futex, private) \
++ ((void) ({ \
++ int *__futex = (futex); \
++ if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, \
++ 1, 0), 0)) \
++ { \
++ if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
++ __lll_lock_wait_private (__futex); \
++ else \
++ __lll_lock_wait (__futex, private); \
++ } \
++ }))
++#define lll_lock(futex, private) __lll_lock (&(futex), private)
++
++
++#define __lll_robust_lock(futex, id, private) \
++ ({ \
++ int *__futex = (futex); \
++ int __val = 0; \
++ \
++ if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id, \
++ 0), 0)) \
++ __val = __lll_robust_lock_wait (__futex, private); \
++ __val; \
++ })
++#define lll_robust_lock(futex, id, private) \
++ __lll_robust_lock (&(futex), id, private)
++
++
++#define __lll_cond_lock(futex, private) \
++ ((void) ({ \
++ int *__futex = (futex); \
++ if (__builtin_expect (atomic_exchange_acq (__futex, 2), 0)) \
++ __lll_lock_wait (__futex, private); \
++ }))
++#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
++
++
++#define lll_robust_cond_lock(futex, id, private) \
++ __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
++
++
++extern int __lll_timedlock_wait (int *futex, const struct timespec *,
++ int private) attribute_hidden;
++extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
++ int private) attribute_hidden;
++
++#define __lll_timedlock(futex, abstime, private) \
++ ({ \
++ int *__futex = (futex); \
++ int __val = 0; \
++ \
++ if (__builtin_expect (atomic_exchange_acq (__futex, 1), 0)) \
++ __val = __lll_timedlock_wait (__futex, abstime, private); \
++ __val; \
++ })
++#define lll_timedlock(futex, abstime, private) \
++ __lll_timedlock (&(futex), abstime, private)
++
++
++#define __lll_robust_timedlock(futex, abstime, id, private) \
++ ({ \
++ int *__futex = (futex); \
++ int __val = 0; \
++ \
++ if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id, \
++ 0), 0)) \
++ __val = __lll_robust_timedlock_wait (__futex, abstime, private); \
++ __val; \
++ })
++#define lll_robust_timedlock(futex, abstime, id, private) \
++ __lll_robust_timedlock (&(futex), abstime, id, private)
++
++
++#define __lll_unlock(futex, private) \
++ (void) \
++ ({ int *__futex = (futex); \
++ int __oldval = atomic_exchange_rel (__futex, 0); \
++ if (__builtin_expect (__oldval > 1, 0)) \
++ lll_futex_wake (__futex, 1, private); \
++ })
++#define lll_unlock(futex, private) __lll_unlock(&(futex), private)
++
++
++#define __lll_robust_unlock(futex, private) \
++ (void) \
++ ({ int *__futex = (futex); \
++ int __oldval = atomic_exchange_rel (__futex, 0); \
++ if (__builtin_expect (__oldval & FUTEX_WAITERS, 0)) \
++ lll_futex_wake (__futex, 1, private); \
++ })
++#define lll_robust_unlock(futex, private) \
++ __lll_robust_unlock(&(futex), private)
++
++
++#define lll_islocked(futex) \
++ (futex != 0)
++
++
++/* Our internal lock implementation is identical to the binary-compatible
++ mutex implementation. */
++
++/* Initializers for lock. */
++#define LLL_LOCK_INITIALIZER (0)
++#define LLL_LOCK_INITIALIZER_LOCKED (1)
++
++/* The states of a lock are:
++ 0 - untaken
++ 1 - taken by one user
++ >1 - taken by more users */
++
++/* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex
++ wakeup when the clone terminates. The memory location contains the
++ thread ID while the clone is running and is reset to zero
++ afterwards. */
++#define lll_wait_tid(tid) \
++ do { \
++ __typeof (tid) __tid; \
++ while ((__tid = (tid)) != 0) \
++ lll_futex_wait (&(tid), __tid, LLL_SHARED);\
++ } while (0)
++
++extern int __lll_timedwait_tid (int *, const struct timespec *)
++ attribute_hidden;
++
++#define lll_timedwait_tid(tid, abstime) \
++ ({ \
++ int __res = 0; \
++ if ((tid) != 0) \
++ __res = __lll_timedwait_tid (&(tid), (abstime)); \
++ __res; \
++ })
++
++#endif /* lowlevellock.h */
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,17 @@
++# Makefile for uClibc NPTL
++#
++# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
++#
++
++libc_linux_arch_CSRC = fork.c
++libc_linux_arch_SSRC = clone.S vfork.S
++libpthread_linux_arch_CSRC = pthread_once.c
++libpthread_linux_arch_SSRC = pt-vfork.S
++
++CFLAGS-OMIT-fork.c = -DNOT_IN_libc -DIS_IN_libpthread
++ASFLAGS-pt-vfork.S = -DNOT_IN_libc -DIS_IN_libpthread -D_LIBC_REENTRANT
++
++ASFLAGS-clone.S = -D_LIBC_REENTRANT
++ASFLAGS-vfork.S = -D_LIBC_REENTRANT
++ASFLAGS-syscall.S = -D_LIBC_REENTRANT
++ASFLAGS-mmap.S = -D_LIBC_REENTRANT
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pthread_once.c uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pthread_once.c
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pthread_once.c 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pthread_once.c 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,89 @@
++/* Copyright (C) 2004-2013 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 "pthreadP.h"
++#include <lowlevellock.h>
++
++unsigned long int __fork_generation attribute_hidden;
++
++static void
++clear_once_control (void *arg)
++{
++ pthread_once_t *once_control = (pthread_once_t *) arg;
++
++ *once_control = 0;
++ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
++}
++
++int
++__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
++{
++ for (;;)
++ {
++ int oldval;
++ int newval;
++
++ /* Pseudo code:
++ newval = __fork_generation | 1;
++ oldval = *once_control;
++ if ((oldval & 2) == 0)
++ *once_control = newval;
++ Do this atomically.
++ */
++ do
++ {
++ newval = __fork_generation | 1;
++ oldval = *once_control;
++ if (oldval & 2)
++ break;
++ } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval);
++
++ /* Check if the initializer has already been done. */
++ if ((oldval & 2) != 0)
++ return 0;
++
++ /* Check if another thread already runs the initializer. */
++ if ((oldval & 1) == 0)
++ break;
++
++ /* Check whether the initializer execution was interrupted by a fork. */
++ if (oldval != newval)
++ break;
++
++ /* Same generation, some other thread was faster. Wait. */
++ lll_futex_wait (once_control, oldval, LLL_PRIVATE);
++ }
++
++ /* This thread is the first here. Do the initialization.
++ Register a cleanup handler so that in case the thread gets
++ interrupted the initialization can be restarted. */
++ pthread_cleanup_push (clear_once_control, once_control);
++
++ init_routine ();
++
++ pthread_cleanup_pop (0);
++
++ /* Say that the initialisation is done. */
++ *once_control = __fork_generation | 2;
++
++ /* Wake up all other threads. */
++ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
++
++ return 0;
++}
++weak_alias (__pthread_once, pthread_once)
++strong_alias (__pthread_once, __pthread_once_internal)
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-initfini.c uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-initfini.c
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-initfini.c 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-initfini.c 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,134 @@
++/* Special .init and .fini section support. Linuxthread version.
++ Copyright (C) 1995,1996,1997,2000,2001,2002 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 of the License, or (at your option) any later version.
++
++ In addition to the permissions in the GNU Lesser General Public
++ License, the Free Software Foundation gives you unlimited
++ permission to link the compiled version of this file with other
++ programs, and to distribute those programs without any restriction
++ coming from the use of this file. (The Library General Public
++ License restrictions do apply in other respects; for example, they
++ cover modification of the file, and distribution when not linked
++ into another program.)
++
++ 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; see the file COPYING.LIB. If not,
++ see <http://www.gnu.org/licenses/>. */
++
++/* This file is compiled into assembly code which is then munged by a sed
++ script into two files: crti.s and crtn.s.
++
++ * crti.s puts a function prologue at the beginning of the
++ .init and .fini sections and defines global symbols for
++ those addresses, so they can be called as functions.
++
++ * crtn.s puts the corresponding function epilogues
++ in the .init and .fini sections. */
++
++#include <stdlib.h>
++
++/* We use embedded asm for .section unconditionally, as this makes it
++ easier to insert the necessary directives into crtn.S. */
++#define SECTION(x) __asm__ (".section " x )
++
++/* Embed an #include to pull in the alignment and .end directives. */
++__asm__ ("\n#include \"defs.h\"");
++__asm__ ("\n#if defined __i686 && defined __ASSEMBLER__");
++__asm__ ("\n#undef __i686");
++__asm__ ("\n#define __i686 __i686");
++__asm__ ("\n#endif");
++
++/* The initial common code ends here. */
++__asm__ ("\n/*@HEADER_ENDS*/");
++
++/* To determine whether we need .end and .align: */
++__asm__ ("\n/*@TESTS_BEGIN*/");
++extern void dummy (void (*foo) (void));
++void
++dummy (void (*foo) (void))
++{
++ if (foo)
++ (*foo) ();
++}
++__asm__ ("\n/*@TESTS_END*/");
++
++/* The beginning of _init: */
++__asm__ ("\n/*@_init_PROLOG_BEGINS*/");
++
++static void
++call_initialize_minimal (void)
++{
++ extern void __pthread_initialize_minimal_internal (void)
++ __attribute ((visibility ("hidden")));
++
++ __pthread_initialize_minimal_internal ();
++}
++
++SECTION (".init");
++extern void __attribute__ ((section (".init"))) _init (void);
++void
++_init (void)
++{
++ /* The very first thing we must do is to set up the registers. */
++ call_initialize_minimal ();
++
++ __asm__ ("ALIGN");
++ __asm__("END_INIT");
++ /* Now the epilog. */
++ __asm__ ("\n/*@_init_PROLOG_ENDS*/");
++ __asm__ ("\n/*@_init_EPILOG_BEGINS*/");
++ SECTION(".init");
++}
++__asm__ ("END_INIT");
++
++/* End of the _init epilog, beginning of the _fini prolog. */
++__asm__ ("\n/*@_init_EPILOG_ENDS*/");
++__asm__ ("\n/*@_fini_PROLOG_BEGINS*/");
++
++SECTION (".fini");
++extern void __attribute__ ((section (".fini"))) _fini (void);
++void
++_fini (void)
++{
++
++ /* End of the _fini prolog. */
++ __asm__ ("ALIGN");
++ __asm__ ("END_FINI");
++ __asm__ ("\n/*@_fini_PROLOG_ENDS*/");
++
++ /* Xtensa: It doesn't really matter whether GCC thinks this is a leaf
++ function or not, and the scripts that are supposed to remove the
++ call don't catch the literal, resulting in an undefined symbol
++ reference. */
++#if 0
++ {
++ /* Let GCC know that _fini is not a leaf function by having a dummy
++ function call here. We arrange for this call to be omitted from
++ either crt file. */
++ extern void i_am_not_a_leaf (void);
++ i_am_not_a_leaf ();
++ }
++#endif
++
++ /* Beginning of the _fini epilog. */
++ __asm__ ("\n/*@_fini_EPILOG_BEGINS*/");
++ SECTION (".fini");
++}
++__asm__ ("END_FINI");
++
++/* End of the _fini epilog. Any further generated assembly (e.g. .ident)
++ is shared between both crt files. */
++__asm__ ("\n/*@_fini_EPILOG_ENDS*/");
++__asm__ ("\n/*@TRAILER_BEGINS*/");
++
++/* End of file. */
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-vfork.S uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-vfork.S
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-vfork.S 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-vfork.S 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,48 @@
++/* Copyright (C) 2013 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 <tls.h>
++
++/*
++ Save the PID value (save the negated value)
++ Registers ar, as are available; pid, tp are preserved across
++ */
++#define SAVE_PID(pid, tp, ar, as) \
++ rur tp, threadptr; \
++ movi ar, TLS_PRE_TCB_SIZE; \
++ sub tp, tp, ar; \
++ l32i pid, tp, PID; \
++ neg ar, pid; \
++ s32i pid, tp, PID; \
++
++/*
++ Restore the PID value if we are back in the parent.
++ */
++#define RESTORE_PID(pid, tp, res) \
++ beqz res, 1f; \
++ s32i pid, tp, PID; \
++1:
++
++#define RESTORE_PID12(ar, as, at) \
++ rur as, threadptr; \
++ movi ar, TLS_PRE_TCB_SIZE; \
++ sub as, as, ar; \
++ l32i ar, as, PID; \
++ neg ar, ar; \
++ s32i ar, as, PID;
++
++#include <libc/sysdeps/linux/xtensa/vfork.S>
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/sysdep-cancel.h uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/sysdep-cancel.h
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/sysdep-cancel.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/sysdep-cancel.h 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,108 @@
++/* Copyright (C) 2003 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <sysdep.h>
++#include <tls.h>
++/* #include <pt-machine.h> */
++#ifndef __ASSEMBLER__
++# include <pthreadP.h>
++#endif
++
++#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
++// FIXME: ENTRY includes an entry instruction, here we'd want entry sp, 48!
++# undef PSEUDO
++# define PSEUDO(name, syscall_name, args) \
++ .text; \
++ ENTRY (name) \
++ SINGLE_THREAD_P(a15); \
++ bnez a15, .Lpseudo_cancel; \
++ DO_CALL (syscall_name, args); \
++ bgez a2, .Lpseudo_done; \
++ movi a4, -4095; \
++ blt a2, a4, .Lpseudo_done; \
++ j SYSCALL_ERROR_LABEL; \
++ .Lpseudo_done: \
++ retw; \
++ .Lpseudo_cancel: \
++ /* The syscall args are in a2...a7; no need to save */ \
++ CENABLE; \
++ /* The return value is in a10 and preserved across the syscall */ \
++ DO_CALL (syscall_name, args); \
++ CDISABLE; \
++ bgez a2, .Lpseudo_end; \
++ movi a4, -4095; \
++ blt a2, a4, .Lpseudo_end; \
++ j SYSCALL_ERROR_LABEL; \
++ .Lpseudo_end:
++
++
++# ifdef IS_IN_libpthread
++# define CENABLE_FUNC __pthread_enable_asynccancel
++# define CDISABLE_FUNC __pthread_disable_asynccancel
++# define __local_multiple_threads __pthread_multiple_threads
++# elif !defined NOT_IN_libc
++# define CENABLE_FUNC __libc_enable_asynccancel
++# define CDISABLE_FUNC __libc_disable_asynccancel
++# define __local_multiple_threads __libc_multiple_threads
++# elif defined IS_IN_librt
++# define CENABLE_FUNC __librt_enable_asynccancel
++# define CDISABLE_FUNC __librt_disable_asynccancel
++# else
++# error Unsupported library
++# endif
++
++# define CENABLE movi a8, CENABLE_FUNC; \
++ callx8 a8
++# define CDISABLE movi a8, CDISABLE_FUNC; \
++ callx8 a8
++
++# if defined IS_IN_libpthread || !defined NOT_IN_libc
++# ifndef __ASSEMBLER__
++extern int __local_multiple_threads attribute_hidden;
++# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
++# else
++# define SINGLE_THREAD_P(reg) movi reg, __local_multiple_threads; \
++ l32i reg, reg, 0;
++# endif
++
++# else
++# ifndef __ASSEMBLER__
++# define SINGLE_THREAD_P \
++ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
++ header.multiple_threads) == 0, 1)
++# else
++# define SINGLE_THREAD_P(reg) \
++ rur reg, threadptr; \
++ l32i reg, reg, MULTIPLE_THREADS_OFFSET;
++# endif
++# endif
++
++#else
++
++/* This code should never be used but we define it anyhow. */
++# define SINGLE_THREAD_P (1)
++# define NO_CANCELLATION 1
++
++#endif
++
++
++#ifndef __ASSEMBLER__
++# define RTLD_SINGLE_THREAD_P \
++ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
++ header.multiple_threads) == 0, 1)
++#endif
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/vfork.S uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/vfork.S
+--- uClibc-git/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/vfork.S 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/vfork.S 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,59 @@
++/* Copyright (C) 2013 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 <tls.h>
++
++/*
++ Save the PID value, save 0x80000000 if PID was 0.
++ Registers a2 and a3 are available; ar should return the PID and as threadptr
++ */
++
++#define SAVE_PID(pid,tp,ar,as) \
++ rur tp, threadptr; \
++ movi ar, TLS_PRE_TCB_SIZE; \
++ sub tp, tp, ar; \
++ l32i pid, tp, PID; \
++ neg ar, pid; \
++ movi as, 0x80000000; \
++ moveqz ar, as, ar; \
++ s32i ar, tp, PID; \
++
++/*
++ Restore the PID value, restore to 0 if saved value was 0x80000000
++ Return value from the syscall is in a2.
++ */
++#define RESTORE_PID(pid,tp,res) \
++ beqz res, 1f; \
++ s32i pid, tp, PID; \
++1:
++
++/*
++ Special version for call12, where we don't have enough registers
++ available to preserve the original PID.
++ */
++#define RESTORE_PID12(ar, as, at) \
++ rur as, threadptr; \
++ movi ar, TLS_PRE_TCB_SIZE; \
++ sub as, as, ar; \
++ l32i ar, as, PID; \
++ movi at, 0x80000000; \
++ sub at, at, ar; \
++ neg ar, ar; \
++ moveqz ar, at, at; \
++ s32i ar, as, PID;
++
++#include <libc/sysdeps/linux/xtensa/vfork.S>
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/dl-tls.h uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/dl-tls.h
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/dl-tls.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/dl-tls.h 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,58 @@
++/* Thread-local storage handling in the ELF dynamic linker. Xtensa version.
++ Copyright (C) 2013 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _XTENSA_DL_TLS_H
++#define _XTENSA_DL_TLS_H 1
++
++/* Type used for the representation of TLS information in the GOT. */
++typedef struct
++{
++ unsigned long int ti_module;
++ unsigned long int ti_offset;
++} tls_index;
++
++extern void *__tls_get_addr (tls_index *ti);
++
++/* Type used to represent a TLS descriptor. */
++struct tlsdesc
++{
++ union
++ {
++ void *pointer;
++ long value;
++ } argument;
++ ptrdiff_t (*entry)(struct tlsdesc *);
++};
++
++/* Type used as the argument in a TLS descriptor for a symbol that
++ needs dynamic TLS offsets. */
++struct tlsdesc_dynamic_arg
++{
++ tls_index tlsinfo;
++ size_t gen_count;
++};
++
++extern ptrdiff_t attribute_hidden
++ _dl_tlsdesc_return(struct tlsdesc_dynamic_arg *);
++
++extern void *_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset);
++extern ptrdiff_t attribute_hidden
++ _dl_tlsdesc_dynamic(struct tlsdesc_dynamic_arg *);
++
++#endif
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/jmpbuf-unwind.h uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/jmpbuf-unwind.h
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/jmpbuf-unwind.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/jmpbuf-unwind.h 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,32 @@
++/* Copyright (C) 2005,2006 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 <setjmp.h>
++#include <stdint.h>
++#include <unwind.h>
++
++/* Test if longjmp to JMPBUF would unwind the frame
++ containing a local variable at ADDRESS. */
++#undef _JMPBUF_UNWINDS
++#define _JMPBUF_UNWINDS(jmpbuf, address, demangle) \
++ ((void *) (address) < (void *) demangle (jmpbuf[JB_SP]))
++
++#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
++ _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
++
++#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
++ ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj))
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/libc-tls.c uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/libc-tls.c
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/libc-tls.c 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/libc-tls.c 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,36 @@
++/* Thread-local storage handling in the ELF dynamic linker. Xtensa version.
++ Copyright (C) 2005 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 <sysdeps/generic/libc-tls.c>
++#include <dl-tls.h>
++
++#if defined(USE_TLS) && USE_TLS
++
++/* On Xtensa, linker optimizations are not required, so __tls_get_addr
++ can be called even in statically linked binaries. In this case module
++ must be always 1 and PT_TLS segment exist in the binary, otherwise it
++ would not link. */
++
++void *
++__tls_get_addr (tls_index *ti)
++{
++ dtv_t *dtv = THREAD_DTV ();
++ return (char *) dtv[1].pointer.val + ti->ti_offset;
++}
++
++#endif
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/Makefile.arch uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/Makefile.arch
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/Makefile.arch 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/Makefile.arch 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,40 @@
++# 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, write to the Free
++# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++# 02111-1307 USA.
++
++CFLAGS-pt-raise.c = -DNOT_IN_libc -DIS_IN_libpthread
++
++ASFLAGS-dl-tlsdesc.S = -DNOT_IN_libc=1
++ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc -DIS_IN_libpthread
++ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc -DIS_IN_libpthread
++ASFLAGS-nptl-sysdep.S = -DNOT_IN_libc -DIS_IN_libpthread \
++ -D_LIBC_REENTRANT \
++ -I$(top_srcdir)libc/sysdeps/linux/xtensa
++
++libc_arch_a_CSRC = libc-tls.c
++librt_arch_a_SSRC = dl-tlsdesc.S
++
++CFLAGS-gen_tlsdesc.c = -S
++$(libpthread_arch_OUT)/gen_tlsdesc.c: $(libpthread_arch_DIR)/tlsdesc.sym | $(libpthread_arch_OUT)
++ $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
++$(libpthread_arch_OUT)/gen_tlsdesc.s: $(libpthread_arch_OUT)/gen_tlsdesc.c | headers
++ $(compile.c)
++libpthread-generated-y += $(libpthread_arch_OUT)/gen_tlsdesc.s
++$(libpthread_arch_OUT)/tlsdesc.h: $(libpthread_arch_OUT)/gen_tlsdesc.s
++ $(do_sed) $(PTHREAD_GENERATE_MANGLE) $< > $@
++ @if test ! -s $@ ; then rm -f $@ ; false ; fi
++pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(libpthread_arch_OUT)/tlsdesc.h
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/pthreaddef.h uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/pthreaddef.h
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/pthreaddef.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/pthreaddef.h 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,39 @@
++/* Copyright (C) 2002, 2003, 2005 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* Default stack size. */
++#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024)
++
++/* Required stack pointer alignment at beginning. */
++#define STACK_ALIGN 16
++
++/* Minimal stack size after allocating thread descriptor and guard size. */
++#define MINIMAL_REST_STACK 2048
++
++/* Alignment requirement for TCB. */
++#define TCB_ALIGNMENT 16
++
++
++/* Location of current stack frame. */
++#define CURRENT_STACK_FRAME __builtin_frame_address (0)
++
++
++/* XXX Until we have a better place keep the definitions here. */
++
++#define __exit_thread_inline(val) \
++ INLINE_SYSCALL (exit, 1, (val))
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/pthread_spin_lock.S uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/pthread_spin_lock.S
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/pthread_spin_lock.S 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/pthread_spin_lock.S 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,37 @@
++/* 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++ .text
++ .align 4
++
++ .globl pthread_spin_lock
++pthread_spin_lock:
++
++ entry a1, 16
++
++ movi a3, 0
++ wsr a3, scompare1
++ movi a3, 1
++1: s32c1i a3, a2, 0
++ bnez a3, 1b
++ movi a2, 0
++
++ retw
++
++ .type pthread_spin_lock, @function
++ .size pthread_spin_lock, .-pthread_spin_lock
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/pthread_spin_trylock.S uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/pthread_spin_trylock.S
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/pthread_spin_trylock.S 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/pthread_spin_trylock.S 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,40 @@
++/* Copyright (C) 2005 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#define _ERRNO_H 1
++#include <bits/errno.h>
++
++ .text
++ .align 4
++
++ .globl pthread_spin_trylock
++pthread_spin_trylock:
++
++ entry a1, 16
++
++ movi a3, 0
++ wsr a3, scompare1
++ movi a3, 1
++ s32c1i a3, a2, 0
++ movi a2, EBUSY
++ moveqz a2, a3, a3
++
++ retw
++
++ .type pthread_spin_trylock, @function
++ .size pthread_spin_trylock, .-pthread_spin_trylock
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/tcb-offsets.sym uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/tcb-offsets.sym
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/tcb-offsets.sym 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/tcb-offsets.sym 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,7 @@
++#include <sysdep.h>
++#include <tls.h>
++
++TLS_PRE_TCB_SIZE sizeof (struct pthread)
++MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads)
++PID offsetof (struct pthread, pid)
++TID offsetof (struct pthread, tid)
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/tlsdesc.sym uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/tlsdesc.sym
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/tlsdesc.sym 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/tlsdesc.sym 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,10 @@
++#include <stddef.h>
++#include <sysdep.h>
++#include <tls.h>
++#include <link.h>
++#include <dl-tls.h>
++
++TLSDESC_ARG offsetof(struct tlsdesc, argument)
++TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count)
++TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module)
++TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset)
+diff -Nur uClibc-git/libpthread/nptl/sysdeps/xtensa/tls.h uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/tls.h
+--- uClibc-git/libpthread/nptl/sysdeps/xtensa/tls.h 1970-01-01 01:00:00.000000000 +0100
++++ uClibc-xtensa/libpthread/nptl/sysdeps/xtensa/tls.h 2014-06-03 12:04:16.669187814 +0200
+@@ -0,0 +1,159 @@
++/* Definition for thread-local data handling. NPTL/Xtensa version.
++ 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, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _TLS_H
++#define _TLS_H
++
++#ifndef __ASSEMBLER__
++
++# include <stdbool.h>
++# include <stddef.h>
++# include <stdint.h>
++
++/* Type for the dtv. */
++typedef union dtv
++{
++ size_t counter;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
++} dtv_t;
++
++
++#else /* __ASSEMBLER__ */
++# include <tcb-offsets.h>
++#endif /* __ASSEMBLER__ */
++
++/* We require TLS support in the tools. */
++#define HAVE_TLS_SUPPORT 1
++#define HAVE_TLS_MODEL_ATTRIBUTE 1
++#define HAVE___THREAD 1
++
++/* Signal that TLS support is available. */
++#define USE_TLS 1
++
++#ifndef __ASSEMBLER__
++
++/* Get system call information. */
++# include <sysdep.h>
++
++/* The TLS blocks start right after the TCB. */
++# define TLS_DTV_AT_TP 1
++
++/* Get the thread descriptor definition. */
++# include <../../descr.h>
++
++typedef struct
++{
++ dtv_t *dtv;
++ void *private;
++} tcbhead_t;
++
++/* This is the size of the initial TCB. */
++# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
++
++/* Alignment requirements for the initial TCB. */
++# define TLS_INIT_TCB_ALIGN 16
++
++/* This is the size of the TCB. */
++# define TLS_TCB_SIZE sizeof (tcbhead_t)
++
++/* This is the size we need before TCB. */
++# define TLS_PRE_TCB_SIZE sizeof (struct pthread)
++
++/* Alignment requirements for the TCB. */
++# define TLS_TCB_ALIGN 16
++
++
++/* Install the dtv pointer. The pointer passed is to the element with
++ index -1 which contain the length. */
++# define INSTALL_DTV(tcbp, dtvp) \
++ (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1)
++
++/* Install new dtv for current thread. */
++# define INSTALL_NEW_DTV(dtv) \
++ ({ tcbhead_t *__tcbp; \
++ __asm__ __volatile__ ("rur %0, threadptr" : "=r" (__tcbp)); \
++ __tcbp->dtv = (dtv); }) \
++
++/* Return dtv of given thread descriptor. */
++# define GET_DTV(tcbp) \
++ (((tcbhead_t *) (tcbp))->dtv)
++
++/* Code to initially initialize the thread pointer. This might need
++ special attention since 'errno' is not yet available and if the
++ operation can cause a failure 'errno' must not be touched. */
++# define TLS_INIT_TP(tcbp, secondcall) \
++ ({ __asm__ __volatile__ ("wur %0, threadptr" : : "r" (tcbp)); 0; })
++
++/* Return the address of the dtv for the current thread. */
++# define THREAD_DTV() \
++ ({ tcbhead_t *__tcbp; \
++ __asm__ __volatile__ ("rur %0, threadptr" : "=r" (__tcbp)); \
++ __tcbp->dtv; })
++
++/* Return the thread descriptor for the current thread. */
++# define THREAD_SELF \
++ ({ struct pthread *__self; \
++ __asm__ ("rur %0, threadptr" : "=r" (__self)); \
++ __self - 1; })
++
++/* Magic for libthread_db to know how to do THREAD_SELF. */
++# define DB_THREAD_SELF \
++ CONST_THREAD_AREA (32, sizeof (struct pthread))
++
++/* Access to data in the thread descriptor is easy. */
++#define THREAD_GETMEM(descr, member) \
++ descr->member
++#define THREAD_GETMEM_NC(descr, member, idx) \
++ descr->member[idx]
++#define THREAD_SETMEM(descr, member, value) \
++ descr->member = (value)
++#define THREAD_SETMEM_NC(descr, member, idx, value) \
++ descr->member[idx] = (value)
++
++/* Get and set the global scope generation counter in struct pthread. */
++#define THREAD_GSCOPE_FLAG_UNUSED 0
++#define THREAD_GSCOPE_FLAG_USED 1
++#define THREAD_GSCOPE_FLAG_WAIT 2
++#define THREAD_GSCOPE_RESET_FLAG() \
++ do \
++ { int __res \
++ = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \
++ THREAD_GSCOPE_FLAG_UNUSED); \
++ if (__res == THREAD_GSCOPE_FLAG_WAIT) \
++ lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
++ } \
++ while (0)
++#define THREAD_GSCOPE_SET_FLAG() \
++ do \
++ { \
++ THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \
++ atomic_write_barrier (); \
++ } \
++ while (0)
++
++#define THREAD_GSCOPE_WAIT() \
++ GL(dl_wait_lookup_done) ()
++
++#endif /* __ASSEMBLER__ */
++
++#endif /* tls.h */