about summary refs log tree commit diff
path: root/sysdeps/mips
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mips')
-rw-r--r--sysdeps/mips/atomicity.h113
-rw-r--r--sysdeps/mips/bits/atomic.h303
-rw-r--r--sysdeps/mips/dl-tls.h46
-rw-r--r--sysdeps/mips/dl-trampoline.c2
-rw-r--r--sysdeps/mips/elf/configure46
-rw-r--r--sysdeps/mips/elf/configure.in35
-rw-r--r--sysdeps/mips/libc-tls.c37
-rw-r--r--sysdeps/mips/sys/asm.h19
-rw-r--r--sysdeps/mips/tls-macros.h88
9 files changed, 574 insertions, 115 deletions
diff --git a/sysdeps/mips/atomicity.h b/sysdeps/mips/atomicity.h
deleted file mode 100644
index 7380e1000c..0000000000
--- a/sysdeps/mips/atomicity.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* Low-level functions for atomic operations. Mips version.
-   Copyright (C) 2001, 2002, 2003, 2004 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 _MIPS_ATOMICITY_H
-#define _MIPS_ATOMICITY_H    1
-
-#include <inttypes.h>
-#include <sgidefs.h>
-
-static inline int
-__attribute__ ((unused))
-exchange_and_add (volatile uint32_t *mem, int val)
-{
-  int result, tmp;
-
-  __asm__ __volatile__
-    ("/* Inline exchange & add */\n"
-     "1:\n\t"
-     ".set	push\n\t"
-#if _MIPS_SIM == _ABIO32
-     ".set	mips2\n\t"
-#endif
-     "ll	%0,%3\n\t"
-     "addu	%1,%4,%0\n\t"
-     "sc	%1,%2\n\t"
-     ".set	pop\n\t"
-     "beqz	%1,1b\n\t"
-     "/* End exchange & add */"
-     : "=&r"(result), "=&r"(tmp), "=m"(*mem)
-     : "m" (*mem), "r"(val)
-     : "memory");
-
-  return result;
-}
-
-static inline void
-__attribute__ ((unused))
-atomic_add (volatile uint32_t *mem, int val)
-{
-  int result;
-
-  __asm__ __volatile__
-    ("/* Inline atomic add */\n"
-     "1:\n\t"
-     ".set	push\n\t"
-#if _MIPS_SIM == _ABIO32
-     ".set	mips2\n\t"
-#endif
-     "ll	%0,%2\n\t"
-     "addu	%0,%3,%0\n\t"
-     "sc	%0,%1\n\t"
-     ".set	pop\n\t"
-     "beqz	%0,1b\n\t"
-     "/* End atomic add */"
-     : "=&r"(result), "=m"(*mem)
-     : "m" (*mem), "r"(val)
-     : "memory");
-}
-
-static inline int
-__attribute__ ((unused))
-compare_and_swap (volatile long int *p, long int oldval, long int newval)
-{
-  long int ret, temp;
-
-  __asm__ __volatile__
-    ("/* Inline compare & swap */\n"
-     "1:\n\t"
-     ".set	push\n\t"
-#if _MIPS_SIM == _ABIO32
-     ".set	mips2\n\t"
-#endif
-#if _MIPS_SIM == _ABI64
-     "lld	%1,%5\n\t"
-#else
-     "ll	%1,%5\n\t"
-#endif
-     "move	%0,$0\n\t"
-     "bne	%1,%3,2f\n\t"
-     "move	%0,%4\n\t"
-#if _MIPS_SIM == _ABI64
-     "scd	%0,%2\n\t"
-#else
-     "sc	%0,%2\n\t"
-#endif
-     ".set	pop\n\t"
-     "beqz	%0,1b\n"
-     "2:\n\t"
-     "/* End compare & swap */"
-     : "=&r" (ret), "=&r" (temp), "=m" (*p)
-     : "r" (oldval), "r" (newval), "m" (*p)
-     : "memory");
-
-  return ret;
-}
-
-#endif /* atomicity.h */
diff --git a/sysdeps/mips/bits/atomic.h b/sysdeps/mips/bits/atomic.h
new file mode 100644
index 0000000000..167d9a59c8
--- /dev/null
+++ b/sysdeps/mips/bits/atomic.h
@@ -0,0 +1,303 @@
+/* Low-level functions for atomic operations. Mips version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _MIPS_BITS_ATOMIC_H
+#define _MIPS_BITS_ATOMIC_H 1
+
+#include <inttypes.h>
+#include <sgidefs.h>
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+#if _MIPS_SIM == _ABIO32
+#define MIPS_PUSH_MIPS2 ".set	mips2\n\t"
+#else
+#define MIPS_PUSH_MIPS2
+#endif
+
+/* See the comments in <sys/asm.h> about the use of the sync instruction.  */
+#ifndef MIPS_SYNC
+# define MIPS_SYNC	sync
+#endif
+
+#define MIPS_SYNC_STR_2(X) #X
+#define MIPS_SYNC_STR_1(X) MIPS_SYNC_STR_2(X)
+#define MIPS_SYNC_STR MIPS_SYNC_STR_1(MIPS_SYNC)
+
+/* Compare and exchange.  For all of the "xxx" routines, we expect a
+   "__prev" and a "__cmp" variable to be provided by the enclosing scope,
+   in which values are returned.  */
+
+#define __arch_compare_and_exchange_xxx_8_int(mem, newval, oldval, rel, acq) \
+  (abort (), __prev = __cmp = 0)
+
+#define __arch_compare_and_exchange_xxx_16_int(mem, newval, oldval, rel, acq) \
+  (abort (), __prev = __cmp = 0)
+
+#define __arch_compare_and_exchange_xxx_32_int(mem, newval, oldval, rel, acq) \
+     __asm__ __volatile__ (						      \
+     ".set	push\n\t"						      \
+     MIPS_PUSH_MIPS2							      \
+     rel	"\n"							      \
+     "1:\t"								      \
+     "ll	%0,%4\n\t"						      \
+     "move	%1,$0\n\t"						      \
+     "bne	%0,%2,2f\n\t"						      \
+     "move	%1,%3\n\t"						      \
+     "sc	%1,%4\n\t"						      \
+     "beqz	%1,1b\n"						      \
+     acq	"\n\t"							      \
+     ".set	pop\n"							      \
+     "2:\n\t"								      \
+	      : "=&r" (__prev), "=&r" (__cmp)				      \
+	      : "r" (oldval), "r" (newval), "m" (*mem)			      \
+	      : "memory")
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32.  */
+#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
+  (abort (), __prev = __cmp = 0)
+#else
+#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
+     __asm__ __volatile__ ("\n"						      \
+     ".set	push\n\t"						      \
+     MIPS_PUSH_MIPS2							      \
+     rel	"\n"							      \
+     "1:\t"								      \
+     "lld	%0,%4\n\t"						      \
+     "move	%1,$0\n\t"						      \
+     "bne	%0,%2,2f\n\t"						      \
+     "move	%1,%3\n\t"						      \
+     "scd	%1,%4\n\t"						      \
+     "beqz	%1,1b\n"						      \
+     acq	"\n\t"							      \
+     ".set	pop\n"							      \
+     "2:\n\t"								      \
+	      : "=&r" (__prev), "=&r" (__cmp)				      \
+	      : "r" (oldval), "r" (newval), "m" (*mem)			      \
+	      : "memory")
+#endif
+
+/* For all "bool" routines, we return FALSE if exchange succesful.  */
+
+#define __arch_compare_and_exchange_bool_8_int(mem, new, old, rel, acq)	\
+({ typeof (*mem) __prev; int __cmp;					\
+   __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);	\
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_16_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					\
+   __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);	\
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_32_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					\
+   __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);	\
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_64_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					\
+   __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);	\
+   !__cmp; })
+
+/* For all "val" routines, return the old value whether exchange
+   successful or not.  */
+
+#define __arch_compare_and_exchange_val_8_int(mem, new, old, rel, acq)	\
+({ typeof (*mem) __prev; int __cmp;					\
+   __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);	\
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_16_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					\
+   __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);	\
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_32_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					\
+   __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);	\
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_64_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					\
+   __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);	\
+   (typeof (*mem))__prev; })
+
+/* Compare and exchange with "acquire" semantics, ie barrier after.  */
+
+#define atomic_compare_and_exchange_bool_acq(mem, new, old)	\
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool, int,	\
+		        mem, new, old, "", MIPS_SYNC_STR)
+
+#define atomic_compare_and_exchange_val_acq(mem, new, old)	\
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,	\
+		       mem, new, old, "", MIPS_SYNC_STR)
+
+/* Compare and exchange with "release" semantics, ie barrier before.  */
+
+#define atomic_compare_and_exchange_bool_rel(mem, new, old)	\
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool, int,	\
+		        mem, new, old, MIPS_SYNC_STR, "")
+
+#define atomic_compare_and_exchange_val_rel(mem, new, old)	\
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,	\
+		       mem, new, old, MIPS_SYNC_STR, "")
+
+
+
+/* Atomic exchange (without compare).  */
+
+#define __arch_exchange_xxx_8_int(mem, newval, rel, acq) \
+  (abort (), 0)
+
+#define __arch_exchange_xxx_16_int(mem, newval, rel, acq) \
+  (abort (), 0)
+
+#define __arch_exchange_xxx_32_int(mem, newval, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					      \
+     __asm__ __volatile__ ("\n"						      \
+     ".set	push\n\t"						      \
+     MIPS_PUSH_MIPS2							      \
+     rel	"\n"							      \
+     "1:\t"								      \
+     "ll	%0,%3\n\t"						      \
+     "move	%1,%2\n\t"						      \
+     "sc	%1,%3\n\t"						      \
+     "beqz	%1,1b\n"						      \
+     acq	"\n\t"							      \
+     ".set	pop\n"							      \
+     "2:\n\t"								      \
+	      : "=&r" (__prev), "=&r" (__cmp)				      \
+	      : "r" (newval), "m" (*mem)				      \
+	      : "memory");						      \
+  __prev; })
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32.  */
+#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
+  (abort (), 0)
+#else
+#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					      \
+     __asm__ __volatile__ ("\n"						      \
+     ".set	push\n\t"						      \
+     MIPS_PUSH_MIPS2							      \
+     rel	"\n"							      \
+     "1:\n"								      \
+     "lld	%0,%3\n\t"						      \
+     "move	%1,%2\n\t"						      \
+     "scd	%1,%3\n\t"						      \
+     "beqz	%1,1b\n"						      \
+     acq	"\n\t"							      \
+     ".set	pop\n"							      \
+     "2:\n\t"								      \
+	      : "=&r" (__prev), "=&r" (__cmp)				      \
+	      : "r" (newval), "m" (*mem)				      \
+	      : "memory");						      \
+  __prev; })
+#endif
+
+#define atomic_exchange_acq(mem, value) \
+  __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, "", MIPS_SYNC_STR)
+
+#define atomic_exchange_rel(mem, value) \
+  __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, MIPS_SYNC_STR, "")
+
+
+/* Atomically add value and return the previous (unincremented) value.  */
+
+#define __arch_exchange_and_add_8_int(mem, newval, rel, acq) \
+  (abort (), (typeof(*mem)) 0)
+
+#define __arch_exchange_and_add_16_int(mem, newval, rel, acq) \
+  (abort (), (typeof(*mem)) 0)
+
+#define __arch_exchange_and_add_32_int(mem, value, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					      \
+     __asm__ __volatile__ ("\n"						      \
+     ".set	push\n\t"						      \
+     MIPS_PUSH_MIPS2							      \
+     rel	"\n"							      \
+     "1:\t"								      \
+     "ll	%0,%3\n\t"						      \
+     "addu	%1,%0,%2\n\t"						      \
+     "sc	%1,%3\n\t"						      \
+     "beqz	%1,1b\n"						      \
+     acq	"\n\t"							      \
+     ".set	pop\n"							      \
+     "2:\n\t"								      \
+	      : "=&r" (__prev), "=&r" (__cmp)				      \
+	      : "r" (value), "m" (*mem)					      \
+	      : "memory");						      \
+  __prev; })
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32.  */
+#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
+  (abort (), (typeof(*mem)) 0)
+#else
+#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;					      \
+     __asm__ __volatile__ (						      \
+     ".set	push\n\t"						      \
+     MIPS_PUSH_MIPS2							      \
+     rel	"\n"							      \
+     "1:\t"								      \
+     "lld	%0,%3\n\t"						      \
+     "daddu	%1,%0,%2\n\t"						      \
+     "scd	%1,%3\n\t"						      \
+     "beqz	%1,1b\n"						      \
+     acq	"\n\t"							      \
+     ".set	pop\n"							      \
+     "2:\n\t"								      \
+	      : "=&r" (__prev), "=&r" (__cmp)				      \
+	      : "r" (value), "m" (*mem)					      \
+	      : "memory");						      \
+  __prev; })
+#endif
+
+/* ??? Barrier semantics for atomic_exchange_and_add appear to be 
+   undefined.  Use full barrier for now, as that's safe.  */
+#define atomic_exchange_and_add(mem, value) \
+  __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,	      \
+		       MIPS_SYNC_STR, MIPS_SYNC_STR)
+
+/* TODO: More atomic operations could be implemented efficiently; only the
+   basic requirements are done.  */
+
+#define atomic_full_barrier() \
+  __asm__ __volatile__ (".set push\n\t"					      \
+			MIPS_PUSH_MIPS2					      \
+			MIPS_SYNC_STR "\n\t"				      \
+			".set pop" : : : "memory")
+
+#endif /* bits/atomic.h */
diff --git a/sysdeps/mips/dl-tls.h b/sysdeps/mips/dl-tls.h
new file mode 100644
index 0000000000..6d3ed6f5a4
--- /dev/null
+++ b/sysdeps/mips/dl-tls.h
@@ -0,0 +1,46 @@
+/* Thread-local storage handling in the ELF dynamic linker.  MIPS version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, 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;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET		0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET		0x8000
+
+/* Compute the value for a GOTTPREL reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym) \
+  ((sym_map)->l_tls_offset + (sym)->st_value - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc.  */
+#define TLS_DTPREL_VALUE(sym) \
+  ((sym)->st_value - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+# define GET_ADDR_OFFSET	(ti->ti_offset + TLS_DTV_OFFSET)
+# define __TLS_GET_ADDR(__ti)	(__tls_get_addr (__ti) - TLS_DTV_OFFSET)
diff --git a/sysdeps/mips/dl-trampoline.c b/sysdeps/mips/dl-trampoline.c
index c5ea59cdb2..459adf9a8e 100644
--- a/sysdeps/mips/dl-trampoline.c
+++ b/sysdeps/mips/dl-trampoline.c
@@ -153,7 +153,7 @@ __dl_runtime_resolve (ElfW(Word) sym_index,
 
 	    if (version->hash != 0)
 	      {
-		sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l, 
+		sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l,
 					       &sym, l->l_scope, version,
 					       ELF_RTYPE_CLASS_PLT, 0, 0);
 		break;
diff --git a/sysdeps/mips/elf/configure b/sysdeps/mips/elf/configure
new file mode 100644
index 0000000000..3d90a1e420
--- /dev/null
+++ b/sysdeps/mips/elf/configure
@@ -0,0 +1,46 @@
+# This file is generated from configure.in by Autoconf.  DO NOT EDIT!
+ # Local configure fragment for sysdeps/mips/elf.
+
+if test "$usetls" != no; then
+# Check for support of thread-local storage handling in assembler and
+# linker.
+echo "$as_me:$LINENO: checking for MIPS TLS support" >&5
+echo $ECHO_N "checking for MIPS TLS support... $ECHO_C" >&6
+if test "${libc_cv_mips_tls+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat > conftest.s <<\EOF
+	.section ".tdata", "awT", %progbits
+	.globl foo
+foo:	.long	1
+	.section ".tbss", "awT", %nobits
+	.globl bar
+bar:	.skip	4
+	.text
+
+	lw	$25, %call16(__tls_get_addr)($28)
+	jalr	$25
+	addiu	$4, $28, %tlsgd(x)
+EOF
+if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  libc_cv_mips_tls=yes
+else
+  libc_cv_mips_tls=no
+fi
+rm -f conftest*
+fi
+echo "$as_me:$LINENO: result: $libc_cv_mips_tls" >&5
+echo "${ECHO_T}$libc_cv_mips_tls" >&6
+if test $libc_cv_mips_tls = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_TLS_SUPPORT 1
+_ACEOF
+
+fi
+fi
+
diff --git a/sysdeps/mips/elf/configure.in b/sysdeps/mips/elf/configure.in
new file mode 100644
index 0000000000..ecb9108c12
--- /dev/null
+++ b/sysdeps/mips/elf/configure.in
@@ -0,0 +1,35 @@
+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
+# Local configure fragment for sysdeps/mips/elf.
+
+if test "$usetls" != no; then
+# Check for support of thread-local storage handling in assembler and
+# linker.
+AC_CACHE_CHECK(for MIPS TLS support, libc_cv_mips_tls, [dnl
+cat > conftest.s <<\EOF
+	.section ".tdata", "awT", %progbits
+	.globl foo
+foo:	.long	1
+	.section ".tbss", "awT", %nobits
+	.globl bar
+bar:	.skip	4
+	.text
+
+	lw	$25, %call16(__tls_get_addr)($28)
+	jalr	$25
+	addiu	$4, $28, %tlsgd(x) 
+EOF
+dnl
+if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS conftest.s 1>&AS_MESSAGE_LOG_FD); then
+  libc_cv_mips_tls=yes
+else
+  libc_cv_mips_tls=no
+fi
+rm -f conftest*])
+if test $libc_cv_mips_tls = yes; then
+  AC_DEFINE(HAVE_TLS_SUPPORT)
+fi
+fi
+
+dnl No MIPS GCC supports accessing static and hidden symbols in an
+dnl position independent way.
+dnl AC_DEFINE(PI_STATIC_AND_HIDDEN)
diff --git a/sysdeps/mips/libc-tls.c b/sysdeps/mips/libc-tls.c
new file mode 100644
index 0000000000..157ba3389a
--- /dev/null
+++ b/sysdeps/mips/libc-tls.c
@@ -0,0 +1,37 @@
+/* Thread-local storage handling in the ELF dynamic linker.  MIPS version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdeps/generic/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On MIPS, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
+
+#endif
diff --git a/sysdeps/mips/sys/asm.h b/sysdeps/mips/sys/asm.h
index b04c36ba5e..b590802fd9 100644
--- a/sysdeps/mips/sys/asm.h
+++ b/sysdeps/mips/sys/asm.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 1998, 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ralf Baechle <ralf@gnu.org>.
 
@@ -470,4 +471,20 @@ symbol		=	value
 # define MTC0	dmtc0
 #endif
 
+/* The MIPS archtectures do not have a uniform memory model.  Particular
+   platforms may provide additional guarantees - for instance, the R4000
+   LL and SC instructions implicitly perform a SYNC, and the 4K promises
+   strong ordering.
+
+   However, in the absence of those guarantees, we must assume weak ordering
+   and SYNC explicitly where necessary.
+
+   Some obsolete MIPS processors may not support the SYNC instruction.  This
+   applies to "true" MIPS I processors; most of the processors which compile
+   using MIPS I implement parts of MIPS II.  */
+
+#ifndef MIPS_SYNC
+# define MIPS_SYNC	sync
+#endif
+
 #endif /* sys/asm.h */
diff --git a/sysdeps/mips/tls-macros.h b/sysdeps/mips/tls-macros.h
new file mode 100644
index 0000000000..2d0516b3e4
--- /dev/null
+++ b/sysdeps/mips/tls-macros.h
@@ -0,0 +1,88 @@
+/* Macros to support TLS testing in times of missing compiler support.  */
+
+#if _MIPS_SIM != _ABI64
+
+/* These versions are for o32 and n32.  */
+
+# define TLS_GD(x)					\
+  ({ void *__result;					\
+     extern void *__tls_get_addr (void *);		\
+     asm ("addiu %0, $28, %%tlsgd(" #x ")"		\
+	  : "=r" (__result));				\
+     (int *)__tls_get_addr (__result); })
+#else
+# define TLS_GD(x)					\
+  ({ void *__result;					\
+     extern void *__tls_get_addr (void *);		\
+     asm ("daddiu %0, $28, %%tlsgd(" #x ")"		\
+	  : "=r" (__result));				\
+     (int *)__tls_get_addr (__result); })
+#endif
+
+#if _MIPS_SIM != _ABI64
+# define TLS_LD(x)					\
+  ({ void *__result;					\
+     extern void *__tls_get_addr (void *);		\
+     asm ("addiu %0, $28, %%tlsldm(" #x ")"		\
+	  : "=r" (__result));				\
+     __result = __tls_get_addr (__result);		\
+     asm ("lui $3,%%dtprel_hi(" #x ")\n\t"		\
+	  "addiu $3,$3,%%dtprel_lo(" #x ")\n\t"		\
+	  "addu %0,%0,$3"				\
+	  : "+r" (__result) : : "$3");			\
+     __result; })
+# define TLS_IE(x)					\
+  ({ void *__result;					\
+     asm (".set push\n\t.set mips32r2\n\t"		\
+	  "rdhwr\t%0,$29\n\t.set pop"			\
+	  : "=v" (__result));				\
+     asm ("lw $3,%%gottprel(" #x ")($28)\n\t"		\
+	  "addu %0,%0,$3"				\
+	  : "+r" (__result) : : "$3");			\
+     __result; })
+# define TLS_LE(x)					\
+  ({ void *__result;					\
+     asm (".set push\n\t.set mips32r2\n\t"		\
+	  "rdhwr\t%0,$29\n\t.set pop"			\
+	  : "=v" (__result));				\
+     asm ("lui $3,%%tprel_hi(" #x ")\n\t"		\
+	  "addiu $3,$3,%%tprel_lo(" #x ")\n\t"		\
+	  "addu %0,%0,$3"				\
+	  : "+r" (__result) : : "$3");			\
+     __result; })
+
+#else
+
+/* These versions are for n64.  */
+
+# define TLS_LD(x)					\
+  ({ void *__result;					\
+     extern void *__tls_get_addr (void *);		\
+     asm ("daddiu %0, $28, %%tlsldm(" #x ")"		\
+	  : "=r" (__result));				\
+     __result = __tls_get_addr (__result);		\
+     asm ("lui $3,%%dtprel_hi(" #x ")\n\t"		\
+	  "daddiu $3,$3,%%dtprel_lo(" #x ")\n\t"	\
+	  "daddu %0,%0,$3"				\
+	  : "+r" (__result) : : "$3");			\
+     __result; })
+# define TLS_IE(x)					\
+  ({ void *__result;					\
+     asm (".set push\n\t.set mips32r2\n\t"		\
+	  "rdhwr\t%0,$29\n\t.set pop"			\
+	  : "=v" (__result));				\
+     asm ("ld $3,%%gottprel(" #x ")($28)\n\t"		\
+	  "daddu %0,%0,$3"				\
+	  : "+r" (__result) : : "$3");			\
+     __result; })
+# define TLS_LE(x)					\
+  ({ void *__result;					\
+     asm (".set push\n\t.set mips32r2\n\t"		\
+	  "rdhwr\t%0,$29\n\t.set pop"			\
+	  : "=v" (__result));				\
+     asm ("lui $3,%%tprel_hi(" #x ")\n\t"		\
+	  "daddiu $3,$3,%%tprel_lo(" #x ")\n\t"		\
+	  "daddu %0,%0,$3"				\
+	  : "+r" (__result) : : "$3");			\
+     __result; })
+#endif