aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--config.h.in4
-rw-r--r--elf/cache.c9
-rw-r--r--elf/elf.h1
-rw-r--r--ports/ChangeLog.mips68
-rw-r--r--ports/sysdeps/mips/bits/nan.h23
-rw-r--r--ports/sysdeps/mips/configure160
-rw-r--r--ports/sysdeps/mips/configure.in9
-rw-r--r--ports/sysdeps/mips/dl-machine.h14
-rw-r--r--ports/sysdeps/mips/fpu_control.h25
-rw-r--r--ports/sysdeps/mips/math_private.h6
-rw-r--r--ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h18
-rw-r--r--ports/sysdeps/mips/shlib-versions4
-rw-r--r--ports/sysdeps/mips/soft-fp/sfp-machine.h18
-rw-r--r--ports/sysdeps/unix/sysv/linux/mips/Makefile90
-rw-r--r--ports/sysdeps/unix/sysv/linux/mips/configure171
-rw-r--r--ports/sysdeps/unix/sysv/linux/mips/configure.in23
-rw-r--r--ports/sysdeps/unix/sysv/linux/mips/dl-cache.h26
-rw-r--r--ports/sysdeps/unix/sysv/linux/mips/readelflib.c35
-rw-r--r--sysdeps/generic/ldconfig.h39
20 files changed, 684 insertions, 68 deletions
diff --git a/ChangeLog b/ChangeLog
index 19fcc3ca15..ded0487082 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2013-09-18 Maciej W. Rozycki <macro@codesourcery.com>
+
+ * config.h.in (HAVE_MIPS_NAN2008): New macro.
+ * elf/elf.h (EF_MIPS_NAN2008): Likewise.
+ * sysdeps/generic/ldconfig.h (FLAG_MIPS_LIB32_NAN2008): Likewise.
+ (FLAG_MIPS64_LIBN32_NAN2008): Likewise.
+ (FLAG_MIPS64_LIBN64_NAN2008): Likewise.
+ * elf/cache.c (print_entry): Handle the new cache flags.
+
2013-09-18 Joseph Myers <joseph@codesourcery.com>
Aldy Hernandez <aldyh@redhat.com>
diff --git a/config.h.in b/config.h.in
index 30568e3af6..0ee1ec6f56 100644
--- a/config.h.in
+++ b/config.h.in
@@ -238,4 +238,8 @@
/* The pt_chown binary is being built and used by grantpt. */
#undef HAVE_PT_CHOWN
+/* ports/sysdeps/mips/configure.in */
+/* Define if using the IEEE 754-2008 NaN encoding on the MIPS target. */
+#undef HAVE_MIPS_NAN2008
+
#endif
diff --git a/elf/cache.c b/elf/cache.c
index 9bf261cd29..1a43dd7765 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -105,6 +105,15 @@ print_entry (const char *lib, int flag, unsigned int osversion,
case FLAG_ARM_LIBSF:
fputs (",soft-float", stdout);
break;
+ case FLAG_MIPS_LIB32_NAN2008:
+ fputs (",nan2008", stdout);
+ break;
+ case FLAG_MIPS64_LIBN32_NAN2008:
+ fputs (",N32,nan2008", stdout);
+ break;
+ case FLAG_MIPS64_LIBN64_NAN2008:
+ fputs (",64bit,nan2008", stdout);
+ break;
case 0:
break;
default:
diff --git a/elf/elf.h b/elf/elf.h
index fe55c928cd..058c20f5bd 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1383,6 +1383,7 @@ typedef struct
#define EF_MIPS_64BIT_WHIRL 16
#define EF_MIPS_ABI2 32
#define EF_MIPS_ABI_ON32 64
+#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
/* Legal values for MIPS architecture level. */
diff --git a/ports/ChangeLog.mips b/ports/ChangeLog.mips
index 5844bf5897..017b2c27eb 100644
--- a/ports/ChangeLog.mips
+++ b/ports/ChangeLog.mips
@@ -1,3 +1,71 @@
+2013-09-18 Maciej W. Rozycki <macro@codesourcery.com>
+ Thomas Schwinge <thomas@codesourcery.com>
+
+ * sysdeps/mips/dl-machine.h (ELF_MACHINE_NAN2008): New macro.
+ (elf_machine_matches_host): Reject objects that use a different
+ NaN encoding convention.
+ * sysdeps/mips/fpu_control.h: Document IEEE 754-2008 feature
+ control bits.
+ (_FPU_ABS2008, _FPU_NAN2008): New macros.
+ (_FPU_RESERVED): Clear bits #20 and #19.
+ (_FPU_DEFAULT) [__mips_nan2008]: Set bit #18.
+ (_FPU_IEEE) [__mips_nan2008]: Likewise.
+ * sysdeps/mips/math_private.h [__mips_nan2008]
+ (HIGH_ORDER_BIT_IS_SET_FOR_SNAN): Don't define.
+ * sysdeps/mips/bits/nan.h [__mips_nan2008] (__qnan_bytes): Define
+ appropriately.
+ * sysdeps/mips/mips64/soft-fp/sfp-machine.h [__mips_nan2008]
+ (_FP_NANFRAC_S, _FP_NANFRAC_D, _FP_NANFRAC_Q): Define 2008-NaN
+ payloads.
+ (_FP_QNANNEGATEDP): Set to 0.
+ * sysdeps/mips/soft-fp/sfp-machine.h [__mips_nan2008]
+ (_FP_NANFRAC_S, _FP_NANFRAC_D, _FP_NANFRAC_Q): Define 2008-NaN
+ payloads.
+ (_FP_QNANNEGATEDP): Set to 0.
+ * sysdeps/unix/sysv/linux/mips/dl-cache.h (_DL_CACHE_DEFAULT_ID):
+ Define 2008 NaN encoding values.
+ * sysdeps/unix/sysv/linux/mips/readelflib.c (process_elf_file):
+ Handle 2008-NaN libraries.
+ * sysdeps/mips/shlib-versions [HAVE_MIPS_NAN2008]: Set
+ ld=ld-linux-mipsn8.so.1.
+ * sysdeps/mips/configure.in: Define HAVE_MIPS_NAN2008 if the
+ 2008 NaN encoding is used.
+ * sysdeps/unix/sysv/linux/mips/Makefile (abi-variants): Add
+ 2008-NaN ABI variants.
+ (abi-o32_soft-options, abi-o32_soft-condition): Update with the
+ __mips_nan2008 macro.
+ (abi-o32_hard-options, abi-o32_hard-condition): Likewise.
+ (abi-n32_soft-options, abi-n32_soft-condition): Likewise.
+ (abi-n32_hard-options, abi-n32_hard-condition): Likewise.
+ (abi-n64_soft-options, abi-n64_soft-condition): Likewise.
+ (abi-n64_hard-options, abi-n64_hard-condition): Likewise.
+ (abi-o32_soft-ld-soname, abi-o32_hard-ld-soname): New macros.
+ (abi-n32_soft-ld-soname, abi-n32_hard-ld-soname): Likewise.
+ (abi-n64_soft-ld-soname, abi-n64_hard-ld-soname): Likewise.
+ (abi-o32_soft_2008-options): Likewise.
+ (abi-o32_soft_2008-condition): Likewise.
+ (abi-o32_hard_2008-options): Likewise.
+ (abi-o32_hard_2008-condition): Likewise.
+ (abi-n32_soft_2008-options): Likewise.
+ (abi-n32_soft_2008-condition): Likewise.
+ (abi-n32_hard_2008-options): Likewise.
+ (abi-n32_hard_2008-condition): Likewise.
+ (abi-n64_soft_2008-options): Likewise.
+ (abi-n64_soft_2008-condition): Likewise.
+ (abi-n64_hard_2008-options): Likewise.
+ (abi-n64_hard_2008-condition): Likewise.
+ (abi-o32_soft_2008-ld-soname): Likewise.
+ (abi-o32_hard_2008-ld-soname): Likewise.
+ (abi-n32_soft_2008-ld-soname): Likewise.
+ (abi-n32_hard_2008-ld-soname): Likewise.
+ (abi-n64_soft_2008-ld-soname): Likewise.
+ (abi-n64_hard_2008-ld-soname): Likewise.
+ * sysdeps/unix/sysv/linux/mips/configure.in: Include the NaN
+ encoding selection in default-abi. Set arch_minimum_kernel to
+ 10.0.0 if 2008 NaN encoding is used.
+ * sysdeps/mips/configure: Regenerate.
+ * sysdeps/unix/sysv/linux/mips/configure: Regenerate.
+
2013-08-30 Ondřej Bílka <neleai@seznam.cz>
* sysdeps/mips/memcpy.S: Fix then/than typos.
diff --git a/ports/sysdeps/mips/bits/nan.h b/ports/sysdeps/mips/bits/nan.h
index 80f7866a97..c322523275 100644
--- a/ports/sysdeps/mips/bits/nan.h
+++ b/ports/sysdeps/mips/bits/nan.h
@@ -22,10 +22,11 @@
/* IEEE Not A Number. */
-/* Note that MIPS has the qNaN and sNaN patterns reversed compared to most
- other architectures. IEEE 754-1985 left the definition of this open to
- implementations, and for MIPS the top bit of the mantissa must be SET to
- indicate a sNaN. */
+/* In legacy-NaN mode MIPS has the qNaN and sNaN patterns reversed
+ compared to most other architectures. IEEE 754-1985 left the
+ definition of this open to implementations, and for MIPS the top bit
+ of the mantissa must be SET to indicate a sNaN. In 2008-NaN mode
+ MIPS aligned to IEEE 754-2008. */
#if __GNUC_PREREQ(3,3)
@@ -33,6 +34,8 @@
#elif defined __GNUC__
+/* No 2008-NaN mode support in any GCC version before 4.9. */
+
# define NAN \
(__extension__ \
((union { unsigned __l __attribute__ ((__mode__ (__SI__))); float __d; }) \
@@ -43,10 +46,18 @@
# include <endian.h>
# if __BYTE_ORDER == __BIG_ENDIAN
-# define __qnan_bytes { 0x7f, 0xbf, 0xff, 0xff }
+# ifdef __mips_nan2008
+# define __qnan_bytes { 0x7f, 0xc0, 0, 0 }
+# else
+# define __qnan_bytes { 0x7f, 0xbf, 0xff, 0xff }
+# endif
# endif
# if __BYTE_ORDER == __LITTLE_ENDIAN
-# define __qnan_bytes { 0xff, 0xff, 0xbf, 0x7f }
+# ifdef __mips_nan2008
+# define __qnan_bytes { 0, 0, 0xc0, 0x7f }
+# else
+# define __qnan_bytes { 0xff, 0xff, 0xbf, 0x7f }
+# endif
# endif
static union { unsigned char __c[4]; float __d; } __qnan_union
diff --git a/ports/sysdeps/mips/configure b/ports/sysdeps/mips/configure
index 898e4c3f20..de8092c970 100644
--- a/ports/sysdeps/mips/configure
+++ b/ports/sysdeps/mips/configure
@@ -1,3 +1,163 @@
# This file is generated from configure.in by Autoconf. DO NOT EDIT!
# Local configure fragment for sysdeps/mips.
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler is using the 2008 NaN encoding" >&5
+$as_echo_n "checking whether the compiler is using the 2008 NaN encoding... " >&6; }
+if ${libc_cv_mips_nan2008+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+dnl
+#ifdef __mips_nan2008
+yes
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then :
+ libc_cv_mips_nan2008=yes
+else
+ libc_cv_mips_nan2008=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_mips_nan2008" >&5
+$as_echo "$libc_cv_mips_nan2008" >&6; }
+if test x$libc_cv_mips_nan2008 = xyes; then
+ $as_echo "#define HAVE_MIPS_NAN2008 1" >>confdefs.h
+
+fi
diff --git a/ports/sysdeps/mips/configure.in b/ports/sysdeps/mips/configure.in
index be9672d823..bcbdaffd9f 100644
--- a/ports/sysdeps/mips/configure.in
+++ b/ports/sysdeps/mips/configure.in
@@ -4,3 +4,12 @@ GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
dnl No MIPS GCC supports accessing static and hidden symbols in an
dnl position independent way.
dnl AC_DEFINE(PI_STATIC_AND_HIDDEN)
+
+AC_CACHE_CHECK([whether the compiler is using the 2008 NaN encoding],
+ libc_cv_mips_nan2008, [AC_EGREP_CPP(yes, [dnl
+#ifdef __mips_nan2008
+yes
+#endif], libc_cv_mips_nan2008=yes, libc_cv_mips_nan2008=no)])
+if test x$libc_cv_mips_nan2008 = xyes; then
+ AC_DEFINE(HAVE_MIPS_NAN2008)
+fi
diff --git a/ports/sysdeps/mips/dl-machine.h b/ports/sysdeps/mips/dl-machine.h
index dae938f039..722c8a0ba8 100644
--- a/ports/sysdeps/mips/dl-machine.h
+++ b/ports/sysdeps/mips/dl-machine.h
@@ -73,6 +73,16 @@ do { if ((l)->l_info[DT_MIPS (RLD_MAP)]) \
(ElfW(Addr)) (r); \
} while (0)
+#if ((defined __mips_nan2008 && !defined HAVE_MIPS_NAN2008) \
+ || (!defined __mips_nan2008 && defined HAVE_MIPS_NAN2008))
+# error "Configuration inconsistency: __mips_nan2008 != HAVE_MIPS_NAN2008, overridden CFLAGS?"
+#endif
+#ifdef __mips_nan2008
+# define ELF_MACHINE_NAN2008 EF_MIPS_NAN2008
+#else
+# define ELF_MACHINE_NAN2008 0
+#endif
+
/* Return nonzero iff ELF header is compatible with the running host. */
static inline int __attribute_used__
elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
@@ -83,6 +93,10 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
return 0;
#endif
+ /* Don't link 2008-NaN and legacy-NaN objects together. */
+ if ((ehdr->e_flags & EF_MIPS_NAN2008) != ELF_MACHINE_NAN2008)
+ return 0;
+
switch (ehdr->e_machine)
{
case EM_MIPS:
diff --git a/ports/sysdeps/mips/fpu_control.h b/ports/sysdeps/mips/fpu_control.h
index 770cbb31d8..40469627a7 100644
--- a/ports/sysdeps/mips/fpu_control.h
+++ b/ports/sysdeps/mips/fpu_control.h
@@ -29,7 +29,9 @@
* available for MIPS III and newer.
* 23 -> Condition bit
* 22-21 -> reserved for architecture implementers
- * 20-18 -> reserved (read as 0, write with 0)
+ * 20 -> reserved (read as 0, write with 0)
+ * 19 -> IEEE 754-2008 non-arithmetic ABS.fmt and NEG.fmt enable
+ * 18 -> IEEE 754-2008 recommended NaN encoding enable
* 17 -> cause bit for unimplemented operation
* 16 -> cause bit for invalid exception
* 15 -> cause bit for division by zero exception
@@ -79,22 +81,33 @@ extern fpu_control_t __fpu_control;
/* flush denormalized numbers to zero */
#define _FPU_FLUSH_TZ 0x1000000
+/* IEEE 754-2008 compliance control. */
+#define _FPU_ABS2008 0x80000
+#define _FPU_NAN2008 0x40000
+
/* rounding control */
#define _FPU_RC_NEAREST 0x0 /* RECOMMENDED */
#define _FPU_RC_ZERO 0x1
#define _FPU_RC_UP 0x2
#define _FPU_RC_DOWN 0x3
-#define _FPU_RESERVED 0xfe9c0000 /* Reserved bits in cw */
+#define _FPU_RESERVED 0xfe840000 /* Reserved bits in cw, incl NAN2008. */
/* The fdlibm code requires strict IEEE double precision arithmetic,
and no interrupts for exceptions, rounding to nearest. */
+#ifdef __mips_nan2008
+# define _FPU_DEFAULT 0x00040000
+#else
+# define _FPU_DEFAULT 0x00000000
+#endif
-#define _FPU_DEFAULT 0x00000000
-
-/* IEEE: same as above, but exceptions */
-#define _FPU_IEEE 0x00000F80
+/* IEEE: same as above, but exceptions. */
+#ifdef __mips_nan2008
+# define _FPU_IEEE 0x00040F80
+#else
+# define _FPU_IEEE 0x00000F80
+#endif
/* Type of the control word. */
typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__SI__)));
diff --git a/ports/sysdeps/mips/math_private.h b/ports/sysdeps/mips/math_private.h
index f0ba4ee706..6b99957c7b 100644
--- a/ports/sysdeps/mips/math_private.h
+++ b/ports/sysdeps/mips/math_private.h
@@ -18,9 +18,13 @@
#ifndef _MATH_PRIVATE_H
+#ifdef __mips_nan2008
+/* MIPS aligned to IEEE 754-2008. */
+#else
/* One of the few architectures where the meaning of the quiet/signaling bit is
inverse to IEEE 754-2008 (as well as common practice for IEEE 754-1985). */
-#define HIGH_ORDER_BIT_IS_SET_FOR_SNAN
+# define HIGH_ORDER_BIT_IS_SET_FOR_SNAN
+#endif
#include_next <math_private.h>
diff --git a/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h b/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
index 9cfd6fbb7b..5be50927d0 100644
--- a/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
+++ b/ports/sysdeps/mips/mips64/soft-fp/sfp-machine.h
@@ -24,15 +24,25 @@
#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv_norm(D,R,X,Y)
#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
-#define _FP_NANFRAC_S (_FP_QNANBIT_S - 1)
-#define _FP_NANFRAC_D (_FP_QNANBIT_D - 1)
-#define _FP_NANFRAC_Q (_FP_QNANBIT_Q - 1), -1
+#ifdef __mips_nan2008
+# define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
+# define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1)
+# define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1
+#else
+# define _FP_NANFRAC_S (_FP_QNANBIT_S - 1)
+# define _FP_NANFRAC_D (_FP_QNANBIT_D - 1)
+# define _FP_NANFRAC_Q (_FP_QNANBIT_Q - 1), -1
+#endif
#define _FP_NANSIGN_S 0
#define _FP_NANSIGN_D 0
#define _FP_NANSIGN_Q 0
#define _FP_KEEPNANFRACP 1
-#define _FP_QNANNEGATEDP 1
+#ifdef __mips_nan2008
+# define _FP_QNANNEGATEDP 0
+#else
+# define _FP_QNANNEGATEDP 1
+#endif
/* From my experiments it seems X is chosen unless one of the
NaNs is sNaN, in which case the result is NANSIGN/NANFRAC. */
diff --git a/ports/sysdeps/mips/shlib-versions b/ports/sysdeps/mips/shlib-versions
index 780939369b..b153732c27 100644
--- a/ports/sysdeps/mips/shlib-versions
+++ b/ports/sysdeps/mips/shlib-versions
@@ -3,7 +3,11 @@ mips.*-.*-linux.* libm=6 GLIBC_2.0 GLIBC_2.2
# Working mips versions were never released between 2.0 and 2.2.
mips.*-.*-linux.* libc=6 GLIBC_2.0 GLIBC_2.2
+%ifdef HAVE_MIPS_NAN2008
+mips.*-.*-linux.* ld=ld-linux-mipsn8.so.1 GLIBC_2.0 GLIBC_2.2
+%else
mips.*-.*-linux.* ld=ld.so.1 GLIBC_2.0 GLIBC_2.2
+%endif
mips.*-.*-linux.* libdl=2 GLIBC_2.0 GLIBC_2.2
mips.*-.*-linux.* libresolv=2 GLIBC_2.0 GLIBC_2.2
diff --git a/ports/sysdeps/mips/soft-fp/sfp-machine.h b/ports/sysdeps/mips/soft-fp/sfp-machine.h
index a60bef7665..fff3b3c613 100644
--- a/ports/sysdeps/mips/soft-fp/sfp-machine.h
+++ b/ports/sysdeps/mips/soft-fp/sfp-machine.h
@@ -21,15 +21,25 @@
#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y)
#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
-#define _FP_NANFRAC_S (_FP_QNANBIT_S - 1)
-#define _FP_NANFRAC_D (_FP_QNANBIT_D - 1), -1
-#define _FP_NANFRAC_Q (_FP_QNANBIT_Q - 1), -1, -1, -1
+#ifdef __mips_nan2008
+# define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
+# define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1
+# define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#else
+# define _FP_NANFRAC_S (_FP_QNANBIT_S - 1)
+# define _FP_NANFRAC_D (_FP_QNANBIT_D - 1), -1
+# define _FP_NANFRAC_Q (_FP_QNANBIT_Q - 1), -1, -1, -1
+#endif
#define _FP_NANSIGN_S 0
#define _FP_NANSIGN_D 0
#define _FP_NANSIGN_Q 0
#define _FP_KEEPNANFRACP 1
-#define _FP_QNANNEGATEDP 1
+#ifdef __mips_nan2008
+# define _FP_QNANNEGATEDP 0
+#else
+# define _FP_QNANNEGATEDP 1
+#endif
/* From my experiments it seems X is chosen unless one of the
NaNs is sNaN, in which case the result is NANSIGN/NANFRAC. */
diff --git a/ports/sysdeps/unix/sysv/linux/mips/Makefile b/ports/sysdeps/unix/sysv/linux/mips/Makefile
index 1e54036bfe..9070b775c4 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/Makefile
+++ b/ports/sysdeps/unix/sysv/linux/mips/Makefile
@@ -8,7 +8,9 @@ sysdep_routines += cachectl cacheflush sysmips _test_and_set
sysdep_headers += sys/cachectl.h sys/sysmips.h sys/tas.h
endif
-abi-variants := o32_soft o32_hard n32_soft n32_hard n64_soft n64_hard
+abi-variants := o32_soft o32_hard o32_soft_2008 o32_hard_2008
+abi-variants += n32_soft n32_hard n32_soft_2008 n32_hard_2008
+abi-variants += n64_soft n64_hard n64_soft_2008 n64_hard_2008
ifeq (,$(filter $(default-abi),$(abi-variants)))
Unknown ABI, must be one of $(abi-variants)
@@ -18,29 +20,89 @@ abi-includes := sgidefs.h
# _MIPS_SIM_ABI32 == 1, _MIPS_SIM_NABI32 == 2, _MIPS_SIM_ABI64 == 3
abi-o32_soft-options := -U_MIPS_SIM -D_MIPS_SIM=1 \
- -D__mips_soft_float -U__mips_hard_float
-abi-o32_soft-condition := defined(__mips_soft_float) \
- && (_MIPS_SIM == _MIPS_SIM_ABI32)
+ -D__mips_soft_float -U__mips_hard_float \
+ -U__mips_nan2008
+abi-o32_soft-condition := !defined(__mips_nan2008) \
+ && defined(__mips_soft_float) \
+ && (_MIPS_SIM == _MIPS_SIM_ABI32)
+abi-o32_soft-ld-soname := ld.so.1
abi-o32_hard-options := -U_MIPS_SIM -D_MIPS_SIM=1 \
- -D__mips_hard_float -U__mips_soft_float
-abi-o32_hard-condition := defined(__mips_hard_float) \
+ -D__mips_hard_float -U__mips_soft_float \
+ -U__mips_nan2008
+abi-o32_hard-condition := !defined(__mips_nan2008) \
+ && defined(__mips_hard_float) \
&& (_MIPS_SIM == _MIPS_SIM_ABI32)
+abi-o32_hard-ld-soname := ld.so.1
+abi-o32_soft_2008-options := -U_MIPS_SIM -D_MIPS_SIM=1 \
+ -D__mips_soft_float -U__mips_hard_float \
+ -D__mips_nan2008
+abi-o32_soft_2008-condition := defined(__mips_nan2008) \
+ && defined(__mips_soft_float) \
+ && (_MIPS_SIM == _MIPS_SIM_ABI32)
+abi-o32_soft_2008-ld-soname := ld-linux-mipsn8.so.1
+abi-o32_hard_2008-options := -U_MIPS_SIM -D_MIPS_SIM=1 \
+ -D__mips_hard_float -U__mips_soft_float \
+ -D__mips_nan2008
+abi-o32_hard_2008-condition := defined(__mips_nan2008) \
+ && defined(__mips_hard_float) \
+ && (_MIPS_SIM == _MIPS_SIM_ABI32)
+abi-o32_hard_2008-ld-soname := ld-linux-mipsn8.so.1
abi-n32_soft-options := -U_MIPS_SIM -D_MIPS_SIM=2 \
- -D__mips_soft_float -U__mips_hard_float
-abi-n32_soft-condition := defined(__mips_soft_float) \
+ -D__mips_soft_float -U__mips_hard_float \
+ -U__mips_nan2008
+abi-n32_soft-condition := !defined(__mips_nan2008) \
+ && defined(__mips_soft_float) \
&& (_MIPS_SIM == _MIPS_SIM_NABI32)
+abi-n32_soft-ld-soname := ld.so.1
abi-n32_hard-options := -U_MIPS_SIM -D_MIPS_SIM=2 \
- -D__mips_hard_float -U__mips_soft_float
-abi-n32_hard-condition := defined(__mips_hard_float) \
+ -D__mips_hard_float -U__mips_soft_float \
+ -U__mips_nan2008
+abi-n32_hard-condition := !defined(__mips_nan2008) \
+ && defined(__mips_hard_float) \
&& (_MIPS_SIM == _MIPS_SIM_NABI32)
+abi-n32_hard-ld-soname := ld.so.1
+abi-n32_soft_2008-options := -U_MIPS_SIM -D_MIPS_SIM=2 \
+ -D__mips_soft_float -U__mips_hard_float \
+ -D__mips_nan2008
+abi-n32_soft_2008-condition := defined(__mips_nan2008) \
+ && defined(__mips_soft_float) \
+ && (_MIPS_SIM == _MIPS_SIM_NABI32)
+abi-n32_soft_2008-ld-soname := ld-linux-mipsn8.so.1
+abi-n32_hard_2008-options := -U_MIPS_SIM -D_MIPS_SIM=2 \
+ -D__mips_hard_float -U__mips_soft_float \
+ -D__mips_nan2008
+abi-n32_hard_2008-condition := defined(__mips_nan2008) \
+ && defined(__mips_hard_float) \
+ && (_MIPS_SIM == _MIPS_SIM_NABI32)
+abi-n32_hard_2008-ld-soname := ld-linux-mipsn8.so.1
abi-n64_soft-options := -U_MIPS_SIM -D_MIPS_SIM=3 \
- -D__mips_soft_float -U__mips_hard_float
-abi-n64_soft-condition := defined(__mips_soft_float) \
+ -D__mips_soft_float -U__mips_hard_float \
+ -U__mips_nan2008
+abi-n64_soft-condition := !defined(__mips_nan2008) \
+ && defined(__mips_soft_float) \
&& (_MIPS_SIM == _MIPS_SIM_ABI64)
+abi-n64_soft-ld-soname := ld.so.1
abi-n64_hard-options := -U_MIPS_SIM -D_MIPS_SIM=3 \
- -D__mips_hard_float -U__mips_soft_float
-abi-n64_hard-condition := defined(__mips_hard_float) \
+ -D__mips_hard_float -U__mips_soft_float \
+ -U__mips_nan2008
+abi-n64_hard-condition := !defined(__mips_nan2008) \
+ && defined(__mips_hard_float) \
&& (_MIPS_SIM == _MIPS_SIM_ABI64)
+abi-n64_hard-ld-soname := ld.so.1
+abi-n64_soft_2008-options := -U_MIPS_SIM -D_MIPS_SIM=3 \
+ -D__mips_soft_float -U__mips_hard_float \
+ -D__mips_nan2008
+abi-n64_soft_2008-condition := defined(__mips_nan2008) \
+ && defined(__mips_soft_float) \
+ && (_MIPS_SIM == _MIPS_SIM_ABI64)
+abi-n64_soft_2008-ld-soname := ld-linux-mipsn8.so.1
+abi-n64_hard_2008-options := -U_MIPS_SIM -D_MIPS_SIM=3 \
+ -D__mips_hard_float -U__mips_soft_float \
+ -D__mips_nan2008
+abi-n64_hard_2008-condition := defined(__mips_nan2008) \
+ && defined(__mips_hard_float) \
+ && (_MIPS_SIM == _MIPS_SIM_ABI64)
+abi-n64_hard_2008-ld-soname := ld-linux-mipsn8.so.1
ifeq ($(subdir),elf)
ifeq ($(build-shared),yes)
diff --git a/ports/sysdeps/unix/sysv/linux/mips/configure b/ports/sysdeps/unix/sysv/linux/mips/configure
index b4ee83e3ae..088210ff97 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/configure
+++ b/ports/sysdeps/unix/sysv/linux/mips/configure
@@ -105,8 +105,168 @@ if test -z "$libc_mips_float"; then
as_fn_error $? "could not determine if compiler is using hard or soft floating point ABI" "$LINENO" 5
fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler is using the 2008 NaN encoding" >&5
+$as_echo_n "checking whether the compiler is using the 2008 NaN encoding... " >&6; }
+if ${libc_cv_mips_nan2008+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+dnl
+#ifdef __mips_nan2008
+yes
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then :
+ libc_cv_mips_nan2008=yes
+else
+ libc_cv_mips_nan2008=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_mips_nan2008" >&5
+$as_echo "$libc_cv_mips_nan2008" >&6; }
+
+libc_mips_nan=
+if test x"$libc_cv_mips_nan2008" = xyes; then
+ libc_mips_nan=_2008
+fi
+
config_vars="$config_vars
-default-abi = ${libc_mips_abi}_${libc_mips_float}"
+default-abi = ${libc_mips_abi}_${libc_mips_float}${libc_mips_nan}"
case "$prefix" in
/usr | /usr/)
@@ -138,3 +298,12 @@ case "$prefix" in
esac
libc_cv_gcc_unwind_find_fde=yes
+
+if test -z "$arch_minimum_kernel"; then
+ if test x$libc_cv_mips_nan2008 = xyes; then
+ # FIXME: Adjust this setting to the actual first upstream kernel
+ # version to support the 2008 NaN encoding and then remove this
+ # comment.
+ arch_minimum_kernel=10.0.0
+ fi
+fi
diff --git a/ports/sysdeps/unix/sysv/linux/mips/configure.in b/ports/sysdeps/unix/sysv/linux/mips/configure.in
index b8dde6ef7a..7087a14a5e 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/configure.in
+++ b/ports/sysdeps/unix/sysv/linux/mips/configure.in
@@ -44,7 +44,19 @@ if test -z "$libc_mips_float"; then
AC_MSG_ERROR([could not determine if compiler is using hard or soft floating point ABI])
fi
-LIBC_CONFIG_VAR([default-abi], [${libc_mips_abi}_${libc_mips_float}])
+AC_CACHE_CHECK([whether the compiler is using the 2008 NaN encoding],
+ libc_cv_mips_nan2008, [AC_EGREP_CPP(yes, [dnl
+#ifdef __mips_nan2008
+yes
+#endif], libc_cv_mips_nan2008=yes, libc_cv_mips_nan2008=no)])
+
+libc_mips_nan=
+if test x"$libc_cv_mips_nan2008" = xyes; then
+ libc_mips_nan=_2008
+fi
+
+LIBC_CONFIG_VAR([default-abi],
+ [${libc_mips_abi}_${libc_mips_float}${libc_mips_nan}])
case "$prefix" in
/usr | /usr/)
@@ -76,3 +88,12 @@ case "$prefix" in
esac
libc_cv_gcc_unwind_find_fde=yes
+
+if test -z "$arch_minimum_kernel"; then
+ if test x$libc_cv_mips_nan2008 = xyes; then
+ # FIXME: Adjust this setting to the actual first upstream kernel
+ # version to support the 2008 NaN encoding and then remove this
+ # comment.
+ arch_minimum_kernel=10.0.0
+ fi
+fi
diff --git a/ports/sysdeps/unix/sysv/linux/mips/dl-cache.h b/ports/sysdeps/unix/sysv/linux/mips/dl-cache.h
index 4a7f3f1f2a..49ad99ab92 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/dl-cache.h
+++ b/ports/sysdeps/unix/sysv/linux/mips/dl-cache.h
@@ -18,11 +18,27 @@
#include <ldconfig.h>
-/* Redefine the cache ID for new ABIs; o32 keeps using the generic check. */
-#if _MIPS_SIM == _ABI64
-# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN64 | FLAG_ELF_LIBC6)
-#elif _MIPS_SIM == _ABIN32
-# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN32 | FLAG_ELF_LIBC6)
+#if ((defined __mips_nan2008 && !defined HAVE_MIPS_NAN2008) \
+ || (!defined __mips_nan2008 && defined HAVE_MIPS_NAN2008))
+# error "Configuration inconsistency: __mips_nan2008 != HAVE_MIPS_NAN2008, overridden CFLAGS?"
+#endif
+
+/* Redefine the cache ID for new ABIs and 2008 NaN support; legacy o32
+ keeps using the generic check. */
+#ifdef __mips_nan2008
+# if _MIPS_SIM == _ABIO32
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS_LIB32_NAN2008 | FLAG_ELF_LIBC6)
+# elif _MIPS_SIM == _ABI64
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN64_NAN2008 | FLAG_ELF_LIBC6)
+# elif _MIPS_SIM == _ABIN32
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN32_NAN2008 | FLAG_ELF_LIBC6)
+# endif
+#else
+# if _MIPS_SIM == _ABI64
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN64 | FLAG_ELF_LIBC6)
+# elif _MIPS_SIM == _ABIN32
+# define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN32 | FLAG_ELF_LIBC6)
+# endif
#endif
#ifdef _DL_CACHE_DEFAULT_ID
diff --git a/ports/sysdeps/unix/sysv/linux/mips/readelflib.c b/ports/sysdeps/unix/sysv/linux/mips/readelflib.c
index 10f0ff7022..fd57a735c3 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/readelflib.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/readelflib.c
@@ -33,19 +33,32 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
unsigned int *osversion, char **soname, void *file_contents,
size_t file_length)
{
- ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
+ union
+ {
+ Elf64_Ehdr *eh64;
+ Elf32_Ehdr *eh32;
+ ElfW(Ehdr) *eh;
+ }
+ elf_header;
int ret;
- if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
+ elf_header.eh = file_contents;
+ if (elf_header.eh->e_ident [EI_CLASS] == ELFCLASS32)
{
- Elf32_Ehdr *elf32_header = (Elf32_Ehdr *) elf_header;
-
ret = process_elf32_file (file_name, lib, flag, osversion, soname,
file_contents, file_length);
+ if (!ret)
+ {
+ Elf32_Word flags = elf_header.eh32->e_flags;
+ int nan2008 = (flags & EF_MIPS_NAN2008) != 0;
- /* n32 libraries are always libc.so.6+. */
- if (!ret && (elf32_header->e_flags & EF_MIPS_ABI2) != 0)
- *flag = FLAG_MIPS64_LIBN32|FLAG_ELF_LIBC6;
+ /* n32 libraries are always libc.so.6+, o32 only if 2008 NaN. */
+ if ((flags & EF_MIPS_ABI2) != 0)
+ *flag = (nan2008 ? FLAG_MIPS64_LIBN32_NAN2008
+ : FLAG_MIPS64_LIBN32) | FLAG_ELF_LIBC6;
+ else if (nan2008)
+ *flag = FLAG_MIPS_LIB32_NAN2008 | FLAG_ELF_LIBC6;
+ }
}
else
{
@@ -53,7 +66,13 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
file_contents, file_length);
/* n64 libraries are always libc.so.6+. */
if (!ret)
- *flag = FLAG_MIPS64_LIBN64|FLAG_ELF_LIBC6;
+ {
+ Elf64_Word flags = elf_header.eh64->e_flags;
+ int nan2008 = (flags & EF_MIPS_NAN2008) != 0;
+
+ *flag = (nan2008 ? FLAG_MIPS64_LIBN64_NAN2008
+ : FLAG_MIPS64_LIBN64) | FLAG_ELF_LIBC6;
+ }
}
return ret;
diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h
index d96089d492..037f959954 100644
--- a/sysdeps/generic/ldconfig.h
+++ b/sysdeps/generic/ldconfig.h
@@ -21,24 +21,27 @@
#include <stdint.h>
-#define FLAG_ANY -1
-#define FLAG_TYPE_MASK 0x00ff
-#define FLAG_LIBC4 0x0000
-#define FLAG_ELF 0x0001
-#define FLAG_ELF_LIBC5 0x0002
-#define FLAG_ELF_LIBC6 0x0003
-#define FLAG_REQUIRED_MASK 0xff00
-#define FLAG_SPARC_LIB64 0x0100
-#define FLAG_IA64_LIB64 0x0200
-#define FLAG_X8664_LIB64 0x0300
-#define FLAG_S390_LIB64 0x0400
-#define FLAG_POWERPC_LIB64 0x0500
-#define FLAG_MIPS64_LIBN32 0x0600
-#define FLAG_MIPS64_LIBN64 0x0700
-#define FLAG_X8664_LIBX32 0x0800
-#define FLAG_ARM_LIBHF 0x0900
-#define FLAG_AARCH64_LIB64 0x0a00
-#define FLAG_ARM_LIBSF 0x0b00
+#define FLAG_ANY -1
+#define FLAG_TYPE_MASK 0x00ff
+#define FLAG_LIBC4 0x0000
+#define FLAG_ELF 0x0001
+#define FLAG_ELF_LIBC5 0x0002
+#define FLAG_ELF_LIBC6 0x0003
+#define FLAG_REQUIRED_MASK 0xff00
+#define FLAG_SPARC_LIB64 0x0100
+#define FLAG_IA64_LIB64 0x0200
+#define FLAG_X8664_LIB64 0x0300
+#define FLAG_S390_LIB64 0x0400
+#define FLAG_POWERPC_LIB64 0x0500
+#define FLAG_MIPS64_LIBN32 0x0600
+#define FLAG_MIPS64_LIBN64 0x0700
+#define FLAG_X8664_LIBX32 0x0800
+#define FLAG_ARM_LIBHF 0x0900
+#define FLAG_AARCH64_LIB64 0x0a00
+#define FLAG_ARM_LIBSF 0x0b00
+#define FLAG_MIPS_LIB32_NAN2008 0x0c00
+#define FLAG_MIPS64_LIBN32_NAN2008 0x0d00
+#define FLAG_MIPS64_LIBN64_NAN2008 0x0e00
/* Name of auxiliary cache. */
#define _PATH_LDCONFIG_AUX_CACHE "/var/cache/ldconfig/aux-cache"