diff options
author | Jakub Jelinek <jakub@redhat.com> | 2008-05-15 07:57:49 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2008-05-15 07:57:49 +0000 |
commit | 78463734c14d180e4d8e16c6e66fb213fc3479c0 (patch) | |
tree | 718b7357ea9e63d4a951a0a725105619b97d2977 /sysdeps | |
parent | ef73dbc1301bc42c132d15ae6ca866233c0beeb4 (diff) |
Updated to fedora-glibc-20080515T0735cvs/fedora-glibc-2_8_90-1
Diffstat (limited to 'sysdeps')
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) |