summaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/i386/Makefile10
-rw-r--r--sysdeps/i386/bits/byteswap.h4
-rw-r--r--sysdeps/i386/bits/linkmap.h1
-rw-r--r--sysdeps/i386/dl-lookupcfg.h28
-rw-r--r--sysdeps/i386/dl-machine.h131
-rw-r--r--sysdeps/i386/dl-tls.h2
-rw-r--r--sysdeps/i386/dl-tlsdesc.S290
-rw-r--r--sysdeps/i386/dl-tlsdesc.h61
-rw-r--r--sysdeps/i386/tlsdesc.c269
-rw-r--r--sysdeps/i386/tlsdesc.sym17
-rw-r--r--sysdeps/ia64/bits/byteswap.h4
-rw-r--r--sysdeps/ieee754/flt-32/w_expf.c2
-rw-r--r--sysdeps/ieee754/ldbl-128/e_j0l.c4
-rw-r--r--sysdeps/ieee754/ldbl-128/e_j1l.c4
-rw-r--r--sysdeps/ieee754/ldbl-128/s_expm1l.c2
-rw-r--r--sysdeps/ieee754/ldbl-128/s_log1pl.c9
-rw-r--r--sysdeps/mach/hurd/bits/ioctls.h56
-rw-r--r--sysdeps/posix/getaddrinfo.c261
-rw-r--r--sysdeps/s390/bits/byteswap.h4
-rw-r--r--sysdeps/sparc/sparc32/Makefile4
-rw-r--r--sysdeps/sparc/sparc64/Makefile4
-rw-r--r--sysdeps/unix/sysv/linux/alpha/bits/resource.h10
-rw-r--r--sysdeps/unix/sysv/linux/bits/resource.h10
-rw-r--r--sysdeps/unix/sysv/linux/bits/socket.h4
-rw-r--r--sysdeps/unix/sysv/linux/dl-osinfo.h1
-rw-r--r--sysdeps/unix/sysv/linux/sparc/bits/resource.h10
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/Makefile4
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/getcontext.S85
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/makecontext.c93
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/setcontext.S119
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/swapcontext.S119
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S1
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/ucontext_i.sym61
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S1
-rw-r--r--sysdeps/unix/sysv/linux/sys/user.h2
-rw-r--r--sysdeps/unix/sysv/linux/times.c59
-rw-r--r--sysdeps/x86_64/Makefile10
-rw-r--r--sysdeps/x86_64/bits/byteswap.h4
-rw-r--r--sysdeps/x86_64/bits/linkmap.h2
-rw-r--r--sysdeps/x86_64/dl-lookupcfg.h28
-rw-r--r--sysdeps/x86_64/dl-machine.h53
-rw-r--r--sysdeps/x86_64/dl-tls.h4
-rw-r--r--sysdeps/x86_64/dl-tlsdesc.S245
-rw-r--r--sysdeps/x86_64/dl-tlsdesc.h64
-rw-r--r--sysdeps/x86_64/tlsdesc.c151
-rw-r--r--sysdeps/x86_64/tlsdesc.sym17
46 files changed, 2179 insertions, 145 deletions
diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile
index e192b91dbd..5f0d9bea21 100644
--- a/sysdeps/i386/Makefile
+++ b/sysdeps/i386/Makefile
@@ -73,3 +73,13 @@ CFLAGS-.o += -mno-tls-direct-seg-refs
CPPFLAGS-.oS += -DNO_TLS_DIRECT_SEG_REFS
CFLAGS-.oS += -mno-tls-direct-seg-refs
endif
+
+ifeq ($(subdir),elf)
+sysdep-dl-routines += tlsdesc dl-tlsdesc
+sysdep_routines += tlsdesc dl-tlsdesc
+sysdep-rtld-routines += tlsdesc dl-tlsdesc
+endif
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tlsdesc.sym
+endif
diff --git a/sysdeps/i386/bits/byteswap.h b/sysdeps/i386/bits/byteswap.h
index 7f2ddc2dc5..1f3fc5e524 100644
--- a/sysdeps/i386/bits/byteswap.h
+++ b/sysdeps/i386/bits/byteswap.h
@@ -1,5 +1,5 @@
/* Macros to swap the order of bytes in integer values.
- Copyright (C) 1997, 1998, 2000, 2002, 2003, 2006, 2007
+ Copyright (C) 1997, 1998, 2000, 2002, 2003, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,7 +18,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#if !defined _BYTESWAP_H && !defined _NETINET_IN_H
+#if !defined _BYTESWAP_H && !defined _NETINET_IN_H && !defined _ENDIAN_H
# error "Never use <bits/byteswap.h> directly; include <byteswap.h> instead."
#endif
diff --git a/sysdeps/i386/bits/linkmap.h b/sysdeps/i386/bits/linkmap.h
index 3be9b7eae8..978d52621e 100644
--- a/sysdeps/i386/bits/linkmap.h
+++ b/sysdeps/i386/bits/linkmap.h
@@ -2,4 +2,5 @@ struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 0x16 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
+ void *tlsdesc_table; /* Address of TLS descriptor hash table. */
};
diff --git a/sysdeps/i386/dl-lookupcfg.h b/sysdeps/i386/dl-lookupcfg.h
new file mode 100644
index 0000000000..2af2b9e8fa
--- /dev/null
+++ b/sysdeps/i386/dl-lookupcfg.h
@@ -0,0 +1,28 @@
+/* Configuration of lookup functions.
+ Copyright (C) 2005, 2008 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 DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+struct link_map;
+
+extern void internal_function _dl_unmap (struct link_map *map);
+
+#define DL_UNMAP(map) _dl_unmap (map)
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index 04296d2a9a..e3342d8e12 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -25,6 +25,7 @@
#include <sys/param.h>
#include <sysdep.h>
#include <tls.h>
+#include <dl-tlsdesc.h>
/* Return nonzero iff ELF header is compatible with the running host. */
static inline int __attribute__ ((unused))
@@ -246,7 +247,7 @@ _dl_start_user:\n\
# define elf_machine_type_class(type) \
((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32 \
|| (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32 \
- || (type) == R_386_TLS_TPOFF) \
+ || (type) == R_386_TLS_TPOFF || (type) == R_386_TLS_DESC) \
* ELF_RTYPE_CLASS_PLT) \
| (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
#else
@@ -373,6 +374,38 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
*reloc_addr = sym->st_value;
# endif
break;
+ case R_386_TLS_DESC:
+ {
+ struct tlsdesc volatile *td =
+ (struct tlsdesc volatile *)reloc_addr;
+
+# ifndef RTLD_BOOTSTRAP
+ if (! sym)
+ td->entry = _dl_tlsdesc_undefweak;
+ else
+# endif
+ {
+# ifndef RTLD_BOOTSTRAP
+# ifndef SHARED
+ CHECK_STATIC_TLS (map, sym_map);
+# else
+ if (!TRY_STATIC_TLS (map, sym_map))
+ {
+ td->arg = _dl_make_tlsdesc_dynamic
+ (sym_map, sym->st_value + (ElfW(Word))td->arg);
+ td->entry = _dl_tlsdesc_dynamic;
+ }
+ else
+# endif
+# endif
+ {
+ td->arg = (void*)(sym->st_value - sym_map->l_tls_offset
+ + (ElfW(Word))td->arg);
+ td->entry = _dl_tlsdesc_return;
+ }
+ }
+ break;
+ }
case R_386_TLS_TPOFF32:
/* The offset is positive, backward from the thread pointer. */
# ifdef RTLD_BOOTSTRAP
@@ -485,6 +518,41 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
Therefore the offset is already correct. */
*reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
break;
+ case R_386_TLS_DESC:
+ {
+ struct tlsdesc volatile *td =
+ (struct tlsdesc volatile *)reloc_addr;
+
+# ifndef RTLD_BOOTSTRAP
+ if (!sym)
+ {
+ td->arg = (void*)reloc->r_addend;
+ td->entry = _dl_tlsdesc_undefweak;
+ }
+ else
+# endif
+ {
+# ifndef RTLD_BOOTSTRAP
+# ifndef SHARED
+ CHECK_STATIC_TLS (map, sym_map);
+# else
+ if (!TRY_STATIC_TLS (map, sym_map))
+ {
+ td->arg = _dl_make_tlsdesc_dynamic
+ (sym_map, sym->st_value + reloc->r_addend);
+ td->entry = _dl_tlsdesc_dynamic;
+ }
+ else
+# endif
+# endif
+ {
+ td->arg = (void*)(sym->st_value - sym_map->l_tls_offset
+ + reloc->r_addend);
+ td->entry = _dl_tlsdesc_return;
+ }
+ }
+ }
+ break;
case R_386_TLS_TPOFF32:
/* The offset is positive, backward from the thread pointer. */
/* We know the offset of object the symbol is contained in.
@@ -578,6 +646,53 @@ elf_machine_lazy_rel (struct link_map *map,
*reloc_addr = (map->l_mach.plt
+ (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4);
}
+ else if (__builtin_expect (r_type == R_386_TLS_DESC, 1))
+ {
+ struct tlsdesc volatile * __attribute__((__unused__)) td =
+ (struct tlsdesc volatile *)reloc_addr;
+
+ /* Handle relocations that reference the local *ABS* in a simple
+ way, so as to preserve a potential addend. */
+ if (ELF32_R_SYM (reloc->r_info) == 0)
+ td->entry = _dl_tlsdesc_resolve_abs_plus_addend;
+ /* Given a known-zero addend, we can store a pointer to the
+ reloc in the arg position. */
+ else if (td->arg == 0)
+ {
+ td->arg = (void*)reloc;
+ td->entry = _dl_tlsdesc_resolve_rel;
+ }
+ else
+ {
+ /* We could handle non-*ABS* relocations with non-zero addends
+ by allocating dynamically an arg to hold a pointer to the
+ reloc, but that sounds pointless. */
+ const Elf32_Rel *const r = reloc;
+ /* The code below was borrowed from elf_dynamic_do_rel(). */
+ const ElfW(Sym) *const symtab =
+ (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+
+#ifdef RTLD_BOOTSTRAP
+ /* The dynamic linker always uses versioning. */
+ assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
+#else
+ if (map->l_info[VERSYMIDX (DT_VERSYM)])
+#endif
+ {
+ const ElfW(Half) *const version =
+ (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+ ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
+ elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
+ &map->l_versions[ndx],
+ (void *) (l_addr + r->r_offset));
+ }
+#ifndef RTLD_BOOTSTRAP
+ else
+ elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
+ (void *) (l_addr + r->r_offset));
+#endif
+ }
+ }
else
_dl_reloc_bad_type (map, r_type, 1);
}
@@ -589,6 +704,20 @@ __attribute__ ((always_inline))
elf_machine_lazy_rela (struct link_map *map,
Elf32_Addr l_addr, const Elf32_Rela *reloc)
{
+ Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
+ const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
+ if (__builtin_expect (r_type == R_386_JMP_SLOT, 1))
+ ;
+ else if (__builtin_expect (r_type == R_386_TLS_DESC, 1))
+ {
+ struct tlsdesc volatile * __attribute__((__unused__)) td =
+ (struct tlsdesc volatile *)reloc_addr;
+
+ td->arg = (void*)reloc;
+ td->entry = _dl_tlsdesc_resolve_rela;
+ }
+ else
+ _dl_reloc_bad_type (map, r_type, 1);
}
#endif /* !RTLD_BOOTSTRAP */
diff --git a/sysdeps/i386/dl-tls.h b/sysdeps/i386/dl-tls.h
index a1707197ce..58705c778d 100644
--- a/sysdeps/i386/dl-tls.h
+++ b/sysdeps/i386/dl-tls.h
@@ -19,7 +19,7 @@
/* Type used for the representation of TLS information in the GOT. */
-typedef struct
+typedef struct dl_tls_index
{
unsigned long int ti_module;
unsigned long int ti_offset;
diff --git a/sysdeps/i386/dl-tlsdesc.S b/sysdeps/i386/dl-tlsdesc.S
new file mode 100644
index 0000000000..db5005d9f4
--- /dev/null
+++ b/sysdeps/i386/dl-tlsdesc.S
@@ -0,0 +1,290 @@
+/* Thread-local storage handling in the ELF dynamic linker. i386 version.
+ Copyright (C) 2004, 2005, 2008 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 "tlsdesc.h"
+
+ .text
+
+ /* This function is used to compute the TP offset for symbols in
+ Static TLS, i.e., whose TP offset is the same for all
+ threads.
+
+ The incoming %eax points to the TLS descriptor, such that
+ 0(%eax) points to _dl_tlsdesc_return itself, and 4(%eax) holds
+ the TP offset of the symbol corresponding to the object
+ denoted by the argument. */
+
+ .hidden _dl_tlsdesc_return
+ .global _dl_tlsdesc_return
+ .type _dl_tlsdesc_return,@function
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_return:
+ movl 4(%eax), %eax
+ ret
+ cfi_endproc
+ .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
+
+ /* This function is used for undefined weak TLS symbols, for
+ which the base address (i.e., disregarding any addend) should
+ resolve to NULL.
+
+ %eax points to the TLS descriptor, such that 0(%eax) points to
+ _dl_tlsdesc_undefweak itself, and 4(%eax) holds the addend.
+ We return the addend minus the TP, such that, when the caller
+ adds TP, it gets the addend back. If that's zero, as usual,
+ that's most likely a NULL pointer. */
+
+ .hidden _dl_tlsdesc_undefweak
+ .global _dl_tlsdesc_undefweak
+ .type _dl_tlsdesc_undefweak,@function
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_undefweak:
+ movl 4(%eax), %eax
+ subl %gs:0, %eax
+ ret
+ cfi_endproc
+ .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
+
+#ifdef SHARED
+ .hidden _dl_tlsdesc_dynamic
+ .global _dl_tlsdesc_dynamic
+ .type _dl_tlsdesc_dynamic,@function
+
+ /* This function is used for symbols that need dynamic TLS.
+
+ %eax points to the TLS descriptor, such that 0(%eax) points to
+ _dl_tlsdesc_dynamic itself, and 4(%eax) points to a struct
+ tlsdesc_dynamic_arg object. It must return in %eax the offset
+ between the thread pointer and the object denoted by the
+ argument, without clobbering any registers.
+
+ The assembly code that follows is a rendition of the following
+ C code, hand-optimized a little bit.
+
+ptrdiff_t
+__attribute__ ((__regparm__ (1)))
+_dl_tlsdesc_dynamic (struct tlsdesc *tdp)
+{
+ struct tlsdesc_dynamic_arg *td = tdp->arg;
+ dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + DTV_OFFSET);
+ if (__builtin_expect (td->gen_count <= dtv[0].counter
+ && (dtv[td->tlsinfo.ti_module].pointer.val
+ != TLS_DTV_UNALLOCATED),
+ 1))
+ return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
+ - __thread_pointer;
+
+ return ___tls_get_addr (&td->tlsinfo) - __thread_pointer;
+}
+*/
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_dynamic:
+ /* Like all TLS resolvers, preserve call-clobbered registers.
+ We need two scratch regs anyway. */
+ subl $28, %esp
+ cfi_adjust_cfa_offset (28)
+ movl %ecx, 20(%esp)
+ movl %edx, 24(%esp)
+ movl TLSDESC_ARG(%eax), %eax
+ movl %gs:DTV_OFFSET, %edx
+ movl TLSDESC_GEN_COUNT(%eax), %ecx
+ cmpl (%edx), %ecx
+ ja .Lslow
+ movl TLSDESC_MODID(%eax), %ecx
+ movl (%edx,%ecx,8), %edx
+ cmpl $-1, %edx
+ je .Lslow
+ movl TLSDESC_MODOFF(%eax), %eax
+ addl %edx, %eax
+.Lret:
+ movl 20(%esp), %ecx
+ subl %gs:0, %eax
+ movl 24(%esp), %edx
+ addl $28, %esp
+ cfi_adjust_cfa_offset (-28)
+ ret
+ .p2align 4,,7
+.Lslow:
+ cfi_adjust_cfa_offset (28)
+ movl %ebx, 16(%esp)
+ call __i686.get_pc_thunk.bx
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ call ___tls_get_addr@PLT
+ movl 16(%esp), %ebx
+ jmp .Lret
+ cfi_endproc
+ .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
+#endif /* SHARED */
+
+ /* This function is a wrapper for a lazy resolver for TLS_DESC
+ REL relocations that reference the *ABS* segment in their own
+ link maps. %ebx points to the caller's GOT. %eax points to a
+ TLS descriptor, such that 0(%eax) holds the address of the
+ resolver wrapper itself (unless some other thread beat us to
+ it) and 4(%eax) holds the addend in the relocation.
+
+ When the actual resolver returns, it will have adjusted the
+ TLS descriptor such that we can tail-call it for it to return
+ the TP offset of the symbol. */
+
+ .hidden _dl_tlsdesc_resolve_abs_plus_addend
+ .global _dl_tlsdesc_resolve_abs_plus_addend
+ .type _dl_tlsdesc_resolve_abs_plus_addend,@function
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_resolve_abs_plus_addend:
+0:
+ pushl %eax
+ cfi_adjust_cfa_offset (4)
+ pushl %ecx
+ cfi_adjust_cfa_offset (4)
+ pushl %edx
+ cfi_adjust_cfa_offset (4)
+ movl $1f - 0b, %ecx
+ movl 4(%ebx), %edx
+ call _dl_tlsdesc_resolve_abs_plus_addend_fixup
+1:
+ popl %edx
+ cfi_adjust_cfa_offset (-4)
+ popl %ecx
+ cfi_adjust_cfa_offset (-4)
+ popl %eax
+ cfi_adjust_cfa_offset (-4)
+ jmp *(%eax)
+ cfi_endproc
+ .size _dl_tlsdesc_resolve_abs_plus_addend, .-_dl_tlsdesc_resolve_abs_plus_addend
+
+ /* This function is a wrapper for a lazy resolver for TLS_DESC
+ REL relocations that had zero addends. %ebx points to the
+ caller's GOT. %eax points to a TLS descriptor, such that
+ 0(%eax) holds the address of the resolver wrapper itself
+ (unless some other thread beat us to it) and 4(%eax) holds a
+ pointer to the relocation.
+
+ When the actual resolver returns, it will have adjusted the
+ TLS descriptor such that we can tail-call it for it to return
+ the TP offset of the symbol. */
+
+ .hidden _dl_tlsdesc_resolve_rel
+ .global _dl_tlsdesc_resolve_rel
+ .type _dl_tlsdesc_resolve_rel,@function
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_resolve_rel:
+0:
+ pushl %eax
+ cfi_adjust_cfa_offset (4)
+ pushl %ecx
+ cfi_adjust_cfa_offset (4)
+ pushl %edx
+ cfi_adjust_cfa_offset (4)
+ movl $1f - 0b, %ecx
+ movl 4(%ebx), %edx
+ call _dl_tlsdesc_resolve_rel_fixup
+1:
+ popl %edx
+ cfi_adjust_cfa_offset (-4)
+ popl %ecx
+ cfi_adjust_cfa_offset (-4)
+ popl %eax
+ cfi_adjust_cfa_offset (-4)
+ jmp *(%eax)
+ cfi_endproc
+ .size _dl_tlsdesc_resolve_rel, .-_dl_tlsdesc_resolve_rel
+
+ /* This function is a wrapper for a lazy resolver for TLS_DESC
+ RELA relocations. %ebx points to the caller's GOT. %eax
+ points to a TLS descriptor, such that 0(%eax) holds the
+ address of the resolver wrapper itself (unless some other
+ thread beat us to it) and 4(%eax) holds a pointer to the
+ relocation.
+
+ When the actual resolver returns, it will have adjusted the
+ TLS descriptor such that we can tail-call it for it to return
+ the TP offset of the symbol. */
+
+ .hidden _dl_tlsdesc_resolve_rela
+ .global _dl_tlsdesc_resolve_rela
+ .type _dl_tlsdesc_resolve_rela,@function
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_resolve_rela:
+0:
+ pushl %eax
+ cfi_adjust_cfa_offset (4)
+ pushl %ecx
+ cfi_adjust_cfa_offset (4)
+ pushl %edx
+ cfi_adjust_cfa_offset (4)
+ movl $1f - 0b, %ecx
+ movl 4(%ebx), %edx
+ call _dl_tlsdesc_resolve_rela_fixup
+1:
+ popl %edx
+ cfi_adjust_cfa_offset (-4)
+ popl %ecx
+ cfi_adjust_cfa_offset (-4)
+ popl %eax
+ cfi_adjust_cfa_offset (-4)
+ jmp *(%eax)
+ cfi_endproc
+ .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
+
+ /* This function is a placeholder for lazy resolving of TLS
+ relocations. Once some thread starts resolving a TLS
+ relocation, it sets up the TLS descriptor to use this
+ resolver, such that other threads that would attempt to
+ resolve it concurrently may skip the call to the original lazy
+ resolver and go straight to a condition wait.
+
+ When the actual resolver returns, it will have adjusted the
+ TLS descriptor such that we can tail-call it for it to return
+ the TP offset of the symbol. */
+
+ .hidden _dl_tlsdesc_resolve_hold
+ .global _dl_tlsdesc_resolve_hold
+ .type _dl_tlsdesc_resolve_hold,@function
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_resolve_hold:
+0:
+ pushl %eax
+ cfi_adjust_cfa_offset (4)
+ pushl %ecx
+ cfi_adjust_cfa_offset (4)
+ pushl %edx
+ cfi_adjust_cfa_offset (4)
+ movl $1f - 0b, %ecx
+ movl 4(%ebx), %edx
+ call _dl_tlsdesc_resolve_hold_fixup
+1:
+ popl %edx
+ cfi_adjust_cfa_offset (-4)
+ popl %ecx
+ cfi_adjust_cfa_offset (-4)
+ popl %eax
+ cfi_adjust_cfa_offset (-4)
+ jmp *(%eax)
+ cfi_endproc
+ .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold
diff --git a/sysdeps/i386/dl-tlsdesc.h b/sysdeps/i386/dl-tlsdesc.h
new file mode 100644
index 0000000000..df4a646fe9
--- /dev/null
+++ b/sysdeps/i386/dl-tlsdesc.h
@@ -0,0 +1,61 @@
+/* Thread-local storage descriptor handling in the ELF dynamic linker.
+ i386 version.
+ Copyright (C) 2005, 2008 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 _I386_DL_TLSDESC_H
+# define _I386_DL_TLSDESC_H 1
+
+/* Type used to represent a TLS descriptor in the GOT. */
+struct tlsdesc
+{
+ ptrdiff_t __attribute__ ((regparm (1))) (*entry) (struct tlsdesc *);
+ void *arg;
+};
+
+typedef struct dl_tls_index
+{
+ unsigned long int ti_module;
+ unsigned long int ti_offset;
+} tls_index;
+
+/* 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 __attribute__ ((regparm (1)))
+ _dl_tlsdesc_return (struct tlsdesc *),
+ _dl_tlsdesc_undefweak (struct tlsdesc *),
+ _dl_tlsdesc_resolve_abs_plus_addend (struct tlsdesc *),
+ _dl_tlsdesc_resolve_rel (struct tlsdesc *),
+ _dl_tlsdesc_resolve_rela (struct tlsdesc *),
+ _dl_tlsdesc_resolve_hold (struct tlsdesc *);
+
+# ifdef SHARED
+extern void *internal_function _dl_make_tlsdesc_dynamic (struct link_map *map,
+ size_t ti_offset);
+
+extern ptrdiff_t attribute_hidden __attribute__ ((regparm (1)))
+ _dl_tlsdesc_dynamic (struct tlsdesc *);
+# endif
+
+#endif
diff --git a/sysdeps/i386/tlsdesc.c b/sysdeps/i386/tlsdesc.c
new file mode 100644
index 0000000000..28287d574b
--- /dev/null
+++ b/sysdeps/i386/tlsdesc.c
@@ -0,0 +1,269 @@
+/* Manage TLS descriptors. i386 version.
+ Copyright (C) 2005, 2008 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 <link.h>
+#include <ldsodefs.h>
+#include <elf/dynamic-link.h>
+#include <tls.h>
+#include <dl-tlsdesc.h>
+#include <tlsdeschtab.h>
+
+/* The following 4 functions take an entry_check_offset argument.
+ It's computed by the caller as an offset between its entry point
+ and the call site, such that by adding the built-in return address
+ that is implicitly passed to the function with this offset, we can
+ easily obtain the caller's entry point to compare with the entry
+ point given in the TLS descriptor. If it's changed, we want to
+ return immediately. */
+
+/* This function is used to lazily resolve TLS_DESC REL relocations
+ that reference the *ABS* segment in their own link maps. The
+ argument is the addend originally stored there. */
+
+void
+__attribute__ ((regparm (3))) attribute_hidden
+_dl_tlsdesc_resolve_abs_plus_addend_fixup (struct tlsdesc volatile *td,
+ struct link_map *l,
+ ptrdiff_t entry_check_offset)
+{
+ ptrdiff_t addend = (ptrdiff_t) td->arg;
+
+ if (_dl_tlsdesc_resolve_early_return_p (td, __builtin_return_address (0)
+ - entry_check_offset))
+ return;
+
+#ifndef SHARED
+ CHECK_STATIC_TLS (l, l);
+#else
+ if (!TRY_STATIC_TLS (l, l))
+ {
+ td->arg = _dl_make_tlsdesc_dynamic (l, addend);
+ td->entry = _dl_tlsdesc_dynamic;
+ }
+ else
+#endif
+ {
+ td->arg = (void*) (addend - l->l_tls_offset);
+ td->entry = _dl_tlsdesc_return;
+ }
+
+ _dl_tlsdesc_wake_up_held_fixups ();
+}
+
+/* This function is used to lazily resolve TLS_DESC REL relocations
+ that originally had zero addends. The argument location, that
+ originally held the addend, is used to hold a pointer to the
+ relocation, but it has to be restored before we call the function
+ that applies relocations. */
+
+void
+__attribute__ ((regparm (3))) attribute_hidden
+_dl_tlsdesc_resolve_rel_fixup (struct tlsdesc volatile *td,
+ struct link_map *l,
+ ptrdiff_t entry_check_offset)
+{
+ const ElfW(Rel) *reloc = td->arg;
+
+ if (_dl_tlsdesc_resolve_early_return_p (td, __builtin_return_address (0)
+ - entry_check_offset))
+ return;
+
+ /* The code below was borrowed from _dl_fixup(),
+ except for checking for STB_LOCAL. */
+ const ElfW(Sym) *const symtab
+ = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
+ lookup_t result;
+
+ /* Look up the target symbol. If the normal lookup rules are not
+ used don't look in the global scope. */
+ if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
+ && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
+ {
+ const struct r_found_version *version = NULL;
+
+ if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ const ElfW(Half) *vernum =
+ (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
+ ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
+ version = &l->l_versions[ndx];
+ if (version->hash == 0)
+ version = NULL;
+ }
+
+ result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
+ l->l_scope, version, ELF_RTYPE_CLASS_PLT,
+ DL_LOOKUP_ADD_DEPENDENCY, NULL);
+ }
+ else
+ {
+ /* We already found the symbol. The module (and therefore its load
+ address) is also known. */
+ result = l;
+ }
+
+ if (!sym)
+ {
+ td->arg = 0;
+ td->entry = _dl_tlsdesc_undefweak;
+ }
+ else
+ {
+# ifndef SHARED
+ CHECK_STATIC_TLS (l, result);
+# else
+ if (!TRY_STATIC_TLS (l, result))
+ {
+ td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value);
+ td->entry = _dl_tlsdesc_dynamic;
+ }
+ else
+# endif
+ {
+ td->arg = (void*)(sym->st_value - result->l_tls_offset);
+ td->entry = _dl_tlsdesc_return;
+ }
+ }
+
+ _dl_tlsdesc_wake_up_held_fixups ();
+}
+
+/* This function is used to lazily resolve TLS_DESC RELA relocations.
+ The argument location is used to hold a pointer to the relocation. */
+
+void
+__attribute__ ((regparm (3))) attribute_hidden
+_dl_tlsdesc_resolve_rela_fixup (struct tlsdesc volatile *td,
+ struct link_map *l,
+ ptrdiff_t entry_check_offset)
+{
+ const ElfW(Rela) *reloc = td->arg;
+
+ if (_dl_tlsdesc_resolve_early_return_p (td, __builtin_return_address (0)
+ - entry_check_offset))
+ return;
+
+ /* The code below was borrowed from _dl_fixup(),
+ except for checking for STB_LOCAL. */
+ const ElfW(Sym) *const symtab
+ = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
+ lookup_t result;
+
+ /* Look up the target symbol. If the normal lookup rules are not
+ used don't look in the global scope. */
+ if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
+ && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
+ {
+ const struct r_found_version *version = NULL;
+
+ if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ const ElfW(Half) *vernum =
+ (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
+ ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
+ version = &l->l_versions[ndx];
+ if (version->hash == 0)
+ version = NULL;
+ }
+
+ result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
+ l->l_scope, version, ELF_RTYPE_CLASS_PLT,
+ DL_LOOKUP_ADD_DEPENDENCY, NULL);
+ }
+ else
+ {
+ /* We already found the symbol. The module (and therefore its load
+ address) is also known. */
+ result = l;
+ }
+
+ if (!sym)
+ {
+ td->arg = (void*) reloc->r_addend;
+ td->entry = _dl_tlsdesc_undefweak;
+ }
+ else
+ {
+# ifndef SHARED
+ CHECK_STATIC_TLS (l, result);
+# else
+ if (!TRY_STATIC_TLS (l, result))
+ {
+ td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value
+ + reloc->r_addend);
+ td->entry = _dl_tlsdesc_dynamic;
+ }
+ else
+# endif
+ {
+ td->arg = (void*) (sym->st_value - result->l_tls_offset
+ + reloc->r_addend);
+ td->entry = _dl_tlsdesc_return;
+ }
+ }
+
+ _dl_tlsdesc_wake_up_held_fixups ();
+}
+
+/* This function is used to avoid busy waiting for other threads to
+ complete the lazy relocation. Once another thread wins the race to
+ relocate a TLS descriptor, it sets the descriptor up such that this
+ function is called to wait until the resolver releases the
+ lock. */
+
+void
+__attribute__ ((regparm (3))) attribute_hidden
+_dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td,
+ struct link_map *l __attribute__((__unused__)),
+ ptrdiff_t entry_check_offset)
+{
+ /* Maybe we're lucky and can return early. */
+ if (__builtin_return_address (0) - entry_check_offset != td->entry)
+ return;
+
+ /* Locking here will stop execution until the running resolver runs
+ _dl_tlsdesc_wake_up_held_fixups(), releasing the lock.
+
+ FIXME: We'd be better off waiting on a condition variable, such
+ that we didn't have to hold the lock throughout the relocation
+ processing. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+}
+
+
+/* Unmap the dynamic object, but also release its TLS descriptor table
+ if there is one. */
+
+void
+internal_function
+_dl_unmap (struct link_map *map)
+{
+ __munmap ((void *) (map)->l_map_start,
+ (map)->l_map_end - (map)->l_map_start);
+
+#if SHARED
+ if (map->l_mach.tlsdesc_table)
+ htab_delete (map->l_mach.tlsdesc_table);
+#endif
+}
diff --git a/sysdeps/i386/tlsdesc.sym b/sysdeps/i386/tlsdesc.sym
new file mode 100644
index 0000000000..33854975d0
--- /dev/null
+++ b/sysdeps/i386/tlsdesc.sym
@@ -0,0 +1,17 @@
+#include <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+
+DTV_OFFSET offsetof(struct pthread, header.dtv)
+
+TLSDESC_ARG offsetof(struct tlsdesc, arg)
+
+TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count)
+TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module)
+TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset)
diff --git a/sysdeps/ia64/bits/byteswap.h b/sysdeps/ia64/bits/byteswap.h
index 6862aa0b60..d64914f36e 100644
--- a/sysdeps/ia64/bits/byteswap.h
+++ b/sysdeps/ia64/bits/byteswap.h
@@ -1,5 +1,5 @@
/* Macros to swap the order of bytes in integer values.
- Copyright (C) 1997, 1998, 2000, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1997,1998,2000,2002,2003,2008 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
@@ -17,7 +17,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#if !defined _BYTESWAP_H && !defined _NETINET_IN_H
+#if !defined _BYTESWAP_H && !defined _NETINET_IN_H && !defined _ENDIAN_H
# error "Never use <bits/byteswap.h> directly; include <byteswap.h> instead."
#endif
diff --git a/sysdeps/ieee754/flt-32/w_expf.c b/sysdeps/ieee754/flt-32/w_expf.c
index ad38fac0f3..4ba21c7c42 100644
--- a/sysdeps/ieee754/flt-32/w_expf.c
+++ b/sysdeps/ieee754/flt-32/w_expf.c
@@ -29,7 +29,7 @@ static const float
#else
static float
#endif
-o_threshold= 8.8721679688e+01, /* 0x42b17180 */
+o_threshold= 8.8722831726e+01, /* 0x42b17217 */
u_threshold= -1.0397208405e+02; /* 0xc2cff1b5 */
#ifdef __STDC__
diff --git a/sysdeps/ieee754/ldbl-128/e_j0l.c b/sysdeps/ieee754/ldbl-128/e_j0l.c
index f235372916..bcd57e2b06 100644
--- a/sysdeps/ieee754/ldbl-128/e_j0l.c
+++ b/sysdeps/ieee754/ldbl-128/e_j0l.c
@@ -679,7 +679,7 @@ __ieee754_j0l (long double x)
{
long double xx, xinv, z, p, q, c, s, cc, ss;
- if (! finitel (x))
+ if (! __finitel (x))
{
if (x != x)
return x;
@@ -816,7 +816,7 @@ long double
{
long double xx, xinv, z, p, q, c, s, cc, ss;
- if (! finitel (x))
+ if (! __finitel (x))
{
if (x != x)
return x;
diff --git a/sysdeps/ieee754/ldbl-128/e_j1l.c b/sysdeps/ieee754/ldbl-128/e_j1l.c
index 7ec073d9e2..7b73e2e799 100644
--- a/sysdeps/ieee754/ldbl-128/e_j1l.c
+++ b/sysdeps/ieee754/ldbl-128/e_j1l.c
@@ -685,7 +685,7 @@ __ieee754_j1l (long double x)
{
long double xx, xinv, z, p, q, c, s, cc, ss;
- if (! finitel (x))
+ if (! __finitel (x))
{
if (x != x)
return x;
@@ -823,7 +823,7 @@ __ieee754_y1l (long double x)
{
long double xx, xinv, z, p, q, c, s, cc, ss;
- if (! finitel (x))
+ if (! __finitel (x))
{
if (x != x)
return x;
diff --git a/sysdeps/ieee754/ldbl-128/s_expm1l.c b/sysdeps/ieee754/ldbl-128/s_expm1l.c
index f373e1e6a9..78bbe65b53 100644
--- a/sysdeps/ieee754/ldbl-128/s_expm1l.c
+++ b/sysdeps/ieee754/ldbl-128/s_expm1l.c
@@ -153,7 +153,7 @@ __expm1l (long double x)
exp(x) - 1 = 2^k (qx + 1) - 1
= 2^k qx + 2^k - 1. */
- px = ldexpl (1.0L, k);
+ px = __ldexpl (1.0L, k);
x = px * qx + (px - 1.0);
return x;
}
diff --git a/sysdeps/ieee754/ldbl-128/s_log1pl.c b/sysdeps/ieee754/ldbl-128/s_log1pl.c
index 64d5146139..defbe76f5e 100644
--- a/sysdeps/ieee754/ldbl-128/s_log1pl.c
+++ b/sysdeps/ieee754/ldbl-128/s_log1pl.c
@@ -120,13 +120,6 @@ static const long double maxlog = 1.1356523406294143949491931077970764891253E4L;
static const long double big = 2e4932L;
static const long double zero = 0.0L;
-#if 1
-/* Make sure these are prototyped. */
-long double frexpl (long double, int *);
-long double ldexpl (long double, int);
-#endif
-
-
long double
__log1pl (long double xm1)
{
@@ -160,7 +153,7 @@ __log1pl (long double xm1)
/* Separate mantissa from exponent. */
/* Use frexp used so that denormal numbers will be handled properly. */
- x = frexpl (x, &e);
+ x = __frexpl (x, &e);
/* Logarithm using log(x) = z + z^3 P(z^2)/Q(z^2),
where z = 2(x-1)/x+1). */
diff --git a/sysdeps/mach/hurd/bits/ioctls.h b/sysdeps/mach/hurd/bits/ioctls.h
index c9d313519c..8718aacd83 100644
--- a/sysdeps/mach/hurd/bits/ioctls.h
+++ b/sysdeps/mach/hurd/bits/ioctls.h
@@ -25,6 +25,46 @@
/* These macros are also defined in <bits/termios.h> (with numerically
identical values) but this serves to shut up cpp's complaining. */
+
+#ifdef NL0
+# undef NL0
+#endif
+#ifdef NL1
+# undef NL1
+#endif
+#ifdef TAB0
+# undef TAB0
+#endif
+#ifdef TAB1
+# undef TAB1
+#endif
+#ifdef TAB2
+# undef TAB2
+#endif
+#ifdef CR0
+# undef CR0
+#endif
+#ifdef CR1
+# undef CR1
+#endif
+#ifdef CR2
+# undef CR2
+#endif
+#ifdef CR3
+# undef CR3
+#endif
+#ifdef FF0
+# undef FF0
+#endif
+#ifdef FF1
+# undef FF1
+#endif
+#ifdef BS0
+# undef BS0
+#endif
+#ifdef BS1
+# undef BS1
+#endif
#ifdef MDMBUF
# undef MDMBUF
#endif
@@ -284,31 +324,25 @@ enum __ioctl_datum { IOC_8, IOC_16, IOC_32, IOC_64 };
#define ODDP 0x00000040 /* get/send odd parity */
#define EVENP 0x00000080 /* get/send even parity */
#define ANYP 0x000000c0 /* get any parity/send none */
-#define NLDLY 0x00000300 /* \n delay */
-#define NLDELAY NLDLY /* traditional BSD name */
+#define NLDELAY 0x00000300 /* \n delay */
#define NL0 0x00000000
#define NL1 0x00000100 /* tty 37 */
#define NL2 0x00000200 /* vt05 */
#define NL3 0x00000300
-#define TABDLY 0x00000c00 /* horizontal tab delay */
-#define TBDELAY TABDLY /* traditional BSD name */
+#define TBDELAY 0x00000c00 /* horizontal tab delay */
#define TAB0 0x00000000
#define TAB1 0x00000400 /* tty 37 */
#define TAB2 0x00000800
-#define TAB3 0x00000c00
#define XTABS 0x00000c00 /* expand tabs on output */
-#define CRDLY 0x00003000 /* \r delay */
-#define CRDELAY CRDLY /* traditional BSD name */
+#define CRDELAY 0x00003000 /* \r delay */
#define CR0 0x00000000
#define CR1 0x00001000 /* tn 300 */
#define CR2 0x00002000 /* tty 37 */
#define CR3 0x00003000 /* concept 100 */
-#define VTDLY 0x00004000 /* vertical tab delay */
-#define VTDELAY VTDLY /* traditional BSD name */
+#define VTDELAY 0x00004000 /* vertical tab delay */
#define FF0 0x00000000
#define FF1 0x00004000 /* tty 37 */
-#define BSDLY 0x00008000 /* \b delay */
-#define BSDELAY BSDLY /* traditional BSD name */
+#define BSDELAY 0x00008000 /* \b delay */
#define BS0 0x00000000
#define BS1 0x00008000
#define ALLDELAY (NLDELAY|TBDELAY|CRDELAY|VTDELAY|BSDELAY)
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 9a27efdf83..8908fc10c3 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -40,6 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <errno.h>
#include <ifaddrs.h>
#include <netdb.h>
+#include <nss.h>
#include <resolv.h>
#include <stdbool.h>
#include <stdio.h>
@@ -60,6 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <not-cancel.h>
#include <nscd/nscd-client.h>
#include <nscd/nscd_proto.h>
+#include <resolv/res_hconf.h>
#ifdef HAVE_LIBIDN
extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
@@ -91,21 +93,14 @@ struct gaih_servtuple
static const struct gaih_servtuple nullserv;
-struct gaih_addrtuple
- {
- struct gaih_addrtuple *next;
- char *name;
- int family;
- uint32_t addr[4];
- uint32_t scopeid;
- };
struct gaih_typeproto
{
int socktype;
int protocol;
- char name[4];
- int protoflag;
+ uint8_t protoflag;
+ bool defaultflag;
+ char name[8];
};
/* Values for `protoflag'. */
@@ -114,11 +109,21 @@ struct gaih_typeproto
static const struct gaih_typeproto gaih_inet_typeproto[] =
{
- { 0, 0, "", 0 },
- { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
- { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
- { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
- { 0, 0, "", 0 }
+ { 0, 0, 0, false, "" },
+ { SOCK_STREAM, IPPROTO_TCP, 0, true, "tcp" },
+ { SOCK_DGRAM, IPPROTO_UDP, 0, true, "udp" },
+#if defined SOCK_DCCP && defined IPPROTO_DCCP
+ { SOCK_DCCP, IPPROTO_DCCP, 0, false, "dccp" },
+#endif
+#ifdef IPPROTO_UDPLITE
+ { SOCK_DGRAM, IPPROTO_UDPLITE, 0, false, "udplite" },
+#endif
+#ifdef IPPROTO_SCTP
+ { SOCK_STREAM, IPPROTO_SCTP, 0, false, "sctp" },
+ { SOCK_SEQPACKET, IPPROTO_SCTP, 0, false, "sctp" },
+#endif
+ { SOCK_RAW, 0, GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE, true, "raw" },
+ { 0, 0, 0, false, "" }
};
struct gaih
@@ -202,6 +207,7 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
if (herrno == NETDB_INTERNAL) \
{ \
__set_h_errno (herrno); \
+ _res.options = old_res_options; \
return -EAI_SYSTEM; \
} \
if (herrno == TRY_AGAIN) \
@@ -246,6 +252,10 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
}
+typedef enum nss_status (*nss_gethostbyname4_r)
+ (const char *name, struct gaih_addrtuple **pat,
+ char *buffer, size_t buflen, int *errnop,
+ int *h_errnop, int32_t *ttlp);
typedef enum nss_status (*nss_gethostbyname3_r)
(const char *name, int af, struct hostent *host,
char *buffer, size_t buflen, int *errnop,
@@ -365,18 +375,19 @@ gaih_inet (const char *name, const struct gaih_service *service,
we know about. */
struct gaih_servtuple **lastp = &st;
for (++tp; tp->name[0]; ++tp)
- {
- struct gaih_servtuple *newp;
+ if (tp->defaultflag)
+ {
+ struct gaih_servtuple *newp;
- newp = __alloca (sizeof (struct gaih_servtuple));
- newp->next = NULL;
- newp->socktype = tp->socktype;
- newp->protocol = tp->protocol;
- newp->port = port;
+ newp = __alloca (sizeof (struct gaih_servtuple));
+ newp->next = NULL;
+ newp->socktype = tp->socktype;
+ newp->protocol = tp->protocol;
+ newp->port = port;
- *lastp = newp;
- lastp = &newp->next;
- }
+ *lastp = newp;
+ lastp = &newp->next;
+ }
}
}
@@ -685,87 +696,132 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (!no_more)
{
- nss_gethostbyname3_r fct = NULL;
- if (req->ai_flags & AI_CANONNAME)
- /* No need to use this function if we do not look for
- the canonical name. The function does not exist in
- all NSS modules and therefore the lookup would
- often fail. */
- fct = __nss_lookup_function (nip, "gethostbyname3_r");
- if (fct == NULL)
- /* We are cheating here. The gethostbyname2_r function does
- not have the same interface as gethostbyname3_r but the
- extra arguments the latter takes are added at the end.
- So the gethostbyname2_r code will just ignore them. */
- fct = __nss_lookup_function (nip, "gethostbyname2_r");
-
- if (fct != NULL)
+ nss_gethostbyname4_r fct4
+ = __nss_lookup_function (nip, "gethostbyname4_r");
+ if (fct4 != NULL)
{
- if (req->ai_family == AF_INET6
- || req->ai_family == AF_UNSPEC)
+ int herrno;
+
+ while (1)
{
- gethosts (AF_INET6, struct in6_addr);
- no_inet6_data = no_data;
- inet6_status = status;
+ rc = 0;
+ status = DL_CALL_FCT (fct4, (name, pat, tmpbuf,
+ tmpbuflen, &rc, &herrno,
+ NULL));
+ if (status != NSS_STATUS_TRYAGAIN
+ || rc != ERANGE || herrno != NETDB_INTERNAL)
+ {
+ if (herrno == NETDB_INTERNAL)
+ {
+ __set_h_errno (herrno);
+ _res.options = old_res_options;
+ return -EAI_SYSTEM;
+ }
+ if (herrno == TRY_AGAIN)
+ no_data = EAI_AGAIN;
+ else
+ no_data = herrno == NO_DATA;
+ break;
+ }
+ tmpbuf = extend_alloca (tmpbuf,
+ tmpbuflen, 2 * tmpbuflen);
}
- if (req->ai_family == AF_INET
- || req->ai_family == AF_UNSPEC
- || (req->ai_family == AF_INET6
- && (req->ai_flags & AI_V4MAPPED)
- /* Avoid generating the mapped addresses if we
- know we are not going to need them. */
- && ((req->ai_flags & AI_ALL) || !got_ipv6)))
+
+ if (status == NSS_STATUS_SUCCESS)
{
- gethosts (AF_INET, struct in_addr);
+ canon = (*pat)->name;
- if (req->ai_family == AF_INET)
+ while (*pat != NULL)
+ pat = &((*pat)->next);
+ }
+ }
+ else
+ {
+ nss_gethostbyname3_r fct = NULL;
+ if (req->ai_flags & AI_CANONNAME)
+ /* No need to use this function if we do not look for
+ the canonical name. The function does not exist in
+ all NSS modules and therefore the lookup would
+ often fail. */
+ fct = __nss_lookup_function (nip, "gethostbyname3_r");
+ if (fct == NULL)
+ /* We are cheating here. The gethostbyname2_r
+ function does not have the same interface as
+ gethostbyname3_r but the extra arguments the
+ latter takes are added at the end. So the
+ gethostbyname2_r code will just ignore them. */
+ fct = __nss_lookup_function (nip, "gethostbyname2_r");
+
+ if (fct != NULL)
+ {
+ if (req->ai_family == AF_INET6
+ || req->ai_family == AF_UNSPEC)
{
+ gethosts (AF_INET6, struct in6_addr);
no_inet6_data = no_data;
inet6_status = status;
}
- }
-
- /* If we found one address for AF_INET or AF_INET6,
- don't continue the search. */
- if (inet6_status == NSS_STATUS_SUCCESS
- || status == NSS_STATUS_SUCCESS)
- {
- if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
+ if (req->ai_family == AF_INET
+ || req->ai_family == AF_UNSPEC
+ || (req->ai_family == AF_INET6
+ && (req->ai_flags & AI_V4MAPPED)
+ /* Avoid generating the mapped addresses if we
+ know we are not going to need them. */
+ && ((req->ai_flags & AI_ALL) || !got_ipv6)))
{
- /* If we need the canonical name, get it
- from the same service as the result. */
- nss_getcanonname_r cfct;
- int herrno;
+ gethosts (AF_INET, struct in_addr);
- cfct = __nss_lookup_function (nip, "getcanonname_r");
- if (cfct != NULL)
+ if (req->ai_family == AF_INET)
{
- const size_t max_fqdn_len = 256;
- char *buf = alloca (max_fqdn_len);
- char *s;
-
- if (DL_CALL_FCT (cfct, (at->name ?: name, buf,
- max_fqdn_len, &s, &rc,
- &herrno))
- == NSS_STATUS_SUCCESS)
- canon = s;
- else
- /* Set to name now to avoid using
- gethostbyaddr. */
- canon = name;
+ no_inet6_data = no_data;
+ inet6_status = status;
}
}
- break;
- }
+ /* If we found one address for AF_INET or AF_INET6,
+ don't continue the search. */
+ if (inet6_status == NSS_STATUS_SUCCESS
+ || status == NSS_STATUS_SUCCESS)
+ {
+ if ((req->ai_flags & AI_CANONNAME) != 0
+ && canon == NULL)
+ {
+ /* If we need the canonical name, get it
+ from the same service as the result. */
+ nss_getcanonname_r cfct;
+ int herrno;
+
+ cfct = __nss_lookup_function (nip,
+ "getcanonname_r");
+ if (cfct != NULL)
+ {
+ const size_t max_fqdn_len = 256;
+ char *buf = alloca (max_fqdn_len);
+ char *s;
+
+ if (DL_CALL_FCT (cfct, (at->name ?: name,
+ buf, max_fqdn_len,
+ &s, &rc, &herrno))
+ == NSS_STATUS_SUCCESS)
+ canon = s;
+ else
+ /* Set to name now to avoid using
+ gethostbyaddr. */
+ canon = name;
+ }
+ }
+
+ break;
+ }
- /* We can have different states for AF_INET and
- AF_INET6. Try to find a useful one for both. */
- if (inet6_status == NSS_STATUS_TRYAGAIN)
- status = NSS_STATUS_TRYAGAIN;
- else if (status == NSS_STATUS_UNAVAIL
- && inet6_status != NSS_STATUS_UNAVAIL)
- status = inet6_status;
+ /* We can have different states for AF_INET and
+ AF_INET6. Try to find a useful one for both. */
+ if (inet6_status == NSS_STATUS_TRYAGAIN)
+ status = NSS_STATUS_TRYAGAIN;
+ else if (status == NSS_STATUS_UNAVAIL
+ && inet6_status != NSS_STATUS_UNAVAIL)
+ status = inet6_status;
+ }
}
if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
@@ -1056,7 +1112,10 @@ get_scope (const struct sockaddr_in6 *in6)
{
if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr))
{
- if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr))
+ if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr)
+ /* RFC 4291 2.5.3 says that the loopback address is to be
+ treated like a link-local address. */
+ || IN6_IS_ADDR_LOOPBACK (&in6->sin6_addr))
scope = 2;
else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr))
scope = 5;
@@ -1189,20 +1248,14 @@ match_prefix (const struct sockaddr_in6 *in6,
{
const struct sockaddr_in *in = (const struct sockaddr_in *) in6;
- /* Convert to IPv6 address. */
+ /* Construct a V4-to-6 mapped address. */
in6_mem.sin6_family = PF_INET6;
in6_mem.sin6_port = in->sin_port;
in6_mem.sin6_flowinfo = 0;
- if (in->sin_addr.s_addr == htonl (0x7f000001))
- in6_mem.sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
- else
- {
- /* Construct a V4-to-6 mapped address. */
- memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr));
- in6_mem.sin6_addr.s6_addr16[5] = 0xffff;
- in6_mem.sin6_addr.s6_addr32[3] = in->sin_addr.s_addr;
- in6_mem.sin6_scope_id = 0;
- }
+ memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr));
+ in6_mem.sin6_addr.s6_addr16[5] = 0xffff;
+ in6_mem.sin6_addr.s6_addr32[3] = in->sin_addr.s_addr;
+ in6_mem.sin6_scope_id = 0;
in6 = &in6_mem;
}
@@ -2034,6 +2087,10 @@ getaddrinfo (const char *name, const char *service,
if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
return EAI_BADFLAGS;
+ /* Initialize configurations. */
+ if (__builtin_expect (!_res_hconf.initialized, 0))
+ _res_hconf_init ();
+
struct in6addrinfo *in6ai = NULL;
size_t in6ailen = 0;
bool seen_ipv4 = false;
diff --git a/sysdeps/s390/bits/byteswap.h b/sysdeps/s390/bits/byteswap.h
index d0e31b8364..4bfd5fa064 100644
--- a/sysdeps/s390/bits/byteswap.h
+++ b/sysdeps/s390/bits/byteswap.h
@@ -1,5 +1,5 @@
/* Macros to swap the order of bytes in integer values. s390 version.
- Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2008 Free Software Foundation, Inc.
Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
This file is part of the GNU C Library.
@@ -18,7 +18,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#if !defined _BYTESWAP_H && !defined _NETINET_IN_H
+#if !defined _BYTESWAP_H && !defined _NETINET_IN_H && !defined _ENDIAN_H
# error "Never use <bits/byteswap.h> directly; include <byteswap.h> instead."
#endif
diff --git a/sysdeps/sparc/sparc32/Makefile b/sysdeps/sparc/sparc32/Makefile
index ed4fba7418..6529ad897b 100644
--- a/sysdeps/sparc/sparc32/Makefile
+++ b/sysdeps/sparc/sparc32/Makefile
@@ -20,6 +20,10 @@ ifeq ($(subdir),gnulib)
sysdep_routines = dotmul umul $(divrem) alloca
endif # gnulib
+ifeq ($(subdir),csu)
+CFLAGS-initfini.s += -mcpu=v7
+endif
+
# We distribute these files, even though they are generated,
# so as to avoid the need for a functioning m4 to build the library.
divrem := sdiv udiv rem urem
diff --git a/sysdeps/sparc/sparc64/Makefile b/sysdeps/sparc/sparc64/Makefile
index c1df31727c..3bb0238832 100644
--- a/sysdeps/sparc/sparc64/Makefile
+++ b/sysdeps/sparc/sparc64/Makefile
@@ -2,3 +2,7 @@ ifeq ($(subdir),csu)
sysdep_routines += hp-timing
elide-routines.os += hp-timing
endif
+
+ifeq ($(subdir),csu)
+CFLAGS-initfini.s += -mcpu=v9
+endif
diff --git a/sysdeps/unix/sysv/linux/alpha/bits/resource.h b/sysdeps/unix/sysv/linux/alpha/bits/resource.h
index 2163745840..92d0199dcd 100644
--- a/sysdeps/unix/sysv/linux/alpha/bits/resource.h
+++ b/sysdeps/unix/sysv/linux/alpha/bits/resource.h
@@ -158,8 +158,16 @@ enum __rusage_who
#define RUSAGE_SELF RUSAGE_SELF
/* All of its terminated child processes. */
- RUSAGE_CHILDREN = -1
+ RUSAGE_CHILDREN = -1,
#define RUSAGE_CHILDREN RUSAGE_CHILDREN
+
+#ifdef __USE_GNU
+ /* The calling thread. */
+ RUSAGE_THREAD = 1
+# define RUSAGE_THREAD RUSAGE_THREAD
+ /* Name for the same functionality on Solaris. */
+# define RUSAGE_LWP RUSAGE_THREAD
+#endif
};
#define __need_timeval
diff --git a/sysdeps/unix/sysv/linux/bits/resource.h b/sysdeps/unix/sysv/linux/bits/resource.h
index 526cdaf53c..95d64ed77f 100644
--- a/sysdeps/unix/sysv/linux/bits/resource.h
+++ b/sysdeps/unix/sysv/linux/bits/resource.h
@@ -158,8 +158,16 @@ enum __rusage_who
#define RUSAGE_SELF RUSAGE_SELF
/* All of its terminated child processes. */
- RUSAGE_CHILDREN = -1
+ RUSAGE_CHILDREN = -1,
#define RUSAGE_CHILDREN RUSAGE_CHILDREN
+
+#ifdef __USE_GNU
+ /* The calling thread. */
+ RUSAGE_THREAD = 1
+# define RUSAGE_THREAD RUSAGE_THREAD
+ /* Name for the same functionality on Solaris. */
+# define RUSAGE_LWP RUSAGE_THREAD
+#endif
};
#define __need_timeval
diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h
index ceb60133e3..3dda3d1c29 100644
--- a/sysdeps/unix/sysv/linux/bits/socket.h
+++ b/sysdeps/unix/sysv/linux/bits/socket.h
@@ -1,5 +1,5 @@
/* System-specific socket constants and types. Linux version.
- Copyright (C) 1991, 1992, 1994-2001, 2004, 2006, 2007
+ Copyright (C) 1991, 1992, 1994-2001, 2004, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -52,6 +52,8 @@ enum __socket_type
SOCK_SEQPACKET = 5, /* Sequenced, reliable, connection-based,
datagrams of fixed maximum length. */
#define SOCK_SEQPACKET SOCK_SEQPACKET
+ SOCK_DCCP = 6,
+#define SOCK_DCCP SOCK_DCCP /* Datagram Congestion Control Protocol. */
SOCK_PACKET = 10 /* Linux specific way of getting packets
at the dev level. For writing rarp and
other similar things on the user level. */
diff --git a/sysdeps/unix/sysv/linux/dl-osinfo.h b/sysdeps/unix/sysv/linux/dl-osinfo.h
index 582412e300..275a0730c8 100644
--- a/sysdeps/unix/sysv/linux/dl-osinfo.h
+++ b/sysdeps/unix/sysv/linux/dl-osinfo.h
@@ -20,6 +20,7 @@
#include <errno.h>
#include <kernel-features.h>
#include <dl-sysdep.h>
+#include <fcntl.h>
#include <stdint.h>
#include <hp-timing.h>
#include <endian.h>
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/resource.h b/sysdeps/unix/sysv/linux/sparc/bits/resource.h
index 3f2c600141..22c087da46 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/resource.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/resource.h
@@ -174,8 +174,16 @@ enum __rusage_who
#define RUSAGE_SELF RUSAGE_SELF
/* All of its terminated child processes. */
- RUSAGE_CHILDREN = -1
+ RUSAGE_CHILDREN = -1,
#define RUSAGE_CHILDREN RUSAGE_CHILDREN
+
+#ifdef __USE_GNU
+ /* The calling thread. */
+ RUSAGE_THREAD = 1
+# define RUSAGE_THREAD RUSAGE_THREAD
+ /* Name for the same functionality on Solaris. */
+# define RUSAGE_LWP RUSAGE_THREAD
+#endif
};
#define __need_timeval
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/Makefile b/sysdeps/unix/sysv/linux/sparc/sparc32/Makefile
index cd1b3fb793..8f7e76be2a 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/Makefile
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/Makefile
@@ -2,6 +2,10 @@ asm-CPPFLAGS = -D__ASSEMBLY__
ASFLAGS-.os += -fPIC
LD += -melf32_sparc
+ifeq ($(subdir),stdlib)
+gen-as-const-headers += ucontext_i.sym
+endif
+
# When I get this to work, this is the right thing
ifeq ($(subdir),elf)
CFLAGS-rtld.c += -mcpu=v8
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/getcontext.S b/sysdeps/unix/sysv/linux/sparc/sparc32/getcontext.S
new file mode 100644
index 0000000000..f8664a7975
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/getcontext.S
@@ -0,0 +1,85 @@
+/* Save current context.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David S. Miller <davem@davemloft.net>, 2008.
+
+ 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 "ucontext_i.h"
+
+/* int __getcontext (ucontext_t *ucp)
+
+ Saves the machine context in UCP such that when it is activated,
+ it appears as if __getcontext() returned again.
+
+ This implementation is intended to be used for *synchronous* context
+ switches only. Therefore, it does not have to save anything
+ other than the PRESERVED state. */
+
+
+ENTRY(__getcontext)
+ save %sp, -112, %sp
+ st %g0, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_PSR]
+
+ /* In reality, we only use the GREG_PC value when setting
+ or swapping contexts. But we fill in NPC for completeness. */
+ add %i7, 8, %o0
+ st %o0, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_PC]
+ add %o0, 4, %o0
+ st %o0, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_NPC]
+
+ rd %y, %o1
+ st %o1, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_Y]
+
+ st %g1, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G1]
+ st %g2, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G2]
+ st %g3, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G3]
+ st %g4, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G4]
+ st %g5, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G5]
+ st %g6, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G6]
+ st %g7, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G7]
+
+ mov SIG_BLOCK, %o0
+ clr %o1
+ add %i0, UC_SIGMASK, %o2
+ mov 8, %o3
+ mov __NR_rt_sigprocmask, %g1
+ ta 0x10
+
+ /* Zero, success, return value. */
+ st %g0, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O0]
+ st %i1, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O1]
+ st %i2, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O2]
+ st %i3, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O3]
+ st %i4, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O4]
+ st %i5, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O5]
+ st %i6, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O6]
+ st %i7, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O7]
+
+ st %g0, [%i0 + UC_MCONTEXT + MC_GWINS]
+
+ /* Do not save FPU state, it is volatile across calls. */
+ stb %g0, [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_EN]
+
+ st %g0, [%i0 + UC_MCONTEXT + MC_XRS + XRS_ID]
+ st %g0, [%i0 + UC_MCONTEXT + MC_XRS + XRS_PTR]
+ jmpl %i7 + 8, %g0
+ restore %g0, %g0, %o0
+END(__getcontext)
+
+weak_alias (__getcontext, getcontext)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/makecontext.c b/sysdeps/unix/sysv/linux/sparc/sparc32/makecontext.c
new file mode 100644
index 0000000000..9b48dade63
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/makecontext.c
@@ -0,0 +1,93 @@
+/* Create new context.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David S. Miller <davem@davemloft.net>, 2008.
+
+ 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 <stdarg.h>
+#include <stdint.h>
+#include <ucontext.h>
+
+/* Sets up the outgoing arguments and the program counter for a user
+ context for the requested function call.
+
+ Returning to the correct parent context is pretty simple on
+ Sparc. We only need to link up the register windows correctly.
+ Since global registers are clobbered by calls, we need not be
+ concernred about those, and thus is all could be worked out without
+ using a trampoline.
+
+ Except that we must deal with the signal mask, thus a trampoline
+ is unavoidable. 32-bit stackframe layout:
+ +-----------------------------------------+
+ | 7th and further parameters |
+ +-----------------------------------------+
+ | backup storage for initial 6 parameters |
+ +-----------------------------------------+
+ | struct return pointer |
+ +-----------------------------------------+
+ | 8 incoming registers |
+ +-----------------------------------------+
+ | 8 local registers |
+ %sp --> +-----------------------------------------+
+
+*/
+
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+ extern void __start_context (void);
+ unsigned long int *sp;
+ va_list ap;
+ int i;
+
+ sp = (unsigned long int *) (ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+ sp -= 16 + 7 + argc;
+ sp = (unsigned long int *) (((uintptr_t) sp) & ~(8 - 1));
+
+ for (i = 0; i < 8; i++)
+ sp[i + 8] = ucp->uc_mcontext.gregs[REG_O0 + i];
+
+ /* The struct return pointer is essentially unused, so we can
+ place the link there. */
+ sp[16] = (unsigned long int) ucp->uc_link;
+
+ va_start (ap, argc);
+
+ /* Fill in outgoing arguments, including those which will
+ end up being passed on the stack. */
+ for (i = 0; i < argc; i++)
+ {
+ unsigned long int arg = va_arg (ap, unsigned long int);
+ if (i < 6)
+ ucp->uc_mcontext.gregs[REG_O0 + i] = arg;
+ else
+ sp[i + 23] = arg;
+ }
+
+ va_end (ap);
+
+ ucp->uc_mcontext.gregs[REG_O6] = (unsigned long int) sp;
+
+ ucp->uc_mcontext.gregs[REG_O7] = ((unsigned long int) __start_context) - 8;
+
+ ucp->uc_mcontext.gregs[REG_PC] = (unsigned long int) func;
+ ucp->uc_mcontext.gregs[REG_nPC] = ucp->uc_mcontext.gregs[REG_PC] + 4;
+}
+
+weak_alias (__makecontext, makecontext)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/setcontext.S b/sysdeps/unix/sysv/linux/sparc/sparc32/setcontext.S
new file mode 100644
index 0000000000..33e40ac65a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/setcontext.S
@@ -0,0 +1,119 @@
+/* Install given context.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David S. Miller <davem@davemloft.net>, 2008.
+
+ 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 <sys/trap.h>
+
+#include "ucontext_i.h"
+
+
+/* int __setcontext (const ucontext_t *ucp)
+
+ Restores the machine context in UCP and thereby resumes execution
+ in that context.
+
+ This implementation is intended to be used for *synchronous* context
+ switches only. Therefore, it does not have to restore anything
+ other than the PRESERVED state. */
+
+ENTRY(__setcontext)
+ save %sp, -112, %sp
+
+ mov SIG_SETMASK, %o0
+ add %i0, UC_SIGMASK, %o1
+ clr %o2
+ mov 8, %o3
+ mov __NR_rt_sigprocmask, %g1
+ ta 0x10
+
+ /* This is a bit on the expensive side, and we could optimize
+ the unwind similar to how the 32-bit sparc longjmp code
+ does if performance of this routine really matters. */
+ ta ST_FLUSH_WINDOWS
+
+ ldub [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_EN], %g1
+ cmp %g1, 0
+ be 1f
+ nop
+ ld [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_FSR], %fsr
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D0], %f0
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D2], %f2
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D4], %f4
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D6], %f6
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D8], %f8
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D10], %f10
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D12], %f12
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D14], %f14
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D16], %f16
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D18], %f18
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D20], %f20
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D22], %f22
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D24], %f24
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D26], %f26
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D28], %f28
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D30], %f30
+1:
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_Y], %g1
+ wr %g1, 0x0, %y
+
+ /* We specifically do not restore %g1 since we need it here as
+ a temporary. */
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G2], %g2
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G3], %g3
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G4], %g4
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G5], %g5
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G6], %g6
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G7], %g7
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O1], %i1
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O2], %i2
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O3], %i3
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O4], %i4
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O5], %i5
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O6], %i6
+ restore
+ ld [%o0 + UC_MCONTEXT + MC_GREGS + GREG_O7], %o7
+ ld [%o0 + UC_MCONTEXT + MC_GREGS + GREG_PC], %g1
+ jmpl %g1, %g0
+ ld [%o0 + UC_MCONTEXT + MC_GREGS + GREG_O0], %o0
+END(__setcontext)
+
+weak_alias (__setcontext, setcontext)
+
+/* This is the helper code which gets called if a function which is
+ registered with 'makecontext' returns. In this case we have to
+ install the context listed in the uc_link element of the context
+ 'makecontext' manipulated at the time of the 'makecontext' call.
+ If the pointer is NULL the process must terminate. */
+
+ENTRY(__start_context)
+ ld [%sp + (16 * 4)], %g1
+ cmp %g1, 0
+ be,a 1f
+ clr %o0
+ call __setcontext
+ mov %g1, %o0
+ /* If this returns (which can happen if the syscall fails) we'll
+ exit the program with the return error value (-1). */
+1: call exit
+ nop
+ /* The 'exit' call should never return. In case it does cause
+ the process to terminate. */
+ unimp
+END(__start_context)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/swapcontext.S b/sysdeps/unix/sysv/linux/sparc/sparc32/swapcontext.S
new file mode 100644
index 0000000000..154746689a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/swapcontext.S
@@ -0,0 +1,119 @@
+/* Save current context and install the given one.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David S. Miller <davem@davemloft.net>, 2008.
+
+ 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 <sys/trap.h>
+
+#include "ucontext_i.h"
+
+
+/* int __swapcontext (ucontext_t *oucp, const ucontext_t *ucp);
+
+ Saves the machine context in oucp such that when it is activated,
+ it appears as if __swapcontext() returned again, restores the
+ machine context in ucp and thereby resumes execution in that
+ context.
+
+ This implementation is intended to be used for *synchronous* context
+ switches only. Therefore, it does not have to save anything
+ other than the PRESERVED state. */
+
+ENTRY(__swapcontext)
+ save %sp, -112, %sp
+ ta ST_FLUSH_WINDOWS
+ st %g0, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_PSR]
+ add %i7, 8, %o0
+ st %o0, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_PC]
+ add %o0, 4, %o0
+ st %o0, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_NPC]
+ rd %y, %o1
+ st %o1, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_Y]
+ st %g1, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G1]
+ st %g2, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G2]
+ st %g3, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G3]
+ st %g4, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G4]
+ st %g5, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G5]
+ st %g6, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G6]
+ st %g7, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G7]
+ st %g0, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O0]
+ st %i1, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O1]
+ st %i2, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O2]
+ st %i3, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O3]
+ st %i4, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O4]
+ st %i5, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O5]
+ st %i6, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O6]
+ st %i7, [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O7]
+ st %g0, [%i0 + UC_MCONTEXT + MC_GWINS]
+ stb %g0, [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_EN]
+ st %g0, [%i0 + UC_MCONTEXT + MC_XRS + XRS_ID]
+ st %g0, [%i0 + UC_MCONTEXT + MC_XRS + XRS_PTR]
+
+ mov SIG_SETMASK, %o0
+ add %i1, UC_SIGMASK, %o1
+ add %i0, UC_SIGMASK, %o2
+ mov 8, %o3
+ mov __NR_rt_sigprocmask, %g1
+ ta 0x10
+
+ mov %i1, %i0
+ ldub [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_EN], %g1
+ cmp %g1, 0
+ be 1f
+ nop
+ ld [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_FSR], %fsr
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D0], %f0
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D2], %f2
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D4], %f4
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D6], %f6
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D8], %f8
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D10], %f10
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D12], %f12
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D14], %f14
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D16], %f16
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D18], %f18
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D20], %f20
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D22], %f22
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D24], %f24
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D26], %f26
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D28], %f28
+ ldd [%i0 + UC_MCONTEXT + MC_FPREGS + FPU_D30], %f30
+1:
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_Y], %g1
+ wr %g1, 0x0, %y
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G2], %g2
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G3], %g3
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G4], %g4
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G5], %g5
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G6], %g6
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_G7], %g7
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O1], %i1
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O2], %i2
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O3], %i3
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O4], %i4
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O5], %i5
+ ld [%i0 + UC_MCONTEXT + MC_GREGS + GREG_O6], %i6
+ restore
+ ld [%o0 + UC_MCONTEXT + MC_GREGS + GREG_O7], %o7
+ ld [%o0 + UC_MCONTEXT + MC_GREGS + GREG_PC], %g1
+ jmpl %g1, %g0
+ ld [%o0 + UC_MCONTEXT + MC_GREGS + GREG_O0], %o0
+END(__swapcontext)
+
+weak_alias (__swapcontext, swapcontext)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S b/sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S
index 1610745524..5786880f26 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S
@@ -27,6 +27,7 @@ ENTRY(syscall)
mov %o3, %o2
mov %o4, %o3
mov %o5, %o4
+ ld [%sp + 92], %o5
ta 0x10
bcc 1f
mov %o7, %g1
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/ucontext_i.sym b/sysdeps/unix/sysv/linux/sparc/sparc32/ucontext_i.sym
new file mode 100644
index 0000000000..544030ce8b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/ucontext_i.sym
@@ -0,0 +1,61 @@
+#include <stddef.h>
+#include <signal.h>
+#include <sys/ucontext.h>
+
+--
+
+SIG_BLOCK
+SIG_SETMASK
+
+UC_FLAGS offsetof (ucontext_t, uc_flags)
+UC_LINK offsetof (ucontext_t, uc_link)
+UC_SIGMASK offsetof (ucontext_t, uc_sigmask)
+UC_STACK offsetof (ucontext_t, uc_stack)
+UC_MCONTEXT offsetof (ucontext_t, uc_mcontext)
+MC_GREGS offsetof (mcontext_t, gregs)
+MC_GWINS offsetof (mcontext_t, gwins)
+MC_FPREGS offsetof (mcontext_t, fpregs)
+MC_XRS offsetof (mcontext_t, xrs)
+MC_FILLER offsetof (mcontext_t, filler)
+GREG_PSR (REG_PSR * sizeof(greg_t))
+GREG_PC (REG_PC * sizeof(greg_t))
+GREG_NPC (REG_nPC * sizeof(greg_t))
+GREG_Y (REG_Y * sizeof(greg_t))
+GREG_G1 (REG_G1 * sizeof(greg_t))
+GREG_G2 (REG_G2 * sizeof(greg_t))
+GREG_G3 (REG_G3 * sizeof(greg_t))
+GREG_G4 (REG_G4 * sizeof(greg_t))
+GREG_G5 (REG_G5 * sizeof(greg_t))
+GREG_G6 (REG_G6 * sizeof(greg_t))
+GREG_G7 (REG_G7 * sizeof(greg_t))
+GREG_O0 (REG_O0 * sizeof(greg_t))
+GREG_O1 (REG_O1 * sizeof(greg_t))
+GREG_O2 (REG_O2 * sizeof(greg_t))
+GREG_O3 (REG_O3 * sizeof(greg_t))
+GREG_O4 (REG_O4 * sizeof(greg_t))
+GREG_O5 (REG_O5 * sizeof(greg_t))
+GREG_O6 (REG_O6 * sizeof(greg_t))
+GREG_O7 (REG_O7 * sizeof(greg_t))
+FPU_D0 offsetof (fpregset_t, fpu_fr.fpu_dregs[0])
+FPU_D2 offsetof (fpregset_t, fpu_fr.fpu_dregs[1])
+FPU_D4 offsetof (fpregset_t, fpu_fr.fpu_dregs[2])
+FPU_D6 offsetof (fpregset_t, fpu_fr.fpu_dregs[3])
+FPU_D8 offsetof (fpregset_t, fpu_fr.fpu_dregs[4])
+FPU_D10 offsetof (fpregset_t, fpu_fr.fpu_dregs[5])
+FPU_D12 offsetof (fpregset_t, fpu_fr.fpu_dregs[6])
+FPU_D14 offsetof (fpregset_t, fpu_fr.fpu_dregs[7])
+FPU_D16 offsetof (fpregset_t, fpu_fr.fpu_dregs[8])
+FPU_D18 offsetof (fpregset_t, fpu_fr.fpu_dregs[9])
+FPU_D20 offsetof (fpregset_t, fpu_fr.fpu_dregs[10])
+FPU_D22 offsetof (fpregset_t, fpu_fr.fpu_dregs[11])
+FPU_D24 offsetof (fpregset_t, fpu_fr.fpu_dregs[12])
+FPU_D26 offsetof (fpregset_t, fpu_fr.fpu_dregs[13])
+FPU_D28 offsetof (fpregset_t, fpu_fr.fpu_dregs[14])
+FPU_D30 offsetof (fpregset_t, fpu_fr.fpu_dregs[15])
+FPU_Q offsetof (fpregset_t, fpu_q)
+FPU_FSR offsetof (fpregset_t, fpu_fsr)
+FPU_QCNT offsetof (fpregset_t, fpu_qcnt)
+FPU_Q_ENTRY_SZ offsetof (fpregset_t, fpu_q_entrysize)
+FPU_EN offsetof (fpregset_t, fpu_en)
+XRS_ID offsetof (xrs_t, xrs_id)
+XRS_PTR offsetof (xrs_t, xrs_ptr)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S b/sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S
index 27487d8ed9..2c89558b2d 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S
@@ -27,6 +27,7 @@ ENTRY(syscall)
mov %o3,%o2
mov %o4,%o3
mov %o5,%o4
+ ldx [%sp + STACK_BIAS + 176],%o5
ta 0x6d
diff --git a/sysdeps/unix/sysv/linux/sys/user.h b/sysdeps/unix/sysv/linux/sys/user.h
index 30e9b57ab7..03e56c3d7f 100644
--- a/sysdeps/unix/sysv/linux/sys/user.h
+++ b/sysdeps/unix/sysv/linux/sys/user.h
@@ -1 +1 @@
-#include <linux/user.h>
+#error "This file is machine-dependent and not provided for this machine."
diff --git a/sysdeps/unix/sysv/linux/times.c b/sysdeps/unix/sysv/linux/times.c
new file mode 100644
index 0000000000..42d265dc87
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/times.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 2008 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 <errno.h>
+#include <sys/times.h>
+#include <sysdep.h>
+
+
+clock_t
+__times (struct tms *buf)
+{
+ INTERNAL_SYSCALL_DECL (err);
+ clock_t ret = INTERNAL_SYSCALL (times, err, 1, buf);
+ if (INTERNAL_SYSCALL_ERROR_P (ret, err)
+ && __builtin_expect (INTERNAL_SYSCALL_ERRNO (ret, err) == EFAULT, 0))
+ {
+ /* This might be an error or not. For architectures which have
+ no separate return value and error indicators we cannot
+ distinguish a return value of -1 from an error. Do it the
+ hard way. We crash applications which pass in an invalid BUF
+ pointer. */
+#define touch(v) \
+ do { \
+ clock_t temp = v; \
+ asm volatile ("" : "+r" (temp)); \
+ v = temp; \
+ } while (0)
+ touch (buf->tms_utime);
+ touch (buf->tms_stime);
+ touch (buf->tms_cutime);
+ touch (buf->tms_cstime);
+
+ /* If we come here the memory is valid and the kernel did not
+ return an EFAULT error. Return the value given by the kernel. */
+ }
+
+ /* Return value (clock_t) -1 signals an error, but if there wasn't any,
+ return the following value. */
+ if (ret == (clock_t) -1)
+ return (clock_t) 0;
+
+ return ret;
+}
+weak_alias (__times, times)
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
index edbdac0e34..da82093381 100644
--- a/sysdeps/x86_64/Makefile
+++ b/sysdeps/x86_64/Makefile
@@ -13,3 +13,13 @@ endif
ifeq ($(subdir),string)
sysdep_routines += cacheinfo
endif
+
+ifeq ($(subdir),elf)
+sysdep-dl-routines += tlsdesc dl-tlsdesc
+sysdep_routines += tlsdesc dl-tlsdesc
+sysdep-rtld-routines += tlsdesc dl-tlsdesc
+endif
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tlsdesc.sym
+endif
diff --git a/sysdeps/x86_64/bits/byteswap.h b/sysdeps/x86_64/bits/byteswap.h
index ec2b17889d..08b38e8523 100644
--- a/sysdeps/x86_64/bits/byteswap.h
+++ b/sysdeps/x86_64/bits/byteswap.h
@@ -1,5 +1,5 @@
/* Macros to swap the order of bytes in integer values.
- Copyright (C) 1997, 1998, 2000, 2002, 2003, 2007
+ Copyright (C) 1997, 1998, 2000, 2002, 2003, 2007, 2008
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,7 +18,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#if !defined _BYTESWAP_H && !defined _NETINET_IN_H
+#if !defined _BYTESWAP_H && !defined _NETINET_IN_H && !defined _ENDIAN_H
# error "Never use <bits/byteswap.h> directly; include <byteswap.h> instead."
#endif
diff --git a/sysdeps/x86_64/bits/linkmap.h b/sysdeps/x86_64/bits/linkmap.h
index 8ea7157156..dd0d140874 100644
--- a/sysdeps/x86_64/bits/linkmap.h
+++ b/sysdeps/x86_64/bits/linkmap.h
@@ -3,6 +3,7 @@ struct link_map_machine
{
Elf64_Addr plt; /* Address of .plt + 0x16 */
Elf64_Addr gotplt; /* Address of .got + 0x18 */
+ void *tlsdesc_table; /* Address of TLS descriptor hash table. */
};
#else
@@ -10,5 +11,6 @@ struct link_map_machine
{
Elf32_Addr plt; /* Address of .plt + 0x16 */
Elf32_Addr gotplt; /* Address of .got + 0x0c */
+ void *tlsdesc_table; /* Address of TLS descriptor hash table. */
};
#endif
diff --git a/sysdeps/x86_64/dl-lookupcfg.h b/sysdeps/x86_64/dl-lookupcfg.h
new file mode 100644
index 0000000000..2af2b9e8fa
--- /dev/null
+++ b/sysdeps/x86_64/dl-lookupcfg.h
@@ -0,0 +1,28 @@
+/* Configuration of lookup functions.
+ Copyright (C) 2005, 2008 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 DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+struct link_map;
+
+extern void internal_function _dl_unmap (struct link_map *map);
+
+#define DL_UNMAP(map) _dl_unmap (map)
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index 31a7013d50..959b1328d7 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -26,6 +26,7 @@
#include <sys/param.h>
#include <sysdep.h>
#include <tls.h>
+#include <dl-tlsdesc.h>
/* Return nonzero iff ELF header is compatible with the running host. */
static inline int __attribute__ ((unused))
@@ -131,6 +132,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
got[2] = (Elf64_Addr) &_dl_runtime_resolve;
}
+ if (l->l_info[ADDRIDX (DT_TLSDESC_GOT)] && lazy)
+ *(Elf64_Addr*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_GOT)]) + l->l_addr)
+ = (Elf64_Addr) &_dl_tlsdesc_resolve_rela;
+
return lazy;
}
@@ -194,7 +199,9 @@ _dl_start_user:\n\
# define elf_machine_type_class(type) \
((((type) == R_X86_64_JUMP_SLOT \
|| (type) == R_X86_64_DTPMOD64 \
- || (type) == R_X86_64_DTPOFF64 || (type) == R_X86_64_TPOFF64) \
+ || (type) == R_X86_64_DTPOFF64 \
+ || (type) == R_X86_64_TPOFF64 \
+ || (type) == R_X86_64_TLSDESC) \
* ELF_RTYPE_CLASS_PLT) \
| (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY))
#else
@@ -323,6 +330,41 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
*reloc_addr = sym->st_value + reloc->r_addend;
# endif
break;
+ case R_X86_64_TLSDESC:
+ {
+ struct tlsdesc volatile *td =
+ (struct tlsdesc volatile *)reloc_addr;
+
+# ifndef RTLD_BOOTSTRAP
+ if (! sym)
+ {
+ td->arg = (void*)reloc->r_addend;
+ td->entry = _dl_tlsdesc_undefweak;
+ }
+ else
+# endif
+ {
+# ifndef RTLD_BOOTSTRAP
+# ifndef SHARED
+ CHECK_STATIC_TLS (map, sym_map);
+# else
+ if (!TRY_STATIC_TLS (map, sym_map))
+ {
+ td->arg = _dl_make_tlsdesc_dynamic
+ (sym_map, sym->st_value + reloc->r_addend);
+ td->entry = _dl_tlsdesc_dynamic;
+ }
+ else
+# endif
+# endif
+ {
+ td->arg = (void*)(sym->st_value - sym_map->l_tls_offset
+ + reloc->r_addend);
+ td->entry = _dl_tlsdesc_return;
+ }
+ }
+ break;
+ }
case R_X86_64_TPOFF64:
/* The offset is negative, forward from the thread pointer. */
# ifndef RTLD_BOOTSTRAP
@@ -435,6 +477,15 @@ elf_machine_lazy_rel (struct link_map *map,
map->l_mach.plt
+ (((Elf64_Addr) reloc_addr) - map->l_mach.gotplt) * 2;
}
+ else if (__builtin_expect (r_type == R_X86_64_TLSDESC, 1))
+ {
+ struct tlsdesc volatile * __attribute__((__unused__)) td =
+ (struct tlsdesc volatile *)reloc_addr;
+
+ td->arg = (void*)reloc;
+ td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
+ + map->l_addr);
+ }
else
_dl_reloc_bad_type (map, r_type, 1);
}
diff --git a/sysdeps/x86_64/dl-tls.h b/sysdeps/x86_64/dl-tls.h
index 3e4768dc1f..9b389edb4a 100644
--- a/sysdeps/x86_64/dl-tls.h
+++ b/sysdeps/x86_64/dl-tls.h
@@ -1,5 +1,5 @@
/* Thread-local storage handling in the ELF dynamic linker. x86-64 version.
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 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
@@ -19,7 +19,7 @@
/* Type used for the representation of TLS information in the GOT. */
-typedef struct
+typedef struct dl_tls_index
{
unsigned long int ti_module;
unsigned long int ti_offset;
diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S
new file mode 100644
index 0000000000..5eac1f2a5b
--- /dev/null
+++ b/sysdeps/x86_64/dl-tlsdesc.S
@@ -0,0 +1,245 @@
+/* Thread-local storage handling in the ELF dynamic linker. x86_64 version.
+ Copyright (C) 2004, 2005, 2008 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 "tlsdesc.h"
+
+ .text
+
+ /* This function is used to compute the TP offset for symbols in
+ Static TLS, i.e., whose TP offset is the same for all
+ threads.
+
+ The incoming %rax points to the TLS descriptor, such that
+ 0(%rax) points to _dl_tlsdesc_return itself, and 8(%rax) holds
+ the TP offset of the symbol corresponding to the object
+ denoted by the argument. */
+
+ .hidden _dl_tlsdesc_return
+ .global _dl_tlsdesc_return
+ .type _dl_tlsdesc_return,@function
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_return:
+ movq 8(%rax), %rax
+ ret
+ cfi_endproc
+ .size _dl_tlsdesc_return, .-_dl_tlsdesc_return
+
+ /* This function is used for undefined weak TLS symbols, for
+ which the base address (i.e., disregarding any addend) should
+ resolve to NULL.
+
+ %rax points to the TLS descriptor, such that 0(%rax) points to
+ _dl_tlsdesc_undefweak itself, and 8(%rax) holds the addend.
+ We return the addend minus the TP, such that, when the caller
+ adds TP, it gets the addend back. If that's zero, as usual,
+ that's most likely a NULL pointer. */
+
+ .hidden _dl_tlsdesc_undefweak
+ .global _dl_tlsdesc_undefweak
+ .type _dl_tlsdesc_undefweak,@function
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_undefweak:
+ movq 8(%rax), %rax
+ subq %fs:0, %rax
+ ret
+ cfi_endproc
+ .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
+
+#ifdef SHARED
+ .hidden _dl_tlsdesc_dynamic
+ .global _dl_tlsdesc_dynamic
+ .type _dl_tlsdesc_dynamic,@function
+
+ /* %rax points to the TLS descriptor, such that 0(%rax) points to
+ _dl_tlsdesc_dynamic itself, and 8(%rax) points to a struct
+ tlsdesc_dynamic_arg object. It must return in %rax the offset
+ between the thread pointer and the object denoted by the
+ argument, without clobbering any registers.
+
+ The assembly code that follows is a rendition of the following
+ C code, hand-optimized a little bit.
+
+ptrdiff_t
+_dl_tlsdesc_dynamic (register struct tlsdesc *tdp asm ("%rax"))
+{
+ struct tlsdesc_dynamic_arg *td = tdp->arg;
+ dtv_t *dtv = *(dtv_t **)((char *)__thread_pointer + DTV_OFFSET);
+ if (__builtin_expect (td->gen_count <= dtv[0].counter
+ && (dtv[td->tlsinfo.ti_module].pointer.val
+ != TLS_DTV_UNALLOCATED),
+ 1))
+ return dtv[td->tlsinfo.ti_module].pointer.val + td->tlsinfo.ti_offset
+ - __thread_pointer;
+
+ return __tls_get_addr_internal (&td->tlsinfo) - __thread_pointer;
+}
+*/
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_dynamic:
+ /* Preserve call-clobbered registers that we modify.
+ We need two scratch regs anyway. */
+ movq %rsi, -16(%rsp)
+ movq %fs:DTV_OFFSET, %rsi
+ movq %rdi, -8(%rsp)
+ movq TLSDESC_ARG(%rax), %rdi
+ movq (%rsi), %rax
+ cmpq %rax, TLSDESC_GEN_COUNT(%rdi)
+ ja .Lslow
+ movq TLSDESC_MODID(%rdi), %rax
+ salq $4, %rax
+ movq (%rax,%rsi), %rax
+ cmpq $-1, %rax
+ je .Lslow
+ addq TLSDESC_MODOFF(%rdi), %rax
+.Lret:
+ movq -16(%rsp), %rsi
+ subq %fs:0, %rax
+ movq -8(%rsp), %rdi
+ ret
+.Lslow:
+ /* Besides rdi and rsi, saved above, save rdx, rcx, r8, r9,
+ r10 and r11. Also, align the stack, that's off by 8 bytes. */
+ subq $72, %rsp
+ cfi_adjust_cfa_offset (72)
+ movq %rdx, 8(%rsp)
+ movq %rcx, 16(%rsp)
+ movq %r8, 24(%rsp)
+ movq %r9, 32(%rsp)
+ movq %r10, 40(%rsp)
+ movq %r11, 48(%rsp)
+ /* %rdi already points to the tlsinfo data structure. */
+ call __tls_get_addr@PLT
+ movq 8(%rsp), %rdx
+ movq 16(%rsp), %rcx
+ movq 24(%rsp), %r8
+ movq 32(%rsp), %r9
+ movq 40(%rsp), %r10
+ movq 48(%rsp), %r11
+ addq $72, %rsp
+ cfi_adjust_cfa_offset (-72)
+ jmp .Lret
+ cfi_endproc
+ .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
+#endif /* SHARED */
+
+ /* This function is a wrapper for a lazy resolver for TLS_DESC
+ RELA relocations. The incoming 0(%rsp) points to the caller's
+ link map, pushed by the dynamic object's internal lazy TLS
+ resolver front-end before tail-calling us. We need to pop it
+ ourselves. %rax points to a TLS descriptor, such that 0(%rax)
+ holds the address of the internal resolver front-end (unless
+ some other thread beat us to resolving it) and 8(%rax) holds a
+ pointer to the relocation.
+
+ When the actual resolver returns, it will have adjusted the
+ TLS descriptor such that we can tail-call it for it to return
+ the TP offset of the symbol. */
+
+ .hidden _dl_tlsdesc_resolve_rela
+ .global _dl_tlsdesc_resolve_rela
+ .type _dl_tlsdesc_resolve_rela,@function
+ cfi_startproc
+ .align 16
+ /* The PLT entry will have pushed the link_map pointer. */
+_dl_tlsdesc_resolve_rela:
+ cfi_adjust_cfa_offset (8)
+ /* Save all call-clobbered registers. */
+ subq $72, %rsp
+ cfi_adjust_cfa_offset (72)
+ movq %rax, (%rsp)
+ movq %rdi, 8(%rsp)
+ movq %rax, %rdi /* Pass tlsdesc* in %rdi. */
+ movq %rsi, 16(%rsp)
+ movq 72(%rsp), %rsi /* Pass link_map* in %rsi. */
+ movq %r8, 24(%rsp)
+ movq %r9, 32(%rsp)
+ movq %r10, 40(%rsp)
+ movq %r11, 48(%rsp)
+ movq %rdx, 56(%rsp)
+ movq %rcx, 64(%rsp)
+ call _dl_tlsdesc_resolve_rela_fixup
+ movq (%rsp), %rax
+ movq 8(%rsp), %rdi
+ movq 16(%rsp), %rsi
+ movq 24(%rsp), %r8
+ movq 32(%rsp), %r9
+ movq 40(%rsp), %r10
+ movq 48(%rsp), %r11
+ movq 56(%rsp), %rdx
+ movq 64(%rsp), %rcx
+ addq $80, %rsp
+ cfi_adjust_cfa_offset (-80)
+ jmp *(%rax)
+ cfi_endproc
+ .size _dl_tlsdesc_resolve_rela, .-_dl_tlsdesc_resolve_rela
+
+ /* This function is a placeholder for lazy resolving of TLS
+ relocations. Once some thread starts resolving a TLS
+ relocation, it sets up the TLS descriptor to use this
+ resolver, such that other threads that would attempt to
+ resolve it concurrently may skip the call to the original lazy
+ resolver and go straight to a condition wait.
+
+ When the actual resolver returns, it will have adjusted the
+ TLS descriptor such that we can tail-call it for it to return
+ the TP offset of the symbol. */
+
+ .hidden _dl_tlsdesc_resolve_hold
+ .global _dl_tlsdesc_resolve_hold
+ .type _dl_tlsdesc_resolve_hold,@function
+ cfi_startproc
+ .align 16
+_dl_tlsdesc_resolve_hold:
+0:
+ /* Save all call-clobbered registers. */
+ subq $72, %rsp
+ cfi_adjust_cfa_offset (72)
+ movq %rax, (%rsp)
+ movq %rdi, 8(%rsp)
+ movq %rax, %rdi /* Pass tlsdesc* in %rdi. */
+ movq %rsi, 16(%rsp)
+ /* Pass _dl_tlsdesc_resolve_hold's address in %rsi. */
+ leaq . - _dl_tlsdesc_resolve_hold(%rip), %rsi
+ movq %r8, 24(%rsp)
+ movq %r9, 32(%rsp)
+ movq %r10, 40(%rsp)
+ movq %r11, 48(%rsp)
+ movq %rdx, 56(%rsp)
+ movq %rcx, 64(%rsp)
+ call _dl_tlsdesc_resolve_hold_fixup
+1:
+ movq (%rsp), %rax
+ movq 8(%rsp), %rdi
+ movq 16(%rsp), %rsi
+ movq 24(%rsp), %r8
+ movq 32(%rsp), %r9
+ movq 40(%rsp), %r10
+ movq 48(%rsp), %r11
+ movq 56(%rsp), %rdx
+ movq 64(%rsp), %rcx
+ addq $72, %rsp
+ cfi_adjust_cfa_offset (-72)
+ jmp *(%eax)
+ cfi_endproc
+ .size _dl_tlsdesc_resolve_hold, .-_dl_tlsdesc_resolve_hold
diff --git a/sysdeps/x86_64/dl-tlsdesc.h b/sysdeps/x86_64/dl-tlsdesc.h
new file mode 100644
index 0000000000..9e64aab5a7
--- /dev/null
+++ b/sysdeps/x86_64/dl-tlsdesc.h
@@ -0,0 +1,64 @@
+/* Thread-local storage descriptor handling in the ELF dynamic linker.
+ x86_64 version.
+ Copyright (C) 2005, 2008 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 _X86_64_DL_TLSDESC_H
+# define _X86_64_DL_TLSDESC_H 1
+
+/* Use this to access DT_TLSDESC_PLT and DT_TLSDESC_GOT. */
+#ifndef ADDRIDX
+# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ + DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
+#endif
+
+/* Type used to represent a TLS descriptor in the GOT. */
+struct tlsdesc
+{
+ ptrdiff_t (*entry)(struct tlsdesc *on_rax);
+ void *arg;
+};
+
+typedef struct dl_tls_index
+{
+ unsigned long int ti_module;
+ unsigned long int ti_offset;
+} tls_index;
+
+/* 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 *on_rax),
+ _dl_tlsdesc_undefweak(struct tlsdesc *on_rax),
+ _dl_tlsdesc_resolve_rela(struct tlsdesc *on_rax),
+ _dl_tlsdesc_resolve_hold(struct tlsdesc *on_rax);
+
+# ifdef SHARED
+extern void *internal_function _dl_make_tlsdesc_dynamic (struct link_map *map,
+ size_t ti_offset);
+
+extern ptrdiff_t attribute_hidden _dl_tlsdesc_dynamic(struct tlsdesc *);
+# endif
+
+#endif
diff --git a/sysdeps/x86_64/tlsdesc.c b/sysdeps/x86_64/tlsdesc.c
new file mode 100644
index 0000000000..0cc32aab69
--- /dev/null
+++ b/sysdeps/x86_64/tlsdesc.c
@@ -0,0 +1,151 @@
+/* Manage TLS descriptors. x86_64 version.
+ Copyright (C) 2005, 2008 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 <link.h>
+#include <ldsodefs.h>
+#include <elf/dynamic-link.h>
+#include <tls.h>
+#include <dl-tlsdesc.h>
+#include <tlsdeschtab.h>
+
+/* The following 2 functions take a caller argument, that contains the
+ address expected to be in the TLS descriptor. If it's changed, we
+ want to return immediately. */
+
+/* This function is used to lazily resolve TLS_DESC RELA relocations.
+ The argument location is used to hold a pointer to the relocation. */
+
+void
+attribute_hidden
+_dl_tlsdesc_resolve_rela_fixup (struct tlsdesc volatile *td,
+ struct link_map *l)
+{
+ const ElfW(Rela) *reloc = td->arg;
+
+ if (_dl_tlsdesc_resolve_early_return_p
+ (td, (void*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_PLT)]) + l->l_addr)))
+ return;
+
+ /* The code below was borrowed from _dl_fixup(). */
+ const ElfW(Sym) *const symtab
+ = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
+ lookup_t result;
+
+ /* Look up the target symbol. If the normal lookup rules are not
+ used don't look in the global scope. */
+ if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
+ && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
+ {
+ const struct r_found_version *version = NULL;
+
+ if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ const ElfW(Half) *vernum =
+ (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
+ ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
+ version = &l->l_versions[ndx];
+ if (version->hash == 0)
+ version = NULL;
+ }
+
+ result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
+ l->l_scope, version, ELF_RTYPE_CLASS_PLT,
+ DL_LOOKUP_ADD_DEPENDENCY, NULL);
+ }
+ else
+ {
+ /* We already found the symbol. The module (and therefore its load
+ address) is also known. */
+ result = l;
+ }
+
+ if (! sym)
+ {
+ td->arg = (void*)reloc->r_addend;
+ td->entry = _dl_tlsdesc_undefweak;
+ }
+ else
+ {
+# ifndef SHARED
+ CHECK_STATIC_TLS (l, result);
+# else
+ if (!TRY_STATIC_TLS (l, result))
+ {
+ td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value
+ + reloc->r_addend);
+ td->entry = _dl_tlsdesc_dynamic;
+ }
+ else
+# endif
+ {
+ td->arg = (void*)(sym->st_value - result->l_tls_offset
+ + reloc->r_addend);
+ td->entry = _dl_tlsdesc_return;
+ }
+ }
+
+ _dl_tlsdesc_wake_up_held_fixups ();
+}
+
+/* This function is used to avoid busy waiting for other threads to
+ complete the lazy relocation. Once another thread wins the race to
+ relocate a TLS descriptor, it sets the descriptor up such that this
+ function is called to wait until the resolver releases the
+ lock. */
+
+void
+attribute_hidden
+_dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td,
+ void *caller)
+{
+ /* Maybe we're lucky and can return early. */
+ if (caller != td->entry)
+ return;
+
+ /* Locking here will stop execution until the running resolver runs
+ _dl_tlsdesc_wake_up_held_fixups(), releasing the lock.
+
+ FIXME: We'd be better off waiting on a condition variable, such
+ that we didn't have to hold the lock throughout the relocation
+ processing. */
+ __rtld_lock_lock_recursive (GL(dl_load_lock));
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+}
+
+/* Unmap the dynamic object, but also release its TLS descriptor table
+ if there is one. */
+
+void
+internal_function
+_dl_unmap (struct link_map *map)
+{
+ __munmap ((void *) (map)->l_map_start,
+ (map)->l_map_end - (map)->l_map_start);
+
+#if SHARED
+ /* _dl_unmap is only called for dlopen()ed libraries, for which
+ calling free() is safe, or before we've completed the initial
+ relocation, in which case calling free() is probably pointless,
+ but still safe. */
+ if (map->l_mach.tlsdesc_table)
+ htab_delete (map->l_mach.tlsdesc_table);
+#endif
+}
diff --git a/sysdeps/x86_64/tlsdesc.sym b/sysdeps/x86_64/tlsdesc.sym
new file mode 100644
index 0000000000..33854975d0
--- /dev/null
+++ b/sysdeps/x86_64/tlsdesc.sym
@@ -0,0 +1,17 @@
+#include <stddef.h>
+#include <sysdep.h>
+#include <tls.h>
+#include <link.h>
+#include <dl-tlsdesc.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+
+DTV_OFFSET offsetof(struct pthread, header.dtv)
+
+TLSDESC_ARG offsetof(struct tlsdesc, arg)
+
+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)