From 4c3023bc803012656cf45749960282351efc8020 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sat, 20 Sep 2014 22:36:23 +0200 Subject: xtensa: add support for NPTL Changes from: https://github.com/foss-xtensa/uClibc/commits/xtensa_nptl Author: Chris Zankel Author: Baruch Siach --- include/elf.h | 5 +- include/link.h | 2 + ldso/include/dl-hash.h | 2 + ldso/include/inline-hashtab.h | 265 +++++++++++++++++++ ldso/include/ldsodefs.h | 7 +- ldso/include/tlsdeschtab.h | 119 +++++++++ ldso/ldso/dl-tls.c | 29 +- ldso/ldso/fdpic/dl-inlines.h | 270 +------------------ ldso/ldso/xtensa/dl-debug.h | 77 ++---- ldso/ldso/xtensa/dl-startup.h | 2 +- ldso/ldso/xtensa/dl-sysdep.h | 9 +- ldso/ldso/xtensa/dl-tlsdesc.S | 96 +++++++ ldso/ldso/xtensa/elfinterp.c | 51 +++- libc/sysdeps/linux/xtensa/Makefile.arch | 5 +- libc/sysdeps/linux/xtensa/clone.S | 101 +++---- libc/sysdeps/linux/xtensa/fork.c | 8 +- libc/sysdeps/linux/xtensa/jmpbuf-unwind.h | 38 ++- libc/sysdeps/linux/xtensa/sys/ptrace.h | 155 +++++++++++ libc/sysdeps/linux/xtensa/sysdep.h | 39 +-- libc/sysdeps/linux/xtensa/vfork.S | 104 ++++---- .../nptl/sysdeps/unix/sysv/linux/lowlevellock.c | 2 - .../sysdeps/unix/sysv/linux/xtensa/Makefile.arch | 15 ++ .../unix/sysv/linux/xtensa/bits/pthreadtypes.h | 184 +++++++++++++ .../unix/sysv/linux/xtensa/bits/semaphore.h | 35 +++ .../nptl/sysdeps/unix/sysv/linux/xtensa/clone.S | 3 + .../sysdeps/unix/sysv/linux/xtensa/createthread.c | 24 ++ .../nptl/sysdeps/unix/sysv/linux/xtensa/fork.c | 29 ++ .../sysdeps/unix/sysv/linux/xtensa/lowlevellock.c | 132 ++++++++++ .../sysdeps/unix/sysv/linux/xtensa/lowlevellock.h | 293 +++++++++++++++++++++ .../sysdeps/unix/sysv/linux/xtensa/pt-initfini.c | 134 ++++++++++ .../sysdeps/unix/sysv/linux/xtensa/pthread_once.c | 89 +++++++ .../sysdeps/unix/sysv/linux/xtensa/sysdep-cancel.h | 108 ++++++++ .../nptl/sysdeps/unix/sysv/linux/xtensa/vfork.S | 59 +++++ libpthread/nptl/sysdeps/xtensa/Makefile.arch | 40 +++ libpthread/nptl/sysdeps/xtensa/dl-tls.h | 58 ++++ libpthread/nptl/sysdeps/xtensa/jmpbuf-unwind.h | 32 +++ libpthread/nptl/sysdeps/xtensa/libc-tls.c | 36 +++ libpthread/nptl/sysdeps/xtensa/pthread_spin_lock.S | 37 +++ .../nptl/sysdeps/xtensa/pthread_spin_trylock.S | 40 +++ libpthread/nptl/sysdeps/xtensa/pthreaddef.h | 39 +++ libpthread/nptl/sysdeps/xtensa/tcb-offsets.sym | 7 + libpthread/nptl/sysdeps/xtensa/tls.h | 159 +++++++++++ libpthread/nptl/sysdeps/xtensa/tlsdesc.sym | 10 + 43 files changed, 2479 insertions(+), 470 deletions(-) create mode 100644 ldso/include/inline-hashtab.h create mode 100644 ldso/include/tlsdeschtab.h create mode 100644 ldso/ldso/xtensa/dl-tlsdesc.S create mode 100644 libc/sysdeps/linux/xtensa/sys/ptrace.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/pthreadtypes.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/semaphore.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/clone.S create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/createthread.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/fork.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/lowlevellock.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pt-initfini.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/pthread_once.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/sysdep-cancel.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/vfork.S create mode 100644 libpthread/nptl/sysdeps/xtensa/Makefile.arch create mode 100644 libpthread/nptl/sysdeps/xtensa/dl-tls.h create mode 100644 libpthread/nptl/sysdeps/xtensa/jmpbuf-unwind.h create mode 100644 libpthread/nptl/sysdeps/xtensa/libc-tls.c create mode 100644 libpthread/nptl/sysdeps/xtensa/pthread_spin_lock.S create mode 100644 libpthread/nptl/sysdeps/xtensa/pthread_spin_trylock.S create mode 100644 libpthread/nptl/sysdeps/xtensa/pthreaddef.h create mode 100644 libpthread/nptl/sysdeps/xtensa/tcb-offsets.sym create mode 100644 libpthread/nptl/sysdeps/xtensa/tls.h create mode 100644 libpthread/nptl/sysdeps/xtensa/tlsdesc.sym diff --git a/include/elf.h b/include/elf.h index 1979209cd..fc6086489 100644 --- a/include/elf.h +++ b/include/elf.h @@ -3072,8 +3072,11 @@ typedef Elf32_Addr Elf32_Conflict; #define R_XTENSA_SLOT12_ALT 47 #define R_XTENSA_SLOT13_ALT 48 #define R_XTENSA_SLOT14_ALT 49 +#define R_XTENSA_TLSDESC_FN 50 +#define R_XTENSA_TLSDESC_ARG 51 +#define R_XTENSA_TLS_TPOFF 53 /* Keep this the last entry. */ -#define R_XTENSA_NUM 50 +#define R_XTENSA_NUM 54 /* C6X specific relocs */ #define R_C6000_NONE 0 diff --git a/include/link.h b/include/link.h index 147b79384..67bc80062 100644 --- a/include/link.h +++ b/include/link.h @@ -132,6 +132,8 @@ struct link_map size_t l_tls_modid; /* Nonzero if _dl_init_static_tls should be called for this module */ unsigned int l_need_tls_init:1; + /* Address of TLS descriptor hash table. */ + void *l_tlsdesc_table; #endif #endif }; diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h index e1e3e3f95..18f21aefa 100644 --- a/ldso/include/dl-hash.h +++ b/ldso/include/dl-hash.h @@ -70,6 +70,8 @@ struct elf_resolve { size_t l_tls_modid; /* Nonzero if _dl_init_static_tls should be called for this module */ unsigned int l_need_tls_init:1; + /* Address of TLS descriptor hash table. */ + void *l_tlsdesc_table; #endif ElfW(Addr) mapaddr; diff --git a/ldso/include/inline-hashtab.h b/ldso/include/inline-hashtab.h new file mode 100644 index 000000000..4a4812027 --- /dev/null +++ b/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 diff --git a/ldso/include/ldsodefs.h b/ldso/include/ldsodefs.h index 4063d00f4..f17ac0ca0 100644 --- a/ldso/include/ldsodefs.h +++ b/ldso/include/ldsodefs.h @@ -62,13 +62,18 @@ extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp) extern void _dl_allocate_static_tls (struct link_map *map) internal_function attribute_hidden; +extern int _dl_try_allocate_static_tls (struct link_map* map) + internal_function attribute_hidden; /* Taken from glibc/elf/dl-reloc.c */ #define CHECK_STATIC_TLS(sym_map) \ do { \ - if (unlikely((sym_map)->l_tls_offset == NO_TLS_OFFSET)) \ + if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET, 0)) \ _dl_allocate_static_tls (sym_map); \ } while (0) +#define TRY_STATIC_TLS(sym_map) \ + (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \ + || _dl_try_allocate_static_tls (sym_map) == 0) /* These are internal entry points to the two halves of _dl_allocate_tls, only used within rtld.c itself at startup time. */ diff --git a/ldso/include/tlsdeschtab.h b/ldso/include/tlsdeschtab.h new file mode 100644 index 000000000..86baea148 --- /dev/null +++ b/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 + + uClibc port by Baruch Siach + + 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 + . */ + +#ifndef TLSDESCHTAB_H +# define TLSDESCHTAB_H 1 + +# ifdef SHARED + +# include + +inline static int +hash_tlsdesc (void *p) +{ + struct tlsdesc_dynamic_arg *td = p; + + /* We know all entries are for the same module, so ti_offset is the + only distinguishing entry. */ + return td->tlsinfo.ti_offset; +} + +inline static int +eq_tlsdesc (void *p, void *q) +{ + struct tlsdesc_dynamic_arg *tdp = p, *tdq = q; + + return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset; +} + +inline static int +map_generation (struct link_map *map) +{ + size_t idx = map->l_tls_modid; + struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list); + + /* Find the place in the dtv slotinfo list. */ + do + { + /* Does it fit in the array of this list element? */ + if (idx < listp->len) + { + /* We should never get here for a module in static TLS, so + we can assume that, if the generation count is zero, we + still haven't determined the generation count for this + module. */ + if (listp->slotinfo[idx].gen) + return listp->slotinfo[idx].gen; + else + break; + } + idx -= listp->len; + listp = listp->next; + } + while (listp != NULL); + + /* If we get to this point, the module still hasn't been assigned an + entry in the dtv slotinfo data structures, and it will when we're + done with relocations. At that point, the module will get a + generation number that is one past the current generation, so + return exactly that. */ + return GL(dl_tls_generation) + 1; +} + +void * +internal_function +_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset) +{ + struct funcdesc_ht *ht; + void **entry; + struct tlsdesc_dynamic_arg *td, test; + + ht = map->l_tlsdesc_table; + if (! ht) + { + ht = htab_create (); + if (! ht) + return 0; + map->l_tlsdesc_table = ht; + } + + test.tlsinfo.ti_module = map->l_tls_modid; + test.tlsinfo.ti_offset = ti_offset; + entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc); + if (*entry) + { + td = *entry; + return td; + } + + *entry = td = _dl_malloc (sizeof (struct tlsdesc_dynamic_arg)); + /* This may be higher than the map's generation, but it doesn't + matter much. Worst case, we'll have one extra DTV update per + thread. */ + td->gen_count = map_generation (map); + td->tlsinfo = test.tlsinfo; + + return td; +} + +# endif /* SHARED */ + +#endif diff --git a/ldso/ldso/dl-tls.c b/ldso/ldso/dl-tls.c index 6679693f4..5d6d3b9d3 100644 --- a/ldso/ldso/dl-tls.c +++ b/ldso/ldso/dl-tls.c @@ -100,20 +100,16 @@ _dl_realloc (void * __ptr, size_t __size) * the static TLS area already allocated for each running thread. If this * object's TLS segment is too big to fit, we fail. If it fits, * we set MAP->l_tls_offset and return. - * This function intentionally does not return any value but signals error - * directly, as static TLS should be rare and code handling it should - * not be inlined as much as possible. */ -void -internal_function __attribute_noinline__ -_dl_allocate_static_tls (struct link_map *map) +int +internal_function +_dl_try_allocate_static_tls (struct link_map* map) { /* If the alignment requirements are too high fail. */ if (map->l_tls_align > _dl_tls_static_align) { fail: - _dl_dprintf(2, "cannot allocate memory in static TLS block"); - _dl_exit(30); + return -1; } # ifdef TLS_TCB_AT_TP @@ -169,6 +165,23 @@ fail: } else map->l_need_tls_init = 1; + + return 0; +} + +/* + * This function intentionally does not return any value but signals error + * directly, as static TLS should be rare and code handling it should + * not be inlined as much as possible. + */ +void +internal_function __attribute_noinline__ +_dl_allocate_static_tls (struct link_map *map) +{ + if (_dl_try_allocate_static_tls (map)) { + _dl_dprintf(2, "cannot allocate memory in static TLS block"); + _dl_exit(30); + } } #ifdef SHARED diff --git a/ldso/ldso/fdpic/dl-inlines.h b/ldso/ldso/fdpic/dl-inlines.h index 14a491689..ebbd0334c 100644 --- a/ldso/ldso/fdpic/dl-inlines.h +++ b/ldso/ldso/fdpic/dl-inlines.h @@ -5,6 +5,8 @@ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ +#include + /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete load map. */ static __always_inline void __dl_init_loadaddr_map(struct elf32_fdpic_loadaddr *loadaddr, Elf32_Addr dl_boot_got_pointer, @@ -143,269 +145,18 @@ __dl_addr_in_loadaddr(void *p, struct elf32_fdpic_loadaddr loadaddr) return 0; } -/* - * The hashcode handling code below is heavily inspired in libiberty's - * hashtab code, but with most adaptation points and support for - * deleting elements removed. - * - * Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - * Contributed by Vladimir Makarov (vmakarov@cygnus.com). - */ -static __always_inline unsigned long -higher_prime_number(unsigned long n) -{ - /* These are primes that are near, but slightly smaller than, a power of two. */ - static const unsigned long primes[] = { - 7, - 13, - 31, - 61, - 127, - 251, - 509, - 1021, - 2039, - 4093, - 8191, - 16381, - 32749, - 65521, - 131071, - 262139, - 524287, - 1048573, - 2097143, - 4194301, - 8388593, - 16777213, - 33554393, - 67108859, - 134217689, - 268435399, - 536870909, - 1073741789, - /* 4294967291 */ - ((unsigned long) 2147483647) + ((unsigned long) 2147483644), - }; - const unsigned long *low = &primes[0]; - const unsigned long *high = &primes[ARRAY_SIZE(primes)]; - - while (low != high) { - const unsigned long *mid = low + (high - low) / 2; - if (n > *mid) - low = mid + 1; - else - high = mid; - } - -#if 0 - /* If we've run out of primes, abort. */ - if (n > *low) { - fprintf(stderr, "Cannot find prime bigger than %lu\n", n); - abort(); - } -#endif - - return *low; -} - -struct funcdesc_ht -{ - /* Table itself */ - struct funcdesc_value **entries; - - /* Current size (in entries) of the hash table */ - size_t size; - - /* Current number of elements */ - size_t n_elements; -}; - -static __always_inline int -hash_pointer(const void *p) +static int +hash_pointer(void *p) { return (int) ((long)p >> 3); } -static __always_inline struct funcdesc_ht * -htab_create(void) -{ - struct funcdesc_ht *ht = _dl_malloc(sizeof(*ht)); - size_t ent_size; - - if (!ht) - return NULL; - ht->size = 3; - ent_size = sizeof(struct funcdesc_ht_value *) * ht->size; - ht->entries = _dl_malloc(ent_size); - if (!ht->entries) - return NULL; - - ht->n_elements = 0; - _dl_memset(ht->entries, 0, ent_size); - - return ht; -} - -/* - * This is only called from _dl_loadaddr_unmap, so it's safe to call - * _dl_free(). See the discussion below. - */ -static __always_inline void -htab_delete(struct funcdesc_ht *htab) +static int +eq_pointer(void *p, void *q) { - size_t i; - - for (i = htab->size - 1; i >= 0; i--) - if (htab->entries[i]) - _dl_free(htab->entries[i]); - - _dl_free(htab->entries); - _dl_free(htab); -} - -/* - * Similar to htab_find_slot, but without several unwanted side effects: - * - Does not call htab->eq_f when it finds an existing entry. - * - Does not change the count of elements/searches/collisions in the - * hash table. - * This function also assumes there are no deleted entries in the table. - * HASH is the hash value for the element to be inserted. - */ -static __always_inline struct funcdesc_value ** -find_empty_slot_for_expand(struct funcdesc_ht *htab, int hash) -{ - size_t size = htab->size; - unsigned int index = hash % size; - struct funcdesc_value **slot = htab->entries + index; - int hash2; - - if (!*slot) - return slot; - - hash2 = 1 + hash % (size - 2); - for (;;) { - index += hash2; - if (index >= size) - index -= size; - - slot = htab->entries + index; - if (!*slot) - return slot; - } -} - -/* - * The following function changes size of memory allocated for the - * entries and repeatedly inserts the table elements. The occupancy - * of the table after the call will be about 50%. Naturally the hash - * table must already exist. Remember also that the place of the - * table entries is changed. If memory allocation failures are allowed, - * this function will return zero, indicating that the table could not be - * expanded. If all goes well, it will return a non-zero value. - */ -static __always_inline int -htab_expand(struct funcdesc_ht *htab) -{ - struct funcdesc_value **oentries; - struct funcdesc_value **olimit; - struct funcdesc_value **p; - struct funcdesc_value **nentries; - size_t nsize; - - oentries = htab->entries; - olimit = oentries + htab->size; - - /* - * Resize only when table after removal of unused elements is either - * too full or too empty. - */ - if (htab->n_elements * 2 > htab->size) - nsize = higher_prime_number(htab->n_elements * 2); - else - nsize = htab->size; - - nentries = _dl_malloc(sizeof(*nentries) * nsize); - _dl_memset(nentries, 0, sizeof(*nentries) * nsize); - if (nentries == NULL) - return 0; - htab->entries = nentries; - htab->size = nsize; - - p = oentries; - do { - if (*p) - *find_empty_slot_for_expand(htab, hash_pointer((*p)->entry_point)) = *p; - p++; - } while (p < olimit); - -#if 0 - /* - * We can't tell whether this was allocated by the _dl_malloc() - * built into ld.so or malloc() in the main executable or libc, - * and calling free() for something that wasn't malloc()ed could - * do Very Bad Things (TM). Take the conservative approach - * here, potentially wasting as much memory as actually used by - * the hash table, even if multiple growths occur. That's not - * so bad as to require some overengineered solution that would - * enable us to keep track of how it was allocated. - */ - _dl_free(oentries); -#endif - return 1; -} - -/* - * This function searches for a hash table slot containing an entry - * equal to the given element. To delete an entry, call this with - * INSERT = 0, then call htab_clear_slot on the slot returned (possibly - * after doing some checks). To insert an entry, call this with - * INSERT = 1, then write the value you want into the returned slot. - * When inserting an entry, NULL may be returned if memory allocation - * fails. - */ -static __always_inline struct funcdesc_value ** -htab_find_slot(struct funcdesc_ht *htab, void *ptr, int insert) -{ - unsigned int index; - int hash, hash2; - size_t size; - struct funcdesc_value **entry; - - if (htab->size * 3 <= htab->n_elements * 4 && - htab_expand(htab) == 0) - return NULL; - - hash = hash_pointer(ptr); - - size = htab->size; - index = hash % size; - - entry = &htab->entries[index]; - if (!*entry) - goto empty_entry; - else if ((*entry)->entry_point == ptr) - return entry; - - hash2 = 1 + hash % (size - 2); - for (;;) { - index += hash2; - if (index >= size) - index -= size; - - entry = &htab->entries[index]; - if (!*entry) - goto empty_entry; - else if ((*entry)->entry_point == ptr) - return entry; - } - - empty_entry: - if (!insert) - return NULL; + struct funcdesc_value *entry = p; - htab->n_elements++; - return entry; + return entry->entry_point == q; } void * @@ -424,7 +175,7 @@ _dl_funcdesc_for (void *entry_point, void *got_value) tpnt->funcdesc_ht = ht; } - entry = htab_find_slot(ht, entry_point, 1); + entry = htab_find_slot(ht, entry_point, 1, hash_pointer, eq_pointer); if (*entry) { _dl_assert((*entry)->entry_point == entry_point); return _dl_stabilize_funcdesc(*entry); @@ -459,7 +210,8 @@ _dl_lookup_address(void const *address) if (fd->got_value != rpnt->loadaddr.got_value) continue; - address = htab_find_slot(rpnt->funcdesc_ht, (void *)fd->entry_point, 0); + address = htab_find_slot(rpnt->funcdesc_ht, (void *)fd->entry_point, 0, + hash_pointer, eq_pointer); if (address && *(struct funcdesc_value *const*)address == fd) { address = (*(struct funcdesc_value *const*)address)->entry_point; diff --git a/ldso/ldso/xtensa/dl-debug.h b/ldso/ldso/xtensa/dl-debug.h index 4128d9452..18beae5ca 100644 --- a/ldso/ldso/xtensa/dl-debug.h +++ b/ldso/ldso/xtensa/dl-debug.h @@ -8,54 +8,31 @@ static const char * const _dl_reltypes_tab[] = { - "R_XTENSA_NONE", - "R_XTENSA_32", - "R_XTENSA_RTLD", - "R_XTENSA_GLOB_DAT", - "R_XTENSA_JMP_SLOT", - "R_XTENSA_RELATIVE", - "R_XTENSA_PLT", - "R_XTENSA_UNUSED7", - "R_XTENSA_OP0", - "R_XTENSA_OP1", - "R_XTENSA_OP2", - "R_XTENSA_ASM_EXPAND", - "R_XTENSA_ASM_SIMPLIFY", - "R_XTENSA_UNUSED13", - "R_XTENSA_UNUSED14", - "R_XTENSA_GNU_VTINHERIT", - "R_XTENSA_GNU_VTENTRY", - "R_XTENSA_DIFF8", - "R_XTENSA_DIFF16", - "R_XTENSA_DIFF32", - "R_XTENSA_SLOT0_OP", - "R_XTENSA_SLOT1_OP", - "R_XTENSA_SLOT2_OP", - "R_XTENSA_SLOT3_OP", - "R_XTENSA_SLOT4_OP", - "R_XTENSA_SLOT5_OP", - "R_XTENSA_SLOT6_OP", - "R_XTENSA_SLOT7_OP", - "R_XTENSA_SLOT8_OP", - "R_XTENSA_SLOT9_OP", - "R_XTENSA_SLOT10_OP", - "R_XTENSA_SLOT11_OP", - "R_XTENSA_SLOT12_OP", - "R_XTENSA_SLOT13_OP", - "R_XTENSA_SLOT14_OP", - "R_XTENSA_SLOT0_ALT", - "R_XTENSA_SLOT1_ALT", - "R_XTENSA_SLOT2_ALT", - "R_XTENSA_SLOT3_ALT", - "R_XTENSA_SLOT4_ALT", - "R_XTENSA_SLOT5_ALT", - "R_XTENSA_SLOT6_ALT", - "R_XTENSA_SLOT7_ALT", - "R_XTENSA_SLOT8_ALT", - "R_XTENSA_SLOT9_ALT", - "R_XTENSA_SLOT10_ALT", - "R_XTENSA_SLOT11_ALT", - "R_XTENSA_SLOT12_ALT", - "R_XTENSA_SLOT13_ALT", - "R_XTENSA_SLOT14_ALT" + [0] "R_XTENSA_NONE", "R_XTENSA_32", + [2] "R_XTENSA_RTLD", "R_XTENSA_GLOB_DAT", + [4] "R_XTENSA_JMP_SLOT", "R_XTENSA_RELATIVE", + [6] "R_XTENSA_PLT", "R_XTENSA_UNUSED7", + [8] "R_XTENSA_OP0", "R_XTENSA_OP1", + [10] "R_XTENSA_OP2", "R_XTENSA_ASM_EXPAND", + [12] "R_XTENSA_ASM_SIMPLIFY", "R_XTENSA_UNUSED13", + [14] "R_XTENSA_UNUSED14", "R_XTENSA_GNU_VTINHERIT", + [16] "R_XTENSA_GNU_VTENTRY", "R_XTENSA_DIFF8", + [18] "R_XTENSA_DIFF16", "R_XTENSA_DIFF32", + [20] "R_XTENSA_SLOT0_OP", "R_XTENSA_SLOT1_OP", + [22] "R_XTENSA_SLOT2_OP", "R_XTENSA_SLOT3_OP", + [24] "R_XTENSA_SLOT4_OP", "R_XTENSA_SLOT5_OP", + [26] "R_XTENSA_SLOT6_OP", "R_XTENSA_SLOT7_OP", + [28] "R_XTENSA_SLOT8_OP", "R_XTENSA_SLOT9_OP", + [30] "R_XTENSA_SLOT10_OP", "R_XTENSA_SLOT11_OP", + [32] "R_XTENSA_SLOT12_OP", "R_XTENSA_SLOT13_OP", + [34] "R_XTENSA_SLOT14_OP", "R_XTENSA_SLOT0_ALT", + [36] "R_XTENSA_SLOT1_ALT", "R_XTENSA_SLOT2_ALT", + [38] "R_XTENSA_SLOT3_ALT", "R_XTENSA_SLOT4_ALT", + [40] "R_XTENSA_SLOT5_ALT", "R_XTENSA_SLOT6_ALT", + [42] "R_XTENSA_SLOT7_ALT", "R_XTENSA_SLOT8_ALT", + [44] "R_XTENSA_SLOT9_ALT", "R_XTENSA_SLOT10_ALT", + [46] "R_XTENSA_SLOT11_ALT", "R_XTENSA_SLOT12_ALT", + [48] "R_XTENSA_SLOT13_ALT", "R_XTENSA_SLOT14_ALT", + [50] "R_XTENSA_TLSDESC_FN", "R_XTENSA_TLSDESC_ARG", + [52] "R_XTENSA_TLS_TPOFF" }; diff --git a/ldso/ldso/xtensa/dl-startup.h b/ldso/ldso/xtensa/dl-startup.h index b135a4cb8..70a6255d9 100644 --- a/ldso/ldso/xtensa/dl-startup.h +++ b/ldso/ldso/xtensa/dl-startup.h @@ -11,7 +11,7 @@ __asm__ ( " .text\n" " .align 4\n" - " .literal_position\n" + " .literal_position\n" " .global _start\n" " .type _start, @function\n" " .hidden _start\n" diff --git a/ldso/ldso/xtensa/dl-sysdep.h b/ldso/ldso/xtensa/dl-sysdep.h index a0ed4e5f2..148de5b95 100644 --- a/ldso/ldso/xtensa/dl-sysdep.h +++ b/ldso/ldso/xtensa/dl-sysdep.h @@ -78,10 +78,13 @@ typedef struct xtensa_got_location_struct { struct elf_resolve; extern unsigned long _dl_linux_resolver (struct elf_resolve *, int); -/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so - undefined references should not be allowed to define the value. */ +/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or + TLS variable, so undefined references should not be allowed to define + the value. */ #define elf_machine_type_class(type) \ - (((type) == R_XTENSA_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) + (((type) == R_XTENSA_JMP_SLOT || (type) == R_XTENSA_TLS_TPOFF \ + || (type) == R_XTENSA_TLSDESC_FN || (type) == R_XTENSA_TLSDESC_ARG) \ + * ELF_RTYPE_CLASS_PLT) /* Return the link-time address of _DYNAMIC. */ static __always_inline Elf32_Addr diff --git a/ldso/ldso/xtensa/dl-tlsdesc.S b/ldso/ldso/xtensa/dl-tlsdesc.S new file mode 100644 index 000000000..a6ebc949e --- /dev/null +++ b/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 + . */ + +#include +#include +#include "tlsdesc.h" + + + .text + .align 4 + .hidden _dl_tlsdesc_return + .global _dl_tlsdesc_return + .type _dl_tlsdesc_return, @function +_dl_tlsdesc_return: + entry a1, 16 + rur.threadptr a3 + add a2, a2, a3 + retw + .size _dl_tlsdesc_return, .-_dl_tlsdesc_return + +#ifdef SHARED + + + /* This function is used for symbols that need dynamic TLS. + + The argument passed to this function points to the TLS descriptor. + + The assembly code that follows is a rendition of the following + C code, hand-optimized a little bit. + + ptrdiff_t + _dl_tlsdesc_dynamic(struct tlsdesc_dynamic_arg *td) + { + dtv_t *dtv = (dtv_t *)THREAD_DTV(); + if (td->gen_count <= dtv[0].counter + && dtv[td->tlsinfo.ti_module].pointer.val + != TLS_DTV_UNALLOCATED) + return dtv[td->tlsinfo.ti_module].pointer.val + + td->tlsinfo.ti_offset - __builtin_thread_pointer(); + return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer(); + } + */ + + .align 4 + .hidden _dl_tlsdesc_dynamic + .global _dl_tlsdesc_dynamic + .type _dl_tlsdesc_dynamic, @function +_dl_tlsdesc_dynamic: + entry a1, 32 + + /* dtv_t *dtv = (dtv_t *)THREAD_DTV(); */ + rur.threadptr a3 + l32i a4, a3, 0 + + /* if (td->gen_count <= dtv[0].counter */ + l32i a6, a2, TLSDESC_GEN_COUNT + l32i a7, a4, 0 + blt a7, a6, .Lslow + + /* && dtv[td->tlsinfo.ti_module].pointer.val != TLS_DTV_UNALLOCATED) */ + l32i a6, a2, TLSDESC_MODID + addx8 a6, a3, a6 + l32i a6, a6, 0 + beqi a6, -1, .Lslow + + /* return dtv[td->tlsinfo.ti_module].pointer.val + + td->tlsinfo.ti_offset - __builtin_thread_pointer(); */ + l32i a6, a2, TLSDESC_MODOFF + sub a2, a6, a3 + retw + + /* return __tls_get_addr (&td->tlsinfo) - __builtin_thread_pointer(); */ +.Lslow: + mov a10, a2 + movi a8, __tls_get_addr + callx8 a8 + sub a2, a10, a3 + retw + .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic + +#endif /* SHARED */ diff --git a/ldso/ldso/xtensa/elfinterp.c b/ldso/ldso/xtensa/elfinterp.c index b4cf9752d..1397e95c9 100644 --- a/ldso/ldso/xtensa/elfinterp.c +++ b/ldso/ldso/xtensa/elfinterp.c @@ -31,6 +31,8 @@ */ #include "ldso.h" +#include "dl-tls.h" +#include "tlsdeschtab.h" unsigned long _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry) @@ -146,6 +148,9 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, int reloc_type; int symtab_index; char *symname; +#if defined USE_TLS && USE_TLS + struct elf_resolve *tls_tpnt = NULL; +#endif struct symbol_ref sym_ref; ElfW(Addr) *reloc_addr; ElfW(Addr) symbol_addr; @@ -172,15 +177,22 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, * here, so all bases should be covered. */ if (unlikely (!symbol_addr && + ELF_ST_TYPE (sym_ref.sym->st_info) != STT_TLS && ELF_ST_BIND (sym_ref.sym->st_info) != STB_WEAK)) { - _dl_dprintf (2, "%s: can't resolve symbol '%s'\n", - _dl_progname, symname); - _dl_exit (1); + return 1; } if (_dl_trace_prelink) { _dl_debug_lookup (symname, tpnt, &symtab[symtab_index], &sym_ref, elf_machine_type_class(reloc_type)); } +#if defined USE_TLS && USE_TLS + tls_tpnt = sym_ref.tpnt; +#endif + } else { + symbol_addr =symtab[symtab_index].st_value; +#if defined USE_TLS && USE_TLS + tls_tpnt = tpnt; +#endif } #if defined (__SUPPORT_LD_DEBUG__) @@ -198,8 +210,8 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, case R_XTENSA_RTLD: if (rpnt->r_addend == 1) { - /* Grab the function pointer stashed at the beginning of the - GOT by the GOT_INIT function. */ + /* Grab the function pointer stashed at the beginning + of the GOT by the GOT_INIT function. */ *reloc_addr = *(ElfW(Addr) *) tpnt->dynamic_info[DT_PLTGOT]; } else if (rpnt->r_addend == 2) { /* Store the link map for the object. */ @@ -213,6 +225,35 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, *reloc_addr += tpnt->loadaddr + rpnt->r_addend; break; +#if defined USE_TLS && USE_TLS + case R_XTENSA_TLS_TPOFF: + CHECK_STATIC_TLS((struct link_map *) tls_tpnt); + *reloc_addr = symbol_addr + tls_tpnt->l_tls_offset + rpnt->r_addend; + break; + case R_XTENSA_TLSDESC_FN: +#ifndef SHARED + CHECK_STATIC_TLS((struct link_map *) tls_tpnt); +#else + if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt)) + *reloc_addr = (ElfW(Addr)) _dl_tlsdesc_dynamic; + else +#endif + *reloc_addr = (ElfW(Addr)) _dl_tlsdesc_return; + break; + case R_XTENSA_TLSDESC_ARG: +#ifndef SHARED + CHECK_STATIC_TLS((struct link_map *) tls_tpnt); +#else + if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt)) + *reloc_addr = (ElfW(Addr)) + _dl_make_tlsdesc_dynamic((struct link_map *) tls_tpnt, + symbol_addr + *reloc_addr); + else +#endif + *reloc_addr += symbol_addr + tls_tpnt->l_tls_offset; + break; +#endif + default: return -1; /* Calls _dl_exit(1). */ } diff --git a/libc/sysdeps/linux/xtensa/Makefile.arch b/libc/sysdeps/linux/xtensa/Makefile.arch index 277a1e325..b9b6b87d5 100644 --- a/libc/sysdeps/linux/xtensa/Makefile.arch +++ b/libc/sysdeps/linux/xtensa/Makefile.arch @@ -5,7 +5,10 @@ # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # -CSRC-y := brk.c fork.c sigaction.c __syscall_error.c +CSRC-y := brk.c sigaction.c __syscall_error.c SSRC-y := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S \ sigrestorer.S syscall.S mmap.S windowspill.S __longjmp.S vfork.S + +CSRC-$(if $(UCLIBC_HAS_THREADS_NATIVE),,y) += fork.c +SSRC-$(if $(UCLIBC_HAS_THREADS_NATIVE),,y) += clone.S diff --git a/libc/sysdeps/linux/xtensa/clone.S b/libc/sysdeps/linux/xtensa/clone.S index aa79aa736..34d68a875 100644 --- a/libc/sysdeps/linux/xtensa/clone.S +++ b/libc/sysdeps/linux/xtensa/clone.S @@ -1,34 +1,38 @@ -/* Copyright (C) 2001, 2005, 2007 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2005 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + Library General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ /* clone is even more special than fork as it mucks with stacks - and invokes a function in the right context after it's all over. */ + and invokes a function in the right context after its all over. */ -#include "sysdep.h" -#include +#include +#include #define _ERRNO_H 1 #include +#ifdef RESET_PID +#include +#endif +#define __ASSEMBLY__ +#include -/* int clone (a2 = int (*fn)(void *arg), - a3 = void *child_stack, - a4 = int flags, - a5 = void *arg, - a6 = pid_t *ptid, - a7 = struct user_desc *tls, - 16(sp) = pid_t *ctid) */ +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, + a2 a3 a4 a5 + pid_t *ptid, struct user_desc *tls, pid_t *ctid) + a6 a7 16(sp) +*/ .text ENTRY (__clone) @@ -39,7 +43,7 @@ ENTRY (__clone) /* a2 and a3 are candidates for destruction by system-call return parameters. We don't need the stack pointer after the system - call. We trust that the kernel will preserve a7, a9, and a6. */ + call. We trust that the kernel will preserve a6, a7 and a9. */ mov a9, a5 /* save function argument */ mov a5, a7 @@ -48,19 +52,18 @@ ENTRY (__clone) mov a6, a4 mov a4, a8 l32i a8, a1, 16 /* child_tid */ - movi a2, SYS_ify (clone) - - /* syscall (a2 = NR_clone, - a6 = clone_flags, - a3 = usp, - a4 = parent_tid, - a5 = child_tls, - a8 = child_tid) */ + movi a2, SYS_ify(clone) + + /* syscall(NR_clone,clone_flags, usp, parent_tid, child_tls, child_tid) + a2 a6 a3 a4 a5 a8 + */ + syscall bltz a2, SYSCALL_ERROR_LABEL beqz a2, .Lthread_start - /* Fall through for parent. */ + /* fall through for parent */ + .Lpseudo_end: retw @@ -69,32 +72,38 @@ ENTRY (__clone) j SYSCALL_ERROR_LABEL .Lthread_start: - /* Start child thread. */ - movi a0, 0 /* terminate the stack frame */ + +#if CLONE_THREAD != 0x00010000 || CLONE_VM != 0x00000100 +# error invalid values for CLONE_THREAD or CLONE_VM +#endif #ifdef RESET_PID - /* Check and see if we need to reset the PID. */ - bbsi.l a6, 16, 1f /* CLONE_THREAD = 0x00010000 */ + bbsi.l a6, 16, .Lskip_restore_pid /* CLONE_THREAD = 0x00010000 */ movi a2, -1 - bbsi.l a6, 8, 2f /* CLONE_VM = 0x00000100 */ - movi a2, SYS_ify (getpid) + bbsi a6, 8, .Lgotpid /* CLONE_VM = 0x00000100 */ + movi a2, SYS_ify(getpid) syscall -2: rur a3, THREADPTR - movi a4, PID_OFFSET - add a4, a4, a3 - s32i a2, a4, 0 - movi a4, TID_OFFSET - add a4, a4, a3 - s32i a2, a3, 0 -1: -#endif /* RESET_PID */ - +.Lgotpid: + rur a3, threadptr + movi a0, TLS_PRE_TCB_SIZE + sub a3, a3, a0 + s32i a2, a3, PID + s32i a2, a3, TID +.Lskip_restore_pid: +#endif + + /* start child thread */ + movi a0, 0 /* terminate the stack frame */ mov a6, a9 /* load up the 'arg' parameter */ callx4 a7 /* call the user's function */ /* Call _exit. Note that any return parameter from the user's - function in a6 is seen as inputs to _exit. */ - movi a2, JUMPTARGET(_exit) + function in a6 is seen as inputs to _exit. */ +#ifdef PIC + movi a2, _exit@PLT +#else + movi a2, _exit +#endif callx4 a2 PSEUDO_END (__clone) diff --git a/libc/sysdeps/linux/xtensa/fork.c b/libc/sysdeps/linux/xtensa/fork.c index e9b681c67..4e4f937a0 100644 --- a/libc/sysdeps/linux/xtensa/fork.c +++ b/libc/sysdeps/linux/xtensa/fork.c @@ -20,6 +20,10 @@ pid_t fork(void) { return (pid_t) INLINE_SYSCALL(clone, 2, SIGCHLD, 0); } -lt_strong_alias(fork) -lt_libc_hidden(fork) +# ifdef __UCLIBC_HAS_THREADS__ +strong_alias(fork,__libc_fork) +libc_hidden_weak(fork) +# else +libc_hidden_def(fork) +# endif #endif diff --git a/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h b/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h index 41f81dbad..4516d9398 100644 --- a/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h +++ b/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 - . */ - -/* Test if longjmp to JMPBUF would unwind the frame containing a local - variable at ADDRESS. */ - +/* + * Copyright (C) 2000-2006 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ #include #include +/* Test if longjmp to JMPBUF would unwind the frame + containing a local variable at ADDRESS. */ #define _JMPBUF_UNWINDS(jmpbuf, address) \ ((void *) (address) < (void *) (jmpbuf)[JB_SP]) + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include +#include + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) +#endif diff --git a/libc/sysdeps/linux/xtensa/sys/ptrace.h b/libc/sysdeps/linux/xtensa/sys/ptrace.h new file mode 100644 index 000000000..882b8c8ed --- /dev/null +++ b/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 + . */ + +#ifndef _SYS_PTRACE_H +#define _SYS_PTRACE_H 1 + +#include + +/* Kludge away careless namespace pollution from the kernel. */ + +#undef PTRACE_GETREGS +#undef PTRACE_SETREGS +#undef PTRACE_GETFPREGS +#undef PTRACE_SETFPREGS +#undef PTRACE_GETFPREGSIZE + + +__BEGIN_DECLS + +/* Type of the REQUEST argument to `ptrace.' */ +enum __ptrace_request +{ + /* Indicate that the process making this request should be traced. + All signals received by this process can be intercepted by its + parent, and its parent can use the other `ptrace' requests. */ + PTRACE_TRACEME = 0, +#define PT_TRACE_ME PTRACE_TRACEME + + /* Return the word in the process's text space at address ADDR. */ + PTRACE_PEEKTEXT = 1, +#define PT_READ_I PTRACE_PEEKTEXT + + /* Return the word in the process's data space at address ADDR. */ + PTRACE_PEEKDATA = 2, +#define PT_READ_D PTRACE_PEEKDATA + + /* Return the word in the process's user area at offset ADDR. */ + PTRACE_PEEKUSER = 3, +#define PT_READ_U PTRACE_PEEKUSER + + /* Write the word DATA into the process's text space at address ADDR. */ + PTRACE_POKETEXT = 4, +#define PT_WRITE_I PTRACE_POKETEXT + + /* Write the word DATA into the process's data space at address ADDR. */ + PTRACE_POKEDATA = 5, +#define PT_WRITE_D PTRACE_POKEDATA + + /* Write the word DATA into the process's user area at offset ADDR. */ + PTRACE_POKEUSER = 6, +#define PT_WRITE_U PTRACE_POKEUSER + + /* Continue the process. */ + PTRACE_CONT = 7, +#define PT_CONTINUE PTRACE_CONT + + /* Kill the process. */ + PTRACE_KILL = 8, +#define PT_KILL PTRACE_KILL + + /* Single step the process. + This is not supported on all machines. */ + PTRACE_SINGLESTEP = 9, +#define PT_STEP PTRACE_SINGLESTEP + + /* Get all general purpose registers used by a processes. + This is not supported on all machines. */ + PTRACE_GETREGS = 12, +#define PT_GETREGS PTRACE_GETREGS + + /* Set all general purpose registers used by a processes. + This is not supported on all machines. */ + PTRACE_SETREGS = 13, +#define PT_SETREGS PTRACE_SETREGS + + /* Get all floating point registers used by a processes. + This is not supported on all machines. */ + PTRACE_GETFPREGS = 14, +#define PT_GETFPREGS PTRACE_GETFPREGS + + /* Set all floating point registers used by a processes. + This is not supported on all machines. */ + PTRACE_SETFPREGS = 15, +#define PT_SETFPREGS PTRACE_SETFPREGS + + /* Attach to a process that is already running. */ + PTRACE_ATTACH = 16, +#define PT_ATTACH PTRACE_ATTACH + + /* Detach from a process attached to with PTRACE_ATTACH. */ + PTRACE_DETACH = 17, +#define PT_DETACH PTRACE_DETACH + + /* Get size required for the buffer holding the floating point registers. + This is not supported on all machines. */ + PTRACE_GETFPREGSIZE = 18, +#define PT_GETFPREGSIZE PTRACE_GETFPREGSIZE + + /* Continue and stop at the next (return from) syscall. */ + PTRACE_SYSCALL = 24 +#define PT_SYSCALL PTRACE_SYSCALL +}; + +/* Options set using PTRACE_SETOPTIONS. */ +enum __ptrace_setoptions { + PTRACE_O_TRACESYSGOOD = 0x00000001, + PTRACE_O_TRACEFORK = 0x00000002, + PTRACE_O_TRACEVFORK = 0x00000004, + PTRACE_O_TRACECLONE = 0x00000008, + PTRACE_O_TRACEEXEC = 0x00000010, + PTRACE_O_TRACEVFORKDONE = 0x00000020, + PTRACE_O_TRACEEXIT = 0x00000040, + PTRACE_O_MASK = 0x0000007f +}; + +/* Wait extended result codes for the above trace options. */ +enum __ptrace_eventcodes { + PTRACE_EVENT_FORK = 1, + PTRACE_EVENT_VFORK = 2, + PTRACE_EVENT_CLONE = 3, + PTRACE_EVENT_EXEC = 4, + PTRACE_EVENT_VFORK_DONE = 5, + PTRACE_EVENT_EXIT = 6 +}; + +/* Perform process tracing functions. REQUEST is one of the values + above, and determines the action to be taken. + For all requests except PTRACE_TRACEME, PID specifies the process to be + traced. + + PID and the other arguments described above for the various requests should + appear (those that are used for the particular request) as: + pid_t PID, void *ADDR, int DATA, void *ADDR2 + after REQUEST. */ +extern long int ptrace (enum __ptrace_request __request, ...) __THROW; + +__END_DECLS + +#endif /* _SYS_PTRACE_H */ diff --git a/libc/sysdeps/linux/xtensa/sysdep.h b/libc/sysdeps/linux/xtensa/sysdep.h index afe95cc6a..cab4a2f8d 100644 --- a/libc/sysdeps/linux/xtensa/sysdep.h +++ b/libc/sysdeps/linux/xtensa/sysdep.h @@ -16,6 +16,10 @@ License along with the GNU C Library; if not, see . */ +#ifndef _LINUX_XTENSA_SYSDEP_H +#define _LINUX_XTENSA_SYSDEP_H 1 + +#include #include #ifdef __ASSEMBLER__ @@ -24,12 +28,6 @@ #define ASM_TYPE_DIRECTIVE(name, typearg) .type name, typearg #define ASM_SIZE_DIRECTIVE(name) .size name, . - name -#ifdef __STDC__ -#define C_LABEL(name) name : -#else -#define C_LABEL(name) name/**/: -#endif - #define ENTRY(name) \ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name), @function); \ @@ -52,6 +50,15 @@ #undef END #define END(name) ASM_SIZE_DIRECTIVE(name) +/* Local label name for asm code. */ +#ifndef L +# ifdef HAVE_ELF +# define L(name) .L##name +# else +# define L(name) name +# endif +#endif + /* Define a macro for this directive so it can be removed in a few places. */ #define LITERAL_POSITION .literal_position @@ -123,19 +130,7 @@ #define PSEUDO_END_ERRVAL(name) \ END (name) -#undef ret_ERRVAL -#define ret_ERRVAL retw - -#if defined RTLD_PRIVATE_ERRNO -# define SYSCALL_ERROR_HANDLER \ -0: movi a4, rtld_errno; \ - neg a2, a2; \ - s32i a2, a4, 0; \ - movi a2, -1; \ - j .Lpseudo_end; - -#elif defined _LIBC_REENTRANT - +#if defined _LIBC_REENTRANT # if defined USE___THREAD # ifndef NOT_IN_libc # define SYSCALL_ERROR_ERRNO __libc_errno @@ -170,3 +165,9 @@ #endif /* _LIBC_REENTRANT */ #endif /* __ASSEMBLER__ */ + +/* Pointer mangling is not yet supported for Xtensa. */ +#define PTR_MANGLE(var) (void) (var) +#define PTR_DEMANGLE(var) (void) (var) + +#endif /* _LINUX_XTENSA_SYSDEP_H */ diff --git a/libc/sysdeps/linux/xtensa/vfork.S b/libc/sysdeps/linux/xtensa/vfork.S index f094ae38f..6aced0a50 100644 --- a/libc/sysdeps/linux/xtensa/vfork.S +++ b/libc/sysdeps/linux/xtensa/vfork.S @@ -1,4 +1,4 @@ -/* Copyright (C) 2005, 2007 Free Software Foundation, Inc. +/* Copyright (C) 2005-2013 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -19,72 +19,67 @@ #include #define _SIGNAL_H #include +#define __ASSEMBLY__ +#include -/* Clone the calling process, but without copying the whole address space. +/* + Clone the calling process, but without copying the whole address space. The calling process is suspended until the new process exits or is replaced by a call to `execve'. Return -1 for errors, 0 to the new process, and the process ID of the new process to the old process. Note that it is important that we don't create a new stack frame for the - caller. */ + caller. - -/* The following are defined in linux/sched.h, which unfortunately - is not safe for inclusion in an assembly file. */ -#define CLONE_VM 0x00000100 /* set if VM shared between processes */ -#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to - wake it up on mm_release */ +*/ #ifndef SAVE_PID -#define SAVE_PID +#define SAVE_PID(a,b,c,d) #endif - #ifndef RESTORE_PID -#define RESTORE_PID +#define RESTORE_PID(a,b,c) +#endif +#ifndef RESTORE_PID12 +#define RESTORE_PID12(a,b,c) #endif +/* + pid_t vfork(void); + Implemented as __clone_syscall(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) + */ -/* pid_t vfork(void); - Implemented as __clone_syscall(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) */ HIDDEN_ENTRY (__vfork) + .literal .Ljumptable, 0, .L4, .L8, .L12 - movi a6, .Ljumptable - extui a2, a0, 30, 2 /* call-size: call4/8/12 = 1/2/3 */ - addx4 a4, a2, a6 /* find return address in jumptable */ - l32i a4, a4, 0 - add a4, a4, a6 - + mov a3, a0 # move return address out of the way + movi a0, .Ljumptable + extui a2, a3, 30, 2 # call-size: call4/8/12 = 1/2/3 + addx4 a0, a2, a0 # find return address in jumptable slli a2, a2, 30 - xor a3, a0, a2 /* remove call-size from return addr */ - extui a5, a4, 30, 2 /* get high bits of jump target */ - slli a5, a5, 30 - or a3, a3, a5 /* stuff them into the return address */ - xor a4, a4, a5 /* clear high bits of jump target */ - or a0, a4, a2 /* create temporary return address */ - retw /* "return" to .L4, .L8, or .L12 */ - - .align 4 -.Ljumptable: - .word 0 - .word .L4 - .Ljumptable - .word .L8 - .Ljumptable - .word .L12 - .Ljumptable + l32i a0, a0, 0 + + xor a3, a3, a2 # remove call-size from return address + or a0, a0, a2 # create temporary return address + retw /* a7: return address */ + .L4: mov a12, a2 mov a13, a3 - SAVE_PID + SAVE_PID(a5,a15,a2,a3) + + /* use syscall 'clone' and set new stack pointer to the same address */ - /* Use syscall 'clone'. Set new stack pointer to the same address. */ - movi a2, SYS_ify (clone) + movi a2, SYS_ify(clone) movi a3, 0 movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD + syscall - RESTORE_PID + RESTORE_PID(a5,a15,a2) movi a5, -4096 @@ -94,22 +89,24 @@ HIDDEN_ENTRY (__vfork) bgeu a6, a5, 1f jx a7 -1: call4 .Lerr /* returns to original caller */ +1: call4 .Lerr /* a11: return address */ + .L8: mov a12, a2 mov a13, a3 mov a14, a6 - SAVE_PID + SAVE_PID(a9,a15,a2,a3) - movi a2, SYS_ify (clone) + movi a2, SYS_ify(clone) movi a3, 0 movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD + syscall - RESTORE_PID + RESTORE_PID(a9,a15,a2) movi a9, -4096 @@ -120,22 +117,25 @@ HIDDEN_ENTRY (__vfork) bgeu a10, a9, 1f jx a11 -1: call8 .Lerr /* returns to original caller */ + +1: call8 .Lerr /* a15: return address */ + .L12: mov a12, a2 mov a13, a3 mov a14, a6 - SAVE_PID + SAVE_PID (a2,a3,a2,a6) - movi a2, SYS_ify (clone) + movi a2, SYS_ify(clone) movi a3, 0 movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD + syscall - RESTORE_PID + RESTORE_PID12(a3,a6,a15) mov a3, a13 movi a13, -4096 @@ -147,18 +147,18 @@ HIDDEN_ENTRY (__vfork) bgeu a14, a13, 1f jx a15 -1: call12 .Lerr /* returns to original caller */ +1: call12 .Lerr .align 4 + .Lerr: entry a1, 16 - /* Restore the return address. */ - extui a4, a0, 30, 2 /* get the call-size bits */ + /* Restore return address */ + + extui a4, a0, 30, 2 slli a4, a4, 30 - slli a3, a3, 2 /* clear high bits of target address */ - srli a3, a3, 2 - or a0, a3, a4 /* combine them */ + or a0, a3, a4 PSEUDO_END (__vfork) .Lpseudo_end: diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c index 2a5bf6dd9..75369bd70 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c @@ -22,8 +22,6 @@ #include #include #include -#include - void #ifndef IS_IN_libpthread diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/Makefile.arch new file mode 100644 index 000000000..8ebe28773 --- /dev/null +++ b/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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/pthreadtypes.h new file mode 100644 index 000000000..5e4402088 --- /dev/null +++ b/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 + . */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +union pthread_attr_t +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +}; +#ifndef __have_pthread_attr_t +typedef union pthread_attr_t pthread_attr_t; +# define __have_pthread_attr_t 1 +#endif + + +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned char __pad1; + unsigned char __pad2; + unsigned char __shared; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned char __flags; +#else + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned char __flags; + unsigned char __shared; + unsigned char __pad1; + unsigned char __pad2; +#endif + int __writer; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/bits/semaphore.h new file mode 100644 index 000000000..8845cf009 --- /dev/null +++ b/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 directly; include instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/xtensa/clone.S new file mode 100644 index 00