summaryrefslogtreecommitdiff
path: root/sysdeps/mips
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2005-04-01 15:13:31 +0000
committerJakub Jelinek <jakub@redhat.com>2005-04-01 15:13:31 +0000
commite8eaba2b25948c0e60f70c33c5c52aad70bbf5fc (patch)
tree020566c0ffd2d27131ee7bac45eea5560a4732bd /sysdeps/mips
parente3166b6660ce5f0640242a4806a380bb651a2291 (diff)
Updated to fedora-glibc-20050401T1444
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/bits/link.h118
-rw-r--r--sysdeps/mips/bits/setjmp.h9
-rw-r--r--sysdeps/mips/dl-machine.h364
-rw-r--r--sysdeps/mips/dl-tls.h46
-rw-r--r--sysdeps/mips/dl-trampoline.c272
-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
12 files changed, 1069 insertions, 381 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/bits/link.h b/sysdeps/mips/bits/link.h
new file mode 100644
index 0000000000..3d77a4c4a5
--- /dev/null
+++ b/sysdeps/mips/bits/link.h
@@ -0,0 +1,118 @@
+/* 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 _LINK_H
+# error "Never include <bits/link.h> directly; use <link.h> instead."
+#endif
+
+#include <sgidefs.h>
+
+#if _MIPS_SIM == _ABIO32
+
+/* Registers for entry into PLT on MIPS. */
+typedef struct La_mips_32_regs
+{
+ uint32_t lr_reg[4]; /* $a0 through $a3 */
+ double lr_fpreg[2]; /* $f12 and $f14 */
+ uint32_t lr_ra;
+ uint32_t lr_sp;
+} La_mips_32_regs;
+
+/* Return values for calls from PLT on MIPS. */
+typedef struct La_mips_32_retval
+{
+ uint32_t lrv_v0;
+ uint32_t lrv_v1;
+ double lrv_f0;
+ double lrv_f2;
+} La_mips_32_retval;
+
+#else
+
+typedef struct La_mips_64_regs
+{
+ uint64_t lr_reg[8]; /* $a0 through $a7 */
+ double lr_fpreg[8]; /* $f12 throgh $f19 */
+ uint64_t lr_ra;
+ uint64_t lr_sp;
+} La_mips_64_regs;
+
+/* Return values for calls from PLT on MIPS. */
+typedef struct La_mips_64_retval
+{
+ uint64_t lrv_v0;
+ uint64_t lrv_v1;
+ double lrv_f0;
+ double lrv_f2;
+} La_mips_64_retval;
+
+#endif
+
+__BEGIN_DECLS
+
+#if _MIPS_SIM == _ABIO32
+
+extern Elf32_Addr la_mips_o32_gnu_pltenter (Elf32_Sym *__sym, unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ La_mips_32_regs *__regs,
+ unsigned int *__flags,
+ const char *__symname,
+ long int *__framesizep);
+extern unsigned int la_mips_o32_gnu_pltexit (Elf32_Sym *__sym, unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ const La_mips_32_regs *__inregs,
+ La_mips_32_retval *__outregs,
+ const char *symname);
+
+#elif _MIPS_SIM == _ABIN32
+
+extern Elf32_Addr la_mips_n32_gnu_pltenter (Elf32_Sym *__sym, unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ La_mips_64_regs *__regs,
+ unsigned int *__flags,
+ const char *__symname,
+ long int *__framesizep);
+extern unsigned int la_mips_n32_gnu_pltexit (Elf32_Sym *__sym, unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ const La_mips_64_regs *__inregs,
+ La_mips_64_retval *__outregs,
+ const char *symname);
+
+#else
+
+extern Elf64_Addr la_mips_n64_gnu_pltenter (Elf64_Sym *__sym, unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ La_mips_64_regs *__regs,
+ unsigned int *__flags,
+ const char *__symname,
+ long int *__framesizep);
+extern unsigned int la_mips_n64_gnu_pltexit (Elf64_Sym *__sym, unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ const La_mips_64_regs *__inregs,
+ La_mips_64_retval *__outregs,
+ const char *symname);
+
+#endif
+
+__END_DECLS
diff --git a/sysdeps/mips/bits/setjmp.h b/sysdeps/mips/bits/setjmp.h
index ec0aaa020d..2b42b22ba4 100644
--- a/sysdeps/mips/bits/setjmp.h
+++ b/sysdeps/mips/bits/setjmp.h
@@ -1,5 +1,5 @@
/* Define the machine-dependent type `jmp_buf'. MIPS version.
- Copyright (C) 1992, 1993, 1995, 1997, 2000, 2002, 2003, 2004
+ Copyright (C) 1992, 1993, 1995, 1997, 2000, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,7 +18,10 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#ifndef _SETJMP_H
+#ifndef _MIPS_BITS_SETJMP_H
+#define _MIPS_BITS_SETJMP_H 1
+
+#if !defined(_SETJMP_H) && !defined(_PTHREAD_H)
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
#endif
@@ -79,3 +82,5 @@ typedef struct
containing a local variable at ADDRESS. */
#define _JMPBUF_UNWINDS(jmpbuf, address) \
((void *) (address) < (jmpbuf)[0].__sp)
+
+#endif /* _MIPS_BITS_SETJMP_H */
diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h
index 0d87b65691..aa2cef83bc 100644
--- a/sysdeps/mips/dl-machine.h
+++ b/sysdeps/mips/dl-machine.h
@@ -1,5 +1,6 @@
/* Machine-dependent ELF dynamic relocation inline functions. MIPS version.
- Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1996-2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>.
@@ -34,6 +35,7 @@
#include <sgidefs.h>
#include <sys/asm.h>
+#include <dl-tls.h>
/* The offset of gp from GOT might be system-dependent. It's set by
ld. The same value is also */
@@ -188,248 +190,6 @@ do { \
} while(0)
-/* Get link map for callers object containing STUB_PC. */
-static inline struct link_map *
-elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
-{
- extern int _dl_mips_gnu_objects;
-
- /* got[1] is reserved to keep its link map address for the shared
- object generated by the gnu linker. If all are such objects, we
- can find the link map from current GPREG simply. If not so, get
- the link map for caller's object containing STUB_PC. */
-
- if (_dl_mips_gnu_objects)
- {
- ElfW(Addr) *got = elf_mips_got_from_gpreg (gpreg);
- ElfW(Word) g1;
-
- g1 = ((ElfW(Word) *) got)[1];
-
- if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0)
- {
- struct link_map *l =
- (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK);
- ElfW(Addr) base, limit;
- const ElfW(Phdr) *p = l->l_phdr;
- ElfW(Half) this, nent = l->l_phnum;
-
- /* For the common case of a stub being called from the containing
- object, STUB_PC will point to somewhere within the object that
- is described by the link map fetched via got[1]. Otherwise we
- have to scan all maps. */
- for (this = 0; this < nent; this++)
- {
- if (p[this].p_type == PT_LOAD)
- {
- base = p[this].p_vaddr + l->l_addr;
- limit = base + p[this].p_memsz;
- if (stub_pc >= base && stub_pc < limit)
- return l;
- }
- }
- }
- }
-
- struct link_map *l;
- Lmid_t nsid;
-
- for (nsid = 0; nsid < DL_NNS; ++nsid)
- for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
- {
- ElfW(Addr) base, limit;
- const ElfW(Phdr) *p = l->l_phdr;
- ElfW(Half) this, nent = l->l_phnum;
-
- for (this = 0; this < nent; ++this)
- {
- if (p[this].p_type == PT_LOAD)
- {
- base = p[this].p_vaddr + l->l_addr;
- limit = base + p[this].p_memsz;
- if (stub_pc >= base && stub_pc < limit)
- return l;
- }
- }
- }
-
- _dl_signal_error (0, NULL, NULL, "cannot find runtime link map");
- return NULL;
-}
-
-#if _MIPS_SIM == _ABIO32
-#define ELF_DL_FRAME_SIZE 40
-
-#define ELF_DL_SAVE_ARG_REGS "\
- sw $15, 36($29)\n \
- sw $4, 16($29)\n \
- sw $5, 20($29)\n \
- sw $6, 24($29)\n \
- sw $7, 28($29)\n \
-"
-
-#define ELF_DL_RESTORE_ARG_REGS "\
- lw $31, 36($29)\n \
- lw $4, 16($29)\n \
- lw $5, 20($29)\n \
- lw $6, 24($29)\n \
- lw $7, 28($29)\n \
-"
-
-#define IFABIO32(X) X
-
-#else /* _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64 */
-
-#define ELF_DL_FRAME_SIZE 80
-
-#define ELF_DL_SAVE_ARG_REGS "\
- sd $15, 72($29)\n \
- sd $4, 8($29)\n \
- sd $5, 16($29)\n \
- sd $6, 24($29)\n \
- sd $7, 32($29)\n \
- sd $8, 40($29)\n \
- sd $9, 48($29)\n \
- sd $10, 56($29)\n \
- sd $11, 64($29)\n \
-"
-
-#define ELF_DL_RESTORE_ARG_REGS "\
- ld $31, 72($29)\n \
- ld $4, 8($29)\n \
- ld $5, 16($29)\n \
- ld $6, 24($29)\n \
- ld $7, 32($29)\n \
- ld $8, 40($29)\n \
- ld $9, 48($29)\n \
- ld $10, 56($29)\n \
- ld $11, 64($29)\n \
-"
-
-#define IFABIO32(X)
-
-#endif
-
-/* Define mips specific runtime resolver. The function __dl_runtime_resolve
- is called from assembler function _dl_runtime_resolve which converts
- special argument registers t7 ($15) and t8 ($24):
- t7 address to return to the caller of the function
- t8 index for this function symbol in .dynsym
- to usual c arguments.
-
- Other architectures call fixup from dl-runtime.c in
- _dl_runtime_resolve. MIPS instead calls __dl_runtime_resolve. We
- have to use our own version because of the way the got section is
- treated on MIPS (we've also got ELF_MACHINE_PLT defined). */
-
-#define ELF_MACHINE_RUNTIME_TRAMPOLINE \
-/* The flag _dl_mips_gnu_objects is set if all dynamic objects are \
- generated by the gnu linker. */ \
-int _dl_mips_gnu_objects = 1; \
- \
-/* This is called from assembly stubs below which the compiler can't see. */ \
-static ElfW(Addr) \
-__dl_runtime_resolve (ElfW(Word), ElfW(Word), ElfW(Addr), ElfW(Addr)) \
- __attribute_used__; \
- \
-static ElfW(Addr) \
-__dl_runtime_resolve (ElfW(Word) sym_index, \
- ElfW(Word) return_address, \
- ElfW(Addr) old_gpreg, \
- ElfW(Addr) stub_pc) \
-{ \
- struct link_map *l = elf_machine_runtime_link_map (old_gpreg, stub_pc); \
- const ElfW(Sym) *const symtab \
- = (const ElfW(Sym) *) D_PTR (l, l_info[DT_SYMTAB]); \
- const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); \
- ElfW(Addr) *got \
- = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]); \
- const ElfW(Word) local_gotno \
- = (const ElfW(Word)) l->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val; \
- const ElfW(Word) gotsym \
- = (const ElfW(Word)) l->l_info[DT_MIPS (GOTSYM)]->d_un.d_val; \
- const ElfW(Sym) *sym = &symtab[sym_index]; \
- ElfW(Addr) value; \
- \
- /* FIXME: The symbol versioning stuff is not tested yet. */ \
- if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) \
- { \
- switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) \
- { \
- default: \
- { \
- const ElfW(Half) *vernum = \
- (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); \
- ElfW(Half) ndx = vernum[sym_index] & 0x7fff; \
- const struct r_found_version *version = &l->l_versions[ndx]; \
- \
- if (version->hash != 0) \
- { \
- value = _dl_lookup_symbol_x (strtab + sym->st_name, l, \
- &sym, l->l_scope, version, \
- ELF_RTYPE_CLASS_PLT, 0, 0); \
- break; \
- } \
- /* Fall through. */ \
- } \
- case 0: \
- value = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym, \
- l->l_scope, 0, ELF_RTYPE_CLASS_PLT, \
- DL_LOOKUP_ADD_DEPENDENCY, 0); \
- } \
- \
- /* Currently value contains the base load address of the object \
- that defines sym. Now add in the symbol offset. */ \
- value = (sym ? value + sym->st_value : 0); \
- } \
- else \
- /* We already found the symbol. The module (and therefore its load \
- address) is also known. */ \
- value = l->l_addr + sym->st_value; \
- \
- /* Apply the relocation with that value. */ \
- *(got + local_gotno + sym_index - gotsym) = value; \
- \
- return value; \
-} \
- \
-asm ("\n \
- .text\n \
- .align 2\n \
- .globl _dl_runtime_resolve\n \
- .type _dl_runtime_resolve,@function\n \
- .ent _dl_runtime_resolve\n \
-_dl_runtime_resolve:\n \
- .frame $29, " STRINGXP(ELF_DL_FRAME_SIZE) ", $31\n \
- .set noreorder\n \
- # Save GP.\n \
- move $3, $28\n \
- # Save arguments and sp value in stack.\n \
- " STRINGXP(PTR_SUBIU) " $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n \
- # Modify t9 ($25) so as to point .cpload instruction.\n \
- " IFABIO32(STRINGXP(PTR_ADDIU) " $25, 12\n") " \
- # Compute GP.\n \
- " STRINGXP(SETUP_GP) "\n \
- " STRINGXV(SETUP_GP64 (0, _dl_runtime_resolve)) "\n \
- .set reorder\n \
- # Save slot call pc.\n \
- move $2, $31\n \
- " IFABIO32(STRINGXP(CPRESTORE(32))) "\n \
- " ELF_DL_SAVE_ARG_REGS " \
- move $4, $24\n \
- move $5, $15\n \
- move $6, $3\n \
- move $7, $2\n \
- jal __dl_runtime_resolve\n \
- " ELF_DL_RESTORE_ARG_REGS " \
- " STRINGXP(RESTORE_GP64) "\n \
- " STRINGXP(PTR_ADDIU) " $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n \
- move $25, $2\n \
- jr $25\n \
- .end _dl_runtime_resolve\n \
- .previous\n \
-");
-
/* Mask identifying addresses reserved for the user program,
where the dynamic linker should not map anything. */
#define ELF_MACHINE_USER_ADDRESS_MASK 0x80000000UL
@@ -451,8 +211,8 @@ _dl_runtime_resolve:\n \
and not just plain _start. */
#define RTLD_START asm (\
- ".text\n"\
- _RTLD_PROLOGUE(ENTRY_POINT) "\
+ ".text\n\
+ " _RTLD_PROLOGUE(ENTRY_POINT) "\
" STRINGXV(SETUP_GPX($25)) "\n\
" STRINGXV(SETUP_GPX64($18,$25)) "\n\
# i386 ABI book says that the first entry of GOT holds\n\
@@ -475,10 +235,10 @@ _dl_runtime_resolve:\n \
" STRINGXP(PTR_ADDIU) " $29, 16\n\
# Get the value of label '_dl_start_user' in t9 ($25).\n\
" STRINGXP(PTR_LA) " $25, _dl_start_user\n\
- .globl _dl_start_user\n\
- .type _dl_start_user,@function\n\
- .aent _dl_start_user\n\
-_dl_start_user:\n\
+ " _RTLD_EPILOGUE(ENTRY_POINT) "\
+ \n\
+ \n\
+ " _RTLD_PROLOGUE(_dl_start_user) "\
" STRINGXP(SETUP_GP) "\n\
" STRINGXV(SETUP_GP64($18,_dl_start_user)) "\n\
move $16, $28\n\
@@ -504,34 +264,48 @@ _dl_start_user:\n\
sll $7, $5, " STRINGXP (PTRLOG) "\n\
" STRINGXP(PTR_ADDU) " $7, $7, $6\n\
" STRINGXP(PTR_ADDU) " $7, $7, " STRINGXP (PTRSIZE) " \n\
- " STRINGXP(PTR_SUBIU) " $29, 32\n\
+ # Make sure the stack pointer is aligned for _dl_init_internal.\n\
+ and $2, $29, -2 * " STRINGXP(SZREG) "\n\
+ " STRINGXP(PTR_S) " $29, -4($2)\n\
+ " STRINGXP(PTR_SUBIU) " $29, $2, 32\n\
" STRINGXP(SAVE_GP(16)) "\n\
# Call the function to run the initializers.\n\
jal _dl_init_internal\n\
- " STRINGXP(PTR_ADDIU) " $29, 32\n\
+ # Restore the stack pointer for _start.\n\
+ " STRINGXP(PTR_L) " $29, 28($29)\n\
# Pass our finalizer function to the user in $2 as per ELF ABI.\n\
" STRINGXP(PTR_LA) " $2, _dl_fini\n\
# Jump to the user entry point.\n\
move $25, $17\n\
jr $25\n\t"\
- _RTLD_EPILOGUE(ENTRY_POINT)\
+ _RTLD_EPILOGUE(_dl_start_user)\
".previous"\
);
/* The MIPS never uses Elfxx_Rela relocations. */
#define ELF_MACHINE_NO_RELA 1
+/* Names of the architecture-specific auditing callback functions. */
+# if _MIPS_SIM == _ABIO32
+# define ARCH_LA_PLTENTER mips_o32_gnu_pltenter
+# define ARCH_LA_PLTEXIT mips_o32_gnu_pltexit
+# elif _MIPS_SIM == _ABIN32
+# define ARCH_LA_PLTENTER mips_n32_gnu_pltenter
+# define ARCH_LA_PLTEXIT mips_n32_gnu_pltexit
+# else
+# define ARCH_LA_PLTENTER mips_n64_gnu_pltenter
+# define ARCH_LA_PLTEXIT mips_n64_gnu_pltexit
+# endif
+
#endif /* !dl_machine_h */
-#ifdef RESOLVE
+#ifdef RESOLVE_MAP
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
MAP is the object containing the reloc. */
-static inline void
-#ifdef RTLD_BOOTSTRAP
- __attribute__ ((always_inline))
-#endif
+auto inline void
+__attribute__ ((always_inline))
elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
const ElfW(Sym) *sym, const struct r_found_version *version,
void *const reloc_addr)
@@ -550,6 +324,47 @@ elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
switch (r_type)
{
+#if defined (USE_TLS) && !defined (RTLD_BOOTSTRAP)
+# if _MIPS_SIM == _ABI64
+ case R_MIPS_TLS_DTPMOD64:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
+# else
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+# endif
+ {
+ struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+ Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
+
+ if (sym)
+ value += sym->st_value;
+
+ switch (r_type)
+ {
+ case R_MIPS_TLS_DTPMOD64:
+ case R_MIPS_TLS_DTPMOD32:
+ if (sym_map)
+ *(ElfW(Word) *)reloc_addr = sym_map->l_tls_modid;
+ break;
+
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_DTPREL32:
+ *(ElfW(Word) *)reloc_addr += TLS_DTPREL_VALUE (sym);
+ break;
+
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_TPREL64:
+ CHECK_STATIC_TLS (map, sym_map);
+ *(ElfW(Word) *)reloc_addr += TLS_TPREL_VALUE (sym_map, sym);
+ break;
+ }
+
+ break;
+ }
+#endif
+
#if _MIPS_SIM == _ABI64
case (R_MIPS_64 << 8) | R_MIPS_REL32:
#else
@@ -635,23 +450,41 @@ elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
}
}
-static inline void
+auto inline void
+__attribute__((always_inline))
elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
void *const reloc_addr)
{
/* XXX Nothing to do. There is no relative relocation, right? */
}
-static inline void
+auto inline void
+__attribute__((always_inline))
elf_machine_lazy_rel (struct link_map *map,
ElfW(Addr) l_addr, const ElfW(Rel) *reloc)
{
/* Do nothing. */
}
+auto inline void
+__attribute__ ((always_inline))
+elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
+ const ElfW(Sym) *sym, const struct r_found_version *version,
+ void *const reloc_addr)
+{
+}
+
+auto inline void
+__attribute__((always_inline))
+elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+ void *const reloc_addr)
+{
+}
+
#ifndef RTLD_BOOTSTRAP
/* Relocate GOT. */
-static inline void
+auto inline void
+__attribute__((always_inline))
elf_machine_got_rel (struct link_map *map, int lazy)
{
ElfW(Addr) *got;
@@ -664,9 +497,9 @@ elf_machine_got_rel (struct link_map *map, int lazy)
const ElfW(Sym) *ref = sym; \
const struct r_found_version *version \
= vernum ? &map->l_versions[vernum[sym_index] & 0x7fff] : NULL; \
- ElfW(Addr) value; \
- value = RESOLVE (&ref, version, R_MIPS_REL32); \
- (ref)? value + ref->st_value: 0; \
+ struct link_map *sym_map; \
+ sym_map = RESOLVE_MAP (&ref, version, R_MIPS_REL32); \
+ ref ? sym_map->l_addr + ref->st_value : 0; \
})
if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
@@ -738,7 +571,8 @@ elf_machine_got_rel (struct link_map *map, int lazy)
/* Set up the loaded object described by L so its stub function
will jump to the on-demand fixup code __dl_runtime_resolve. */
-static inline int
+auto inline int
+__attribute__((always_inline))
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
{
# ifndef RTLD_BOOTSTRAP
@@ -774,4 +608,4 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
return lazy;
}
-#endif /* RESOLVE */
+#endif /* RESOLVE_MAP */
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
new file mode 100644
index 0000000000..459adf9a8e
--- /dev/null
+++ b/sysdeps/mips/dl-trampoline.c
@@ -0,0 +1,272 @@
+/* PLT trampoline. MIPS version.
+ Copyright (C) 1996-2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>.
+
+ 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. */
+
+/* FIXME: Profiling of shared libraries is not implemented yet. */
+
+#include <sysdep.h>
+#include <link.h>
+#include <elf.h>
+#include <ldsodefs.h>
+#include <dl-machine.h>
+
+/* Get link map for callers object containing STUB_PC. */
+static inline struct link_map *
+elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
+{
+ extern int _dl_mips_gnu_objects;
+
+ /* got[1] is reserved to keep its link map address for the shared
+ object generated by the gnu linker. If all are such objects, we
+ can find the link map from current GPREG simply. If not so, get
+ the link map for caller's object containing STUB_PC. */
+
+ if (_dl_mips_gnu_objects)
+ {
+ ElfW(Addr) *got = elf_mips_got_from_gpreg (gpreg);
+ ElfW(Word) g1;
+
+ g1 = ((ElfW(Word) *) got)[1];
+
+ if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0)
+ {
+ struct link_map *l =
+ (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK);
+ ElfW(Addr) base, limit;
+ const ElfW(Phdr) *p = l->l_phdr;
+ ElfW(Half) this, nent = l->l_phnum;
+
+ /* For the common case of a stub being called from the containing
+ object, STUB_PC will point to somewhere within the object that
+ is described by the link map fetched via got[1]. Otherwise we
+ have to scan all maps. */
+ for (this = 0; this < nent; this++)
+ {
+ if (p[this].p_type == PT_LOAD)
+ {
+ base = p[this].p_vaddr + l->l_addr;
+ limit = base + p[this].p_memsz;
+ if (stub_pc >= base && stub_pc < limit)
+ return l;
+ }
+ }
+ }
+ }
+
+ struct link_map *l;
+ Lmid_t nsid;
+
+ for (nsid = 0; nsid < DL_NNS; ++nsid)
+ for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
+ {
+ ElfW(Addr) base, limit;
+ const ElfW(Phdr) *p = l->l_phdr;
+ ElfW(Half) this, nent = l->l_phnum;
+
+ for (this = 0; this < nent; ++this)
+ {
+ if (p[this].p_type == PT_LOAD)
+ {
+ base = p[this].p_vaddr + l->l_addr;
+ limit = base + p[this].p_memsz;
+ if (stub_pc >= base && stub_pc < limit)
+ return l;
+ }
+ }
+ }
+
+ _dl_signal_error (0, NULL, NULL, "cannot find runtime link map");
+ return NULL;
+}
+
+/* Define mips specific runtime resolver. The function __dl_runtime_resolve
+ is called from assembler function _dl_runtime_resolve which converts
+ special argument registers t7 ($15) and t8 ($24):
+ t7 address to return to the caller of the function
+ t8 index for this function symbol in .dynsym
+ to usual c arguments.
+
+ Other architectures call fixup from dl-runtime.c in
+ _dl_runtime_resolve. MIPS instead calls __dl_runtime_resolve. We
+ have to use our own version because of the way the got section is
+ treated on MIPS (we've also got ELF_MACHINE_PLT defined). */
+
+/* The flag _dl_mips_gnu_objects is set if all dynamic objects are
+ generated by the gnu linker. */
+int _dl_mips_gnu_objects = 1;
+
+#define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
+
+/* This is called from assembly stubs below which the compiler can't see. */
+static ElfW(Addr)
+__dl_runtime_resolve (ElfW(Word), ElfW(Word), ElfW(Addr), ElfW(Addr))
+ __attribute_used__;
+
+static ElfW(Addr)
+__dl_runtime_resolve (ElfW(Word) sym_index,
+ ElfW(Word) return_address,
+ ElfW(Addr) old_gpreg,
+ ElfW(Addr) stub_pc)
+{
+ struct link_map *l = elf_machine_runtime_link_map (old_gpreg, stub_pc);
+ const ElfW(Sym) *const symtab
+ = (const ElfW(Sym) *) D_PTR (l, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
+ ElfW(Addr) *got
+ = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
+ const ElfW(Word) local_gotno
+ = (const ElfW(Word)) l->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
+ const ElfW(Word) gotsym
+ = (const ElfW(Word)) l->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
+ const ElfW(Sym) *sym = &symtab[sym_index];
+ struct link_map *sym_map;
+ ElfW(Addr) value;
+
+ /* FIXME: The symbol versioning stuff is not tested yet. */
+ if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
+ {
+ switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ default:
+ {
+ const ElfW(Half) *vernum =
+ (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
+ ElfW(Half) ndx = vernum[sym_index] & 0x7fff;
+ const struct r_found_version *version = &l->l_versions[ndx];
+
+ if (version->hash != 0)
+ {
+ sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l,
+ &sym, l->l_scope, version,
+ ELF_RTYPE_CLASS_PLT, 0, 0);
+ break;
+ }
+ /* Fall through. */
+ }
+ case 0:
+ sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
+ l->l_scope, 0, ELF_RTYPE_CLASS_PLT,
+ DL_LOOKUP_ADD_DEPENDENCY, 0);
+ }
+
+ /* Currently value contains the base load address of the object
+ that defines sym. Now add in the symbol offset. */
+ value = (sym ? sym_map->l_addr + sym->st_value : 0);
+ }
+ else
+ /* We already found the symbol. The module (and therefore its load
+ address) is also known. */
+ value = l->l_addr + sym->st_value;
+
+ /* Apply the relocation with that value. */
+ *(got + local_gotno + sym_index - gotsym) = value;
+
+ return value;
+}
+
+#if _MIPS_SIM == _ABIO32
+#define ELF_DL_FRAME_SIZE 40
+
+#define ELF_DL_SAVE_ARG_REGS "\
+ sw $15, 36($29)\n \
+ sw $4, 16($29)\n \
+ sw $5, 20($29)\n \
+ sw $6, 24($29)\n \
+ sw $7, 28($29)\n \
+"
+
+#define ELF_DL_RESTORE_ARG_REGS "\
+ lw $31, 36($29)\n \
+ lw $4, 16($29)\n \
+ lw $5, 20($29)\n \
+ lw $6, 24($29)\n \
+ lw $7, 28($29)\n \
+"
+
+#define IFABIO32(X) X
+
+#else /* _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64 */
+
+#define ELF_DL_FRAME_SIZE 80
+
+#define ELF_DL_SAVE_ARG_REGS "\
+ sd $15, 72($29)\n \
+ sd $4, 8($29)\n \
+ sd $5, 16($29)\n \
+ sd $6, 24($29)\n \
+ sd $7, 32($29)\n \
+ sd $8, 40($29)\n \
+ sd $9, 48($29)\n \
+ sd $10, 56($29)\n \
+ sd $11, 64($29)\n \
+"
+
+#define ELF_DL_RESTORE_ARG_REGS "\
+ ld $31, 72($29)\n \
+ ld $4, 8($29)\n \
+ ld $5, 16($29)\n \
+ ld $6, 24($29)\n \
+ ld $7, 32($29)\n \
+ ld $8, 40($29)\n \
+ ld $9, 48($29)\n \
+ ld $10, 56($29)\n \
+ ld $11, 64($29)\n \
+"
+
+#define IFABIO32(X)
+
+#endif
+
+asm ("\n\
+ .text\n\
+ .align 2\n\
+ .globl _dl_runtime_resolve\n\
+ .type _dl_runtime_resolve,@function\n\
+ .ent _dl_runtime_resolve\n\
+_dl_runtime_resolve:\n\
+ .frame $29, " STRINGXP(ELF_DL_FRAME_SIZE) ", $31\n\
+ .set noreorder\n\
+ # Save GP.\n\
+ move $3, $28\n\
+ # Save arguments and sp value in stack.\n\
+ " STRINGXP(PTR_SUBIU) " $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\
+ # Modify t9 ($25) so as to point .cpload instruction.\n\
+ " IFABIO32(STRINGXP(PTR_ADDIU) " $25, 12\n") "\
+ # Compute GP.\n\
+ " STRINGXP(SETUP_GP) "\n\
+ " STRINGXV(SETUP_GP64 (0, _dl_runtime_resolve)) "\n\
+ .set reorder\n\
+ # Save slot call pc.\n\
+ move $2, $31\n\
+ " IFABIO32(STRINGXP(CPRESTORE(32))) "\n\
+ " ELF_DL_SAVE_ARG_REGS "\
+ move $4, $24\n\
+ move $5, $15\n\
+ move $6, $3\n\
+ move $7, $2\n\
+ jal __dl_runtime_resolve\n\
+ " ELF_DL_RESTORE_ARG_REGS "\
+ " STRINGXP(RESTORE_GP64) "\n\
+ " STRINGXP(PTR_ADDIU) " $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\
+ move $25, $2\n\
+ jr $25\n\
+ .end _dl_runtime_resolve\n\
+ .previous\n\
+");
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