Преглед на файлове

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 години
родител
ревизия
4c3023bc80
променени са 43 файла, в които са добавени 2479 реда и са изтрити 470 реда
  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_SLOT12_ALT	47
 #define R_XTENSA_SLOT13_ALT	48
 #define R_XTENSA_SLOT13_ALT	48
 #define R_XTENSA_SLOT14_ALT	49
 #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.  */
 /* Keep this the last entry.  */
-#define R_XTENSA_NUM		50
+#define R_XTENSA_NUM		54
 
 
 /* C6X specific relocs */
 /* C6X specific relocs */
 #define R_C6000_NONE		0
 #define R_C6000_NONE		0

+ 2 - 0
include/link.h

@@ -132,6 +132,8 @@ struct link_map
     size_t l_tls_modid;
     size_t l_tls_modid;
     /* Nonzero if _dl_init_static_tls should be called for this module */
     /* Nonzero if _dl_init_static_tls should be called for this module */
     unsigned int l_need_tls_init:1;
     unsigned int l_need_tls_init:1;
+    /* Address of TLS descriptor hash table.  */
+    void *l_tlsdesc_table;
 #endif
 #endif
 #endif
 #endif
   };
   };

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

@@ -70,6 +70,8 @@ struct elf_resolve {
   size_t l_tls_modid;
   size_t l_tls_modid;
   /* Nonzero if _dl_init_static_tls should be called for this module */
   /* Nonzero if _dl_init_static_tls should be called for this module */
   unsigned int l_need_tls_init:1;
   unsigned int l_need_tls_init:1;
+  /* Address of TLS descriptor hash table.  */
+  void *l_tlsdesc_table;
 #endif
 #endif
 
 
   ElfW(Addr) mapaddr;
   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)
 extern void _dl_allocate_static_tls (struct link_map *map)
      internal_function attribute_hidden;
      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 */
 /* Taken from glibc/elf/dl-reloc.c */
 #define CHECK_STATIC_TLS(sym_map)											\
 #define CHECK_STATIC_TLS(sym_map)											\
 	do {																	\
 	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);								\
 			_dl_allocate_static_tls (sym_map);								\
 	} while (0)
 	} 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,
 /* These are internal entry points to the two halves of _dl_allocate_tls,
    only used within rtld.c itself at startup time.  */
    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
  * 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,
  * object's TLS segment is too big to fit, we fail.  If it fits,
  * we set MAP->l_tls_offset and return.
  * 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 the alignment requirements are too high fail.  */
 	if (map->l_tls_align > _dl_tls_static_align)
 	if (map->l_tls_align > _dl_tls_static_align)
 	{
 	{
 fail:
 fail:
-		_dl_dprintf(2, "cannot allocate memory in static TLS block");
-		_dl_exit(30);
+		return -1;
 	}
 	}
 
 
 # ifdef TLS_TCB_AT_TP
 # ifdef TLS_TCB_AT_TP
@@ -169,6 +165,23 @@ fail:
 	}
 	}
 	else
 	else
 		map->l_need_tls_init = 1;
 		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
 #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.
  * 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. */
 /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete load map. */
 static __always_inline void
 static __always_inline void
 __dl_init_loadaddr_map(struct elf32_fdpic_loadaddr *loadaddr, Elf32_Addr dl_boot_got_pointer,
 __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;
 	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);
 	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 *
 void *
@@ -424,7 +175,7 @@ _dl_funcdesc_for (void *entry_point, void *got_value)
 		tpnt->funcdesc_ht = ht;
 		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) {
 	if (*entry) {
 		_dl_assert((*entry)->entry_point == entry_point);
 		_dl_assert((*entry)->entry_point == entry_point);
 		return _dl_stabilize_funcdesc(*entry);
 		return _dl_stabilize_funcdesc(*entry);
@@ -459,7 +210,8 @@ _dl_lookup_address(void const *address)
 		if (fd->got_value != rpnt->loadaddr.got_value)
 		if (fd->got_value != rpnt->loadaddr.got_value)
 			continue;
 			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) {
 		if (address && *(struct funcdesc_value *const*)address == fd) {
 			address = (*(struct funcdesc_value *const*)address)->entry_point;
 			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[] =
 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__ (
 __asm__ (
     "	.text\n"
     "	.text\n"
     "	.align  4\n"
     "	.align  4\n"
-    "	.literal_position\n"
+    "   .literal_position\n"
     "	.global _start\n"
     "	.global _start\n"
     "	.type   _start, @function\n"
     "	.type   _start, @function\n"
     "	.hidden _start\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;
 struct elf_resolve;
 extern unsigned long _dl_linux_resolver (struct elf_resolve *, int);
 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) \
 #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.  */
 /* Return the link-time address of _DYNAMIC.  */
 static __always_inline Elf32_Addr
 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 "ldso.h"
+#include "dl-tls.h"
+#include "tlsdeschtab.h"
 
 
 unsigned long
 unsigned long
 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
 _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 reloc_type;
 	int symtab_index;
 	int symtab_index;
 	char *symname;
 	char *symname;
+#if defined USE_TLS && USE_TLS
+	struct elf_resolve *tls_tpnt = NULL;
+#endif
 	struct symbol_ref sym_ref;
 	struct symbol_ref sym_ref;
 	ElfW(Addr) *reloc_addr;
 	ElfW(Addr) *reloc_addr;
 	ElfW(Addr) symbol_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.
 		 * here, so all bases should be covered.
 		 */
 		 */
 		if (unlikely (!symbol_addr &&
 		if (unlikely (!symbol_addr &&
+					  ELF_ST_TYPE (sym_ref.sym->st_info) != STT_TLS &&
 					  ELF_ST_BIND (sym_ref.sym->st_info) != STB_WEAK)) {
 					  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) {
 		if (_dl_trace_prelink) {
 			_dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
 			_dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
 						&sym_ref, elf_machine_type_class(reloc_type));
 						&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__)
 #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:
 	case R_XTENSA_RTLD:
 		if (rpnt->r_addend == 1) {
 		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];
 			*reloc_addr = *(ElfW(Addr) *) tpnt->dynamic_info[DT_PLTGOT];
 		} else if (rpnt->r_addend == 2) {
 		} else if (rpnt->r_addend == 2) {
 			/* Store the link map for the object.  */
 			/* 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;
 		*reloc_addr += tpnt->loadaddr + rpnt->r_addend;
 		break;
 		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:
 	default:
 		return -1; /* Calls _dl_exit(1).  */
 		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.
 # 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 \
 SSRC-y := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S \
 	sigrestorer.S syscall.S mmap.S windowspill.S __longjmp.S vfork.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
    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,
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    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
 /* 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
 #define _ERRNO_H	1
 #include <bits/errno.h>
 #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
         .text
 ENTRY (__clone)
 ENTRY (__clone)
@@ -39,7 +43,7 @@ ENTRY (__clone)
 
 
 	/* a2 and a3 are candidates for destruction by system-call return
 	/* a2 and a3 are candidates for destruction by system-call return
 	   parameters.  We don't need the stack pointer after the system
 	   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	a9, a5			/* save function argument */
 	mov	a5, a7
 	mov	a5, a7
@@ -48,19 +52,18 @@ ENTRY (__clone)
 	mov	a6, a4
 	mov	a6, a4
 	mov	a4, a8
 	mov	a4, a8
 	l32i	a8, a1, 16		/* child_tid */
 	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
 	syscall
 	bltz	a2, SYSCALL_ERROR_LABEL
 	bltz	a2, SYSCALL_ERROR_LABEL
 	beqz	a2, .Lthread_start
 	beqz	a2, .Lthread_start
 
 
-	/* Fall through for parent.  */
+	/* fall through for parent */
+
 .Lpseudo_end:
 .Lpseudo_end:
 	retw
 	retw
 
 
@@ -69,32 +72,38 @@ ENTRY (__clone)
 	j	SYSCALL_ERROR_LABEL
 	j	SYSCALL_ERROR_LABEL
 
 
 .Lthread_start:
 .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
 #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
 	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
 	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 */
 	mov	a6, a9			/* load up the 'arg' parameter */
 	callx4	a7			/* call the user's function */
 	callx4	a7			/* call the user's function */
 
 
 	/* Call _exit.  Note that any return parameter from the user's
 	/* 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
 	callx4	a2
 
 
 PSEUDO_END (__clone)
 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);
 	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
 #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 <setjmp.h>
 #include <jmpbuf-offsets.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) \
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
   ((void *) (address) < (void *) (jmpbuf)[JB_SP])
   ((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
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
    <http://www.gnu.org/licenses/>.  */
 
 
+#ifndef _LINUX_XTENSA_SYSDEP_H
+#define _LINUX_XTENSA_SYSDEP_H 1
+
+#include <common/sysdep.h>
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 
 
 #ifdef __ASSEMBLER__
 #ifdef __ASSEMBLER__
@@ -24,12 +28,6 @@
 #define ASM_TYPE_DIRECTIVE(name, typearg) .type name, typearg
 #define ASM_TYPE_DIRECTIVE(name, typearg) .type name, typearg
 #define ASM_SIZE_DIRECTIVE(name) .size name, . - name
 #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)							\
 #define	ENTRY(name)							\
   ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				\
   ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				\
   ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name), @function);			\
   ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name), @function);			\
@@ -52,6 +50,15 @@
 #undef END
 #undef END
 #define END(name) ASM_SIZE_DIRECTIVE(name)
 #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 a macro for this directive so it can be removed in a few places.  */
 #define LITERAL_POSITION .literal_position
 #define LITERAL_POSITION .literal_position
 
 
@@ -123,19 +130,7 @@
 #define	PSEUDO_END_ERRVAL(name)						      \
 #define	PSEUDO_END_ERRVAL(name)						      \
   END (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
 # if defined USE___THREAD
 #  ifndef NOT_IN_libc
 #  ifndef NOT_IN_libc
 #   define SYSCALL_ERROR_ERRNO __libc_errno
 #   define SYSCALL_ERROR_ERRNO __libc_errno
@@ -170,3 +165,9 @@
 #endif /* _LIBC_REENTRANT */
 #endif /* _LIBC_REENTRANT */
 
 
 #endif	/* __ASSEMBLER__ */
 #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.
    This file is part of the GNU C Library.
 
 
    The GNU C Library is free software; you can redistribute it and/or
    The GNU C Library is free software; you can redistribute it and/or
@@ -19,72 +19,67 @@
 #include <sys/syscall.h>
 #include <sys/syscall.h>
 #define _SIGNAL_H
 #define _SIGNAL_H
 #include <bits/signum.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
    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,
    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.
    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
    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
 #ifndef SAVE_PID
-#define SAVE_PID
+#define SAVE_PID(a,b,c,d)
 #endif
 #endif
-
 #ifndef RESTORE_PID
 #ifndef RESTORE_PID
-#define RESTORE_PID
+#define RESTORE_PID(a,b,c)
+#endif
+#ifndef RESTORE_PID12
+#define RESTORE_PID12(a,b,c)
 #endif
 #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)
 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
 	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 */
 	/* a7: return address */
+
 .L4:	mov	a12, a2
 .L4:	mov	a12, a2
 	mov	a13, a3
 	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	a3, 0
 	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
 	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
+
         syscall
         syscall
 
 
-	RESTORE_PID
+	RESTORE_PID(a5,a15,a2)
 
 
 	movi	a5, -4096
 	movi	a5, -4096
 
 
@@ -94,22 +89,24 @@ HIDDEN_ENTRY (__vfork)
 
 
 	bgeu	a6, a5, 1f
 	bgeu	a6, a5, 1f
 	jx	a7
 	jx	a7
-1:	call4	.Lerr			/* returns to original caller */
 
 
+1:	call4	.Lerr
 
 
 	/* a11: return address */
 	/* a11: return address */
+
 .L8:	mov	a12, a2
 .L8:	mov	a12, a2
 	mov	a13, a3
 	mov	a13, a3
 	mov	a14, a6
 	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	a3, 0
 	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
 	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
+
 	syscall
 	syscall
 
 
-	RESTORE_PID
+	RESTORE_PID(a9,a15,a2)
 
 
 	movi	a9, -4096
 	movi	a9, -4096
 
 
@@ -120,22 +117,25 @@ HIDDEN_ENTRY (__vfork)
 
 
 	bgeu	a10, a9, 1f
 	bgeu	a10, a9, 1f
 	jx	a11
 	jx	a11
-1:	call8	.Lerr			/* returns to original caller */
+
+1:	call8	.Lerr
 
 
 
 
 	/* a15: return address */
 	/* a15: return address */
+
 .L12:	mov	a12, a2
 .L12:	mov	a12, a2
 	mov	a13, a3
 	mov	a13, a3
 	mov	a14, a6
 	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	a3, 0
 	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
 	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
+
 	syscall
 	syscall
 
 
-	RESTORE_PID
+	RESTORE_PID12(a3,a6,a15)
 
 
 	mov	a3, a13
 	mov	a3, a13
 	movi	a13, -4096
 	movi	a13, -4096
@@ -147,18 +147,18 @@ HIDDEN_ENTRY (__vfork)
 
 
 	bgeu	a14, a13, 1f
 	bgeu	a14, a13, 1f
 	jx	a15
 	jx	a15
-1:	call12	.Lerr			/* returns to original caller */
 
 
+1:	call12	.Lerr
 
 
 	.align 4
 	.align 4
+
 .Lerr:	entry	a1, 16
 .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	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)
 	PSEUDO_END (__vfork)
 .Lpseudo_end:
 .Lpseudo_end:

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

@@ -22,8 +22,6 @@
 #include <lowlevellock.h>
 #include <lowlevellock.h>
 #include <sys/time.h>
 #include <sys/time.h>
 #include <tls.h>
 #include <tls.h>
-#include <tcb-offsets.h>
-
 
 
 void
 void
 #ifndef IS_IN_libpthread
 #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)