diff options
Diffstat (limited to 'libpthread/nptl/sysdeps/x86_64')
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/Makefile.arch | 53 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/dl-tls.h | 29 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h | 31 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c | 1 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c | 1 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S | 40 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S | 31 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/pthreaddef.h | 43 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym | 28 | ||||
-rw-r--r-- | libpthread/nptl/sysdeps/x86_64/tls.h | 438 |
10 files changed, 695 insertions, 0 deletions
diff --git a/libpthread/nptl/sysdeps/x86_64/Makefile.arch b/libpthread/nptl/sysdeps/x86_64/Makefile.arch new file mode 100644 index 000000000..b17c321dc --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/Makefile.arch @@ -0,0 +1,53 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = pthread_spin_lock.c +libpthread_SSRC = pthread_spin_trylock.S + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-x86_64 = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/x86_64 +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/x86_64 +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + @sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/x86_64/dl-tls.h b/libpthread/nptl/sysdeps/x86_64/dl-tls.h new file mode 100644 index 000000000..3e4768dc1 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. x86-64 version. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.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. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h new file mode 100644 index 000000000..345ed557c --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_RSP] - (_adj)) + +/* We use the normal lobngjmp for unwinding. */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c new file mode 100644 index 000000000..55696204c --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c @@ -0,0 +1 @@ +#include "../i386/pthread_spin_init.c" diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c new file mode 100644 index 000000000..7cf0e0ecc --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c @@ -0,0 +1 @@ +#include "../i386/pthread_spin_lock.c" diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S new file mode 100644 index 000000000..9b5133583 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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 <pthread-errnos.h> + + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + + .globl pthread_spin_trylock + .type pthread_spin_trylock,@function + .align 16 +pthread_spin_trylock: + movl $1, %eax + xorl %ecx, %ecx + LOCK + cmpxchgl %ecx, (%rdi) + movl $EBUSY, %eax + cmovel %ecx, %eax + retq + .size pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S new file mode 100644 index 000000000..d3e13bde9 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S @@ -0,0 +1,31 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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. */ + + .globl pthread_spin_unlock + .type pthread_spin_unlock,@function + .align 16 +pthread_spin_unlock: + movl $1, (%rdi) + xorl %eax, %eax + retq + .size pthread_spin_unlock,.-pthread_spin_unlock + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/x86_64/pthreaddef.h b/libpthread/nptl/sysdeps/x86_64/pthreaddef.h new file mode 100644 index 000000000..b33c18638 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthreaddef.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. SSE requires 16 + bytes. */ +#define STACK_ALIGN 16 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 16 + + +/* Location of current stack frame. The frame pointer is not usable. */ +#define CURRENT_STACK_FRAME \ + ({ char *frame; __asm__ ("movq %%rsp, %0" : "=r" (frame)); frame; }) + + +/* XXX Until we have a better place keep the definitions here. */ + +/* While there is no such syscall. */ +#define __exit_thread_inline(val) \ + __asm__ volatile ("syscall" :: "a" (__NR_exit), "D" (val)) diff --git a/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym b/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym new file mode 100644 index 000000000..cf863752e --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym @@ -0,0 +1,28 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +PID offsetof (struct pthread, pid) +CANCELHANDLING offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) +CLEANUP offsetof (struct pthread, cleanup) +CLEANUP_PREV offsetof (struct _pthread_cleanup_buffer, __prev) +MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) +MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +POINTER_GUARD offsetof (tcbhead_t, pointer_guard) +VGETCPU_CACHE_OFFSET offsetof (tcbhead_t, vgetcpu_cache) +#ifndef __ASSUME_PRIVATE_FUTEX +PRIVATE_FUTEX offsetof (tcbhead_t, private_futex) +#endif +RTLD_SAVESPACE_SSE offsetof (tcbhead_t, rtld_savespace_sse) + +-- Not strictly offsets, but these values are also used in the TCB. +TCB_CANCELSTATE_BITMASK CANCELSTATE_BITMASK +TCB_CANCELTYPE_BITMASK CANCELTYPE_BITMASK +TCB_CANCELING_BITMASK CANCELING_BITMASK +TCB_CANCELED_BITMASK CANCELED_BITMASK +TCB_EXITING_BITMASK EXITING_BITMASK +TCB_CANCEL_RESTMASK CANCEL_RESTMASK +TCB_TERMINATED_BITMASK TERMINATED_BITMASK +TCB_PTHREAD_CANCELED PTHREAD_CANCELED diff --git a/libpthread/nptl/sysdeps/x86_64/tls.h b/libpthread/nptl/sysdeps/x86_64/tls.h new file mode 100644 index 000000000..396ad4213 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/tls.h @@ -0,0 +1,438 @@ +/* Definition for thread-local data handling. nptl/x86_64 version. + Copyright (C) 2002-2007, 2008, 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H 1 + +#ifndef __ASSEMBLER__ +# include <asm/prctl.h> /* For ARCH_SET_FS. */ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <sysdep.h> +# include <bits/kernel-features.h> +# include <bits/wordsize.h> +# include <xmmintrin.h> + + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessarily the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; + int gscope_flag; + uintptr_t sysinfo; + uintptr_t stack_guard; + uintptr_t pointer_guard; + unsigned long int vgetcpu_cache[2]; +# ifndef __ASSUME_PRIVATE_FUTEX + int private_futex; +# else + int __unused1; +# endif +# if __WORDSIZE == 64 + int rtld_must_xmm_save; +# endif + /* Reservation of some values for the TM ABI. */ + void *__private_tm[5]; +# if __WORDSIZE == 64 + long int __unused2; + /* Have space for the post-AVX register size. */ + __m128 rtld_savespace_sse[8][4]; + + void *__padding[8]; +# endif +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT 1 +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 + +/* Signal that TLS support is available. */ +#define USE_TLS 1 + +/* Alignment requirement for the stack. */ +#define STACK_ALIGN 16 + + +#ifndef __ASSEMBLER__ +/* Get system call information. */ +# include <sysdep.h> + + +/* Get the thread descriptor definition. */ +# include <descr.h> + +#ifndef LOCK_PREFIX +# ifdef UP +# define LOCK_PREFIX /* nothing */ +# else +# define LOCK_PREFIX "lock;" +# endif +#endif + +/* This is the size of the initial TCB. Can't be just sizeof (tcbhead_t), + because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole + struct pthread even when not linked with -lpthread. */ +# define TLS_INIT_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +//# define TLS_TCB_ALIGN __alignof__ (struct pthread) +// Normally the above would be correct But we have to store post-AVX +// vector registers in the TCB and we want the storage to be aligned. +// unfortunately there isn't yet a type for these values and hence no +// 32-byte alignment requirement. Make this explicit, for now. +# define TLS_TCB_ALIGN 32 + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtvp) \ + ({ struct pthread *__pd; \ + THREAD_SETMEM (__pd, header.dtv, (dtvp)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + + +/* Macros to load from and store into segment registers. */ +# define TLS_GET_FS() \ + ({ int __seg; __asm__ ("movl %%fs, %0" : "=q" (__seg)); __seg; }) +# define TLS_SET_FS(val) \ + __asm__ ("movl %0, %%fs" :: "q" (val)) + + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. + + We have to make the syscall for both uses of the macro since the + address might be (and probably is) different. */ +# define TLS_INIT_TP(thrdescr, secondcall) \ + ({ void *_thrdescr = (thrdescr); \ + tcbhead_t *_head = _thrdescr; \ + int _result; \ + \ + _head->tcb = _thrdescr; \ + /* For now the thread descriptor is at the same address. */ \ + _head->self = _thrdescr; \ + \ + /* It is a simple syscall to set the %fs value for the thread. */ \ + __asm__ volatile ("syscall" \ + : "=a" (_result) \ + : "0" ((unsigned long int) __NR_arch_prctl), \ + "D" ((unsigned long int) ARCH_SET_FS), \ + "S" (_thrdescr) \ + : "memory", "cc", "r11", "cx"); \ + \ + _result ? "cannot set %fs base address for thread-local storage" : 0; \ + }) + + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct pthread *__pd; \ + THREAD_GETMEM (__pd, header.dtv); }) + + +/* Return the thread descriptor for the current thread. + + The contained asm must *not* be marked volatile since otherwise + assignments like + pthread_descr self = thread_self(); + do not get optimized away. */ +# define THREAD_SELF \ + ({ struct pthread *__self; \ + __asm__ ("movq %%fs:%c1,%q0" : "=r" (__self) \ + : "i" (offsetof (struct pthread, header.self))); \ + __self;}) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF_INCLUDE <sys/reg.h> /* For the FS constant. */ +# define DB_THREAD_SELF CONST_THREAD_AREA (64, FS) + +/* Read member of the thread descriptor directly. */ +# define THREAD_GETMEM(descr, member) \ + ({ __typeof (descr->member) __value; \ + if (sizeof (__value) == 1) \ + __asm__ volatile ("movb %%fs:%P2,%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member))); \ + else if (sizeof (__value) == 4) \ + __asm__ volatile ("movl %%fs:%P1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movq %%fs:%P1,%q0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member))); \ + } \ + __value; }) + + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +# define THREAD_GETMEM_NC(descr, member, idx) \ + ({ __typeof (descr->member[0]) __value; \ + if (sizeof (__value) == 1) \ + __asm__ volatile ("movb %%fs:%P2(%q3),%b0" \ + : "=q" (__value) \ + : "0" (0), "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else if (sizeof (__value) == 4) \ + __asm__ volatile ("movl %%fs:%P1(,%q2,4),%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member[0])), "r" (idx));\ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movq %%fs:%P1(,%q2,8),%q0" \ + : "=r" (__value) \ + : "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + } \ + __value; }) + + +/* Loading addresses of objects on x86-64 needs to be treated special + when generating PIC code. */ +#ifdef __pic__ +# define IMM_MODE "nr" +#else +# define IMM_MODE "ir" +#endif + + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +# define THREAD_SETMEM(descr, member, value) \ + ({ if (sizeof (descr->member) == 1) \ + __asm__ volatile ("movb %b0,%%fs:%P1" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member))); \ + else if (sizeof (descr->member) == 4) \ + __asm__ volatile ("movl %0,%%fs:%P1" : \ + : IMM_MODE (value), \ + "i" (offsetof (struct pthread, member))); \ + else \ + { \ + if (sizeof (descr->member) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movq %q0,%%fs:%P1" : \ + : IMM_MODE ((unsigned long int) value), \ + "i" (offsetof (struct pthread, member))); \ + }}) + + +/* Set member of the thread descriptor directly. */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ + ({ if (sizeof (descr->member[0]) == 1) \ + __asm__ volatile ("movb %b0,%%fs:%P1(%q2)" : \ + : "iq" (value), \ + "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else if (sizeof (descr->member[0]) == 4) \ + __asm__ volatile ("movl %0,%%fs:%P1(,%q2,4)" : \ + : IMM_MODE (value), \ + "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + else \ + { \ + if (sizeof (descr->member[0]) != 8) \ + /* There should not be any value with a size other than 1, \ + 4 or 8. */ \ + abort (); \ + \ + __asm__ volatile ("movq %q0,%%fs:%P1(,%q2,8)" : \ + : IMM_MODE ((unsigned long int) value), \ + "i" (offsetof (struct pthread, member[0])), \ + "r" (idx)); \ + }}) + + +/* Atomic compare and exchange on TLS, returning old value. */ +# define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \ + ({ __typeof (descr->member) __ret; \ + __typeof (oldval) __old = (oldval); \ + if (sizeof (descr->member) == 4) \ + __asm__ volatile (LOCK_PREFIX "cmpxchgl %2, %%fs:%P3" \ + : "=a" (__ret) \ + : "0" (__old), "r" (newval), \ + "i" (offsetof (struct pthread, member))); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); \ + __ret; }) + + +/* Atomic logical and. */ +# define THREAD_ATOMIC_AND(descr, member, val) \ + (void) ({ if (sizeof ((descr)->member) == 4) \ + __asm__ volatile (LOCK_PREFIX "andl %1, %%fs:%P0" \ + :: "i" (offsetof (struct pthread, member)), \ + "ir" (val)); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); }) + + +/* Atomic set bit. */ +# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \ + (void) ({ if (sizeof ((descr)->member) == 4) \ + __asm__ volatile (LOCK_PREFIX "orl %1, %%fs:%P0" \ + :: "i" (offsetof (struct pthread, member)), \ + "ir" (1 << (bit))); \ + else \ + /* Not necessary for other sizes in the moment. */ \ + abort (); }) + + +# define CALL_THREAD_FCT(descr) \ + ({ void *__res; \ + __asm__ volatile ("movq %%fs:%P2, %%rdi\n\t" \ + "callq *%%fs:%P1" \ + : "=a" (__res) \ + : "i" (offsetof (struct pthread, start_routine)), \ + "i" (offsetof (struct pthread, arg)) \ + : "di", "si", "cx", "dx", "r8", "r9", "r10", "r11", \ + "memory", "cc"); \ + __res; }) + + +/* Set the stack guard field in TCB head. */ +# define THREAD_SET_STACK_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, header.stack_guard, value) +# define THREAD_COPY_STACK_GUARD(descr) \ + ((descr)->header.stack_guard \ + = THREAD_GETMEM (THREAD_SELF, header.stack_guard)) + + +/* Set the pointer guard field in the TCB head. */ +# define THREAD_SET_POINTER_GUARD(value) \ + THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value) +# define THREAD_COPY_POINTER_GUARD(descr) \ + ((descr)->header.pointer_guard \ + = THREAD_GETMEM (THREAD_SELF, header.pointer_guard)) + + +/* Get and set the global scope generation counter in the TCB head. */ +# define THREAD_GSCOPE_FLAG_UNUSED 0 +# define THREAD_GSCOPE_FLAG_USED 1 +# define THREAD_GSCOPE_FLAG_WAIT 2 +# define THREAD_GSCOPE_RESET_FLAG() \ + do \ + { int __res; \ + __asm__ volatile ("xchgl %0, %%fs:%P1" \ + : "=r" (__res) \ + : "i" (offsetof (struct pthread, header.gscope_flag)), \ + "0" (THREAD_GSCOPE_FLAG_UNUSED)); \ + if (__res == THREAD_GSCOPE_FLAG_WAIT) \ + lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \ + } \ + while (0) +# define THREAD_GSCOPE_SET_FLAG() \ + THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED) +# define THREAD_GSCOPE_WAIT() \ + GL(dl_wait_lookup_done) () + + +# ifdef SHARED +/* Defined in dl-trampoline.S. */ +extern void _dl_x86_64_save_sse (void); +extern void _dl_x86_64_restore_sse (void); + +# define RTLD_CHECK_FOREIGN_CALL \ + (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) != 0) + +/* NB: Don't use the xchg operation because that would imply a lock + prefix which is expensive and unnecessary. The cache line is also + not contested at all. */ +# define RTLD_ENABLE_FOREIGN_CALL \ + int old_rtld_must_xmm_save = THREAD_GETMEM (THREAD_SELF, \ + header.rtld_must_xmm_save); \ + THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 1) + +# define RTLD_PREPARE_FOREIGN_CALL \ + do if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save)) \ + { \ + _dl_x86_64_save_sse (); \ + THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 0); \ + } \ + while (0) + +# define RTLD_FINALIZE_FOREIGN_CALL \ + do { \ + if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) == 0) \ + _dl_x86_64_restore_sse (); \ + THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, \ + old_rtld_must_xmm_save); \ + } while (0) +# endif + + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ |