Browse Source

xtensa: add support for NPTL

Changes from:
https://github.com/foss-xtensa/uClibc/commits/xtensa_nptl

Author: Chris Zankel <chris@zankel.net>
Author: Baruch Siach <baruch@tkos.co.il>
Waldemar Brodkorb 9 years ago
parent
commit
4c3023bc80
43 changed files with 2479 additions and 470 deletions
  1. 4 1
      include/elf.h
  2. 2 0
      include/link.h
  3. 2 0
      ldso/include/dl-hash.h
  4. 265 0
      ldso/include/inline-hashtab.h
  5. 6 1
      ldso/include/ldsodefs.h
  6. 119 0
      ldso/include/tlsdeschtab.h
  7. 21 8
      ldso/ldso/dl-tls.c
  8. 11 259
      ldso/ldso/fdpic/dl-inlines.h
  9. 27 50
      ldso/ldso/xtensa/dl-debug.h
  10. 1 1
      ldso/ldso/xtensa/dl-startup.h
  11. 6 3
      ldso/ldso/xtensa/dl-sysdep.h
  12. 96 0
      ldso/ldso/xtensa/dl-tlsdesc.S
  13. 46 5
      ldso/ldso/xtensa/elfinterp.c
  14. 4 1
      libc/sysdeps/linux/xtensa/Makefile.arch
  15. 55 46
      libc/sysdeps/linux/xtensa/clone.S
  16. 6 2
      libc/sysdeps/linux/xtensa/fork.c
  17. 18 20
      libc/sysdeps/linux/xtensa/jmpbuf-unwind.h
  18. 155 0
      libc/sysdeps/linux/xtensa/sys/ptrace.h
  19. 20 19
      libc/sysdeps/linux/xtensa/sysdep.h
  20. 52 52
      libc/sysdeps/linux/xtensa/vfork.S
  21. 0 2
      libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c
  22. 15 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch
  23. 184 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/pthreadtypes.h
  24. 35 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/semaphore.h
  25. 3 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/clone.S
  26. 24 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/createthread.c
  27. 29 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/fork.c
  28. 132 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.c
  29. 293 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.h
  30. 134 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-initfini.c
  31. 89 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pthread_once.c
  32. 108 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/sysdep-cancel.h
  33. 59 0
      libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/vfork.S
  34. 40 0
      libpthread/nptl/sysdeps/xtensa/Makefile.arch
  35. 58 0
      libpthread/nptl/sysdeps/xtensa/dl-tls.h
  36. 32 0
      libpthread/nptl/sysdeps/xtensa/jmpbuf-unwind.h
  37. 36 0
      libpthread/nptl/sysdeps/xtensa/libc-tls.c
  38. 37 0
      libpthread/nptl/sysdeps/xtensa/pthread_spin_lock.S
  39. 40 0
      libpthread/nptl/sysdeps/xtensa/pthread_spin_trylock.S
  40. 39 0
      libpthread/nptl/sysdeps/xtensa/pthreaddef.h
  41. 7 0
      libpthread/nptl/sysdeps/xtensa/tcb-offsets.sym
  42. 159 0
      libpthread/nptl/sysdeps/xtensa/tls.h
  43. 10 0
      libpthread/nptl/sysdeps/xtensa/tlsdesc.sym

+ 4 - 1
include/elf.h

@@ -3072,8 +3072,11 @@ typedef Elf32_Addr Elf32_Conflict;
 #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

+ 2 - 0
include/link.h

@@ -132,6 +132,8 @@ struct link_map
     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
   };

+ 2 - 0
ldso/include/dl-hash.h

@@ -70,6 +70,8 @@ struct elf_resolve {
   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;

+ 265 - 0
ldso/include/inline-hashtab.h

@@ -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

+ 6 - 1
ldso/include/ldsodefs.h

@@ -62,13 +62,18 @@ extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
 
 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.  */

+ 119 - 0
ldso/include/tlsdeschtab.h

@@ -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

+ 21 - 8
ldso/ldso/dl-tls.c

@@ -100,20 +100,16 @@ _dl_realloc (void * __ptr, size_t __size)
  * 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 @@ fail:
 	}
 	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

+ 11 - 259
ldso/ldso/fdpic/dl-inlines.h

@@ -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 @@ __dl_addr_in_loadaddr(void *p, struct elf32_fdpic_loadaddr loadaddr)
 	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)
+static int
+eq_pointer(void *p, void *q)
 {
-	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)
-{
-	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 @@ _dl_funcdesc_for (void *entry_point, void *got_value)
 		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 @@ _dl_lookup_address(void const *address)
 		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;

+ 27 - 50
ldso/ldso/xtensa/dl-debug.h

@@ -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"
 };

+ 1 - 1
ldso/ldso/xtensa/dl-startup.h

@@ -11,7 +11,7 @@
 __asm__ (
     "	.text\n"
     "	.align  4\n"
-    "	.literal_position\n"
+    "   .literal_position\n"
     "	.global _start\n"
     "	.type   _start, @function\n"
     "	.hidden _start\n"

+ 6 - 3
ldso/ldso/xtensa/dl-sysdep.h

@@ -78,10 +78,13 @@ typedef struct xtensa_got_location_struct {
 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

+ 96 - 0
ldso/ldso/xtensa/dl-tlsdesc.S

@@ -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 */

+ 46 - 5
ldso/ldso/xtensa/elfinterp.c

@@ -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 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 	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 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 		 * 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 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 
 	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 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 		*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).  */
 	}

+ 4 - 1
libc/sysdeps/linux/xtensa/Makefile.arch

@@ -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

+ 55 - 46
libc/sysdeps/linux/xtensa/clone.S

@@ -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>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
+#define __ASSEMBLY__
+#include <linux/sched.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) */
+/* 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 @@ ENTRY (__clone)
 
 	/* 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 @@ ENTRY (__clone)
 	mov	a6, a4
 	mov	a4, a8
 	l32i	a8, a1, 16		/* child_tid */
-	movi	a2, SYS_ify (clone)
-
-	/* syscall (a2 = NR_clone,
-		    a6 = clone_flags,
-		    a3 = usp,
-		    a4 = parent_tid,
-		    a5 = child_tls,
-		    a8 = child_tid) */
+	movi	a2, SYS_ify(clone)
+
+	/* syscall(NR_clone,clone_flags, usp, parent_tid, child_tls, child_tid)
+                     a2         a6        a3        a4        a5         a8
+         */
+
 	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 @@ ENTRY (__clone)
 	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)

+ 6 - 2
libc/sysdeps/linux/xtensa/fork.c

@@ -20,6 +20,10 @@ pid_t fork(void)
 {
 	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

+ 18 - 20
libc/sysdeps/linux/xtensa/jmpbuf-unwind.h

@@ -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

+ 155 - 0
libc/sysdeps/linux/xtensa/sys/ptrace.h

@@ -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 */

+ 20 - 19
libc/sysdeps/linux/xtensa/sysdep.h

@@ -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 */

+ 52 - 52
libc/sysdeps/linux/xtensa/vfork.S

@@ -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' and set new stack pointer to the same address */
 
-	/* Use syscall 'clone'.  Set new stack pointer to the same address.  */
-	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(a5,a15,a2)
 
 	movi	a5, -4096
 
@@ -94,22 +89,24 @@ HIDDEN_ENTRY (__vfork)
 
 	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 @@ HIDDEN_ENTRY (__vfork)
 
 	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 @@ HIDDEN_ENTRY (__vfork)
 
 	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:

+ 0 - 2
libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c

@@ -22,8 +22,6 @@
 #include <lowlevellock.h>
 #include <sys/time.h>
 #include <tls.h>
-#include <tcb-offsets.h>
-
 
 void
 #ifndef IS_IN_libpthread

+ 15 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch

@@ -0,0 +1,15 @@
+# uClibc-ng project
+# Licensed under the LGPL v2.1, see the file COPYING and LICENSE.
+
+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 =
+
+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

+ 184 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/pthreadtypes.h

@@ -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 */

+ 35 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/semaphore.h

@@ -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;

+ 3 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/clone.S

@@ -0,0 +1,3 @@
+#define RESET_PID
+#include <tcb-offsets.h>
+#include <libc/sysdeps/linux/xtensa/clone.S>

+ 24 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/createthread.c

@@ -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>

+ 29 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/fork.c

@@ -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"

+ 132 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.c

@@ -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

+ 293 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.h

@@ -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 */

+ 134 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-initfini.c

@@ -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. */

+ 89 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pthread_once.c

@@ -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)

+ 108 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/sysdep-cancel.h

@@ -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

+ 59 - 0
libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/vfork.S

@@ -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>

+ 40 - 0
libpthread/nptl/sysdeps/xtensa/Makefile.arch

@@ -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

+ 58 - 0
libpthread/nptl/sysdeps/xtensa/dl-tls.h

@@ -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

+ 32 - 0
libpthread/nptl/sysdeps/xtensa/jmpbuf-unwind.h

@@ -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))

+ 36 - 0
libpthread/nptl/sysdeps/xtensa/libc-tls.c

@@ -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

+ 37 - 0
libpthread/nptl/sysdeps/xtensa/pthread_spin_lock.S

@@ -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

+ 40 - 0
libpthread/nptl/sysdeps/xtensa/pthread_spin_trylock.S

@@ -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

+ 39 - 0
libpthread/nptl/sysdeps/xtensa/pthreaddef.h

@@ -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))

+ 7 - 0
libpthread/nptl/sysdeps/xtensa/tcb-offsets.sym

@@ -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)

+ 159 - 0
libpthread/nptl/sysdeps/xtensa/tls.h

@@ -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 */

+ 10 - 0
libpthread/nptl/sysdeps/xtensa/tlsdesc.sym

@@ -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)