aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Fortune <matthew.fortune@imgtec.com>2014-06-01 00:16:25 +0100
committerMatthew Fortune <matthew.fortune@imgtec.com>2014-12-31 21:09:21 +0000
commit0bd956720c457ff054325b48f26ac7c91cb060e8 (patch)
tree403b4652711dbce685ca37ab835653bee15f93b3
parentf59ad976ed979d22637c5187f6a92fbbd8c191e4 (diff)
downloadglibc-0bd956720c457ff054325b48f26ac7c91cb060e8.tar.xz
glibc-0bd956720c457ff054325b48f26ac7c91cb060e8.zip
Add support for MIPS O32 FPXX and .MIPS.abiflags
* elf/elf.h (PT_MIPS_ABIFLAGS): Define. (Elf_MIPS_ABIFlags_v0): New structure. (EF_MIPS_FP64): Define. (MIPS_AFL_REG_NONE, MIPS_AFL_REG_32, MIPS_AFL_REG_64): Likewise. (MIPS_AFL_REG_128, MIPS_AFL_ASE_DSP, MIPS_AFL_ASE_DSP64): Likewise. (MIPS_AFL_ASE_DSPR2, MIPS_AFL_ASE_EVA, MIPS_AFL_ASE_MCU): Likewise. (MIPS_AFL_ASE_MDMX, MIPS_AFL_ASE_MIPS3D, MIPS_AFL_ASE_MT): Likewise. (MIPS_AFL_ASE_SMARTMIPS, MIPS_AFL_ASE_VIRT): Likewise. (MIPS_AFL_ASE_VIRT64, MIPS_AFL_ASE_MSA, MIPS_AFL_ASE_MSA64): Likewise. (MIPS_AFL_ASE_MIPS16, MIPS_AFL_ASE_MICROMIPS): Likewise. (MIPS_AFL_ASE_XPA, MIPS_AFL_EXT_XLR, MIPS_AFL_EXT_OCTEON2): Likewise. (MIPS_AFL_EXT_OCTEONP, MIPS_AFL_EXT_LOONGSON_3A): Likewise. (MIPS_AFL_EXT_OCTEON, MIPS_AFL_EXT_5900, MIPS_AFL_EXT_4010): Likewise. (MIPS_AFL_EXT_4100, MIPS_AFL_EXT_3900, MIPS_AFL_EXT_10000): Likewise. (MIPS_AFL_EXT_SB1, MIPS_AFL_EXT_4111, MIPS_AFL_EXT_4120): Likewise. (MIPS_AFL_EXT_5400, MIPS_AFL_EXT_5500): Likewise. (MIPS_AFL_EXT_LOONGSON_2E, MIPS_AFL_EXT_LOONGSON_2F): Likewise. (Val_GNU_MIPS_ABI_FP_ANY, Val_GNU_MIPS_ABI_FP_DOUBLE): New enum values. (Val_GNU_MIPS_ABI_FP_SINGLE, Val_GNU_MIPS_ABI_FP_SOFT): Likewise. (Val_GNU_MIPS_ABI_FP_OLD_64, Val_GNU_MIPS_ABI_FP_XX): Likewise. (Val_GNU_MIPS_ABI_FP_64, Val_GNU_MIPS_ABI_FP_64A): Likewise. (Val_GNU_MIPS_ABI_FP_MAX): Likewise. * sysdeps/mips/Makefile [subdir=elf]: Add tst-abi-interlink, tst-mode-switch-1, tst-mode-switch-2, tst-mode-switch-3 tests. * sysdeps/mips/bits/linkmap.h (struct link_map_machine): Add fpmode field. * sysdeps/mips/dl-machine.h (elf_machine_matches_host): Reject EF_MIPS_FP64. * sysdeps/mips/dl-machine-reject-phdr.h: New file. * sysdeps/mips/tst-abi-fp32mod.c: Likewise. * sysdeps/mips/tst-abi-fpxxmod.c: Likewise. * sysdeps/mips/tst-abi-fpxxomod.c: Likewise. * sysdeps/mips/tst-abi-fp64mod.c: Likewise. * sysdeps/mips/tst-abi-fp64amod.c: Likewise. * sysdeps/mips/tst-abi-interlink.c: Likewise. * sysdeps/mips/tst-mode-switch-1.c: Likewise. * sysdeps/mips/tst-mode-switch-2.c: Likewise. * sysdeps/mips/tst-mode-switch-3.c: Likewise. * sysdeps/unix/sysv/linux/mips/configure.ac (o32-fpabi): Define to record the current FP ABI extension. (mips-mode-switch): Define to show if kernel headers support mode switching. * sysdeps/unix/sysv/linux/mips/configure: Regenerate. * sysdeps/unix/sysv/linux/mips/ldsodefs.h: Increase maximum supported SYSV ABI version to 3. * sysdeps/unix/sysv/linux/mips/libc-abis: Add new MIPS_O32_FP64 feature.
-rw-r--r--ChangeLog50
-rw-r--r--elf/elf.h103
-rw-r--r--sysdeps/mips/Makefile50
-rw-r--r--sysdeps/mips/bits/linkmap.h2
-rw-r--r--sysdeps/mips/dl-machine-reject-phdr.h326
-rw-r--r--sysdeps/mips/dl-machine.h5
-rw-r--r--sysdeps/mips/tst-abi-fp32mod.c22
-rw-r--r--sysdeps/mips/tst-abi-fp64amod.c22
-rw-r--r--sysdeps/mips/tst-abi-fp64mod.c22
-rw-r--r--sysdeps/mips/tst-abi-fpxxmod.c22
-rw-r--r--sysdeps/mips/tst-abi-fpxxomod.c22
-rw-r--r--sysdeps/mips/tst-abi-interlink.c844
-rw-r--r--sysdeps/mips/tst-mode-switch-1.c123
-rw-r--r--sysdeps/mips/tst-mode-switch-2.c163
-rw-r--r--sysdeps/mips/tst-mode-switch-3.c90
-rw-r--r--sysdeps/unix/sysv/linux/mips/configure142
-rw-r--r--sysdeps/unix/sysv/linux/mips/configure.ac53
-rw-r--r--sysdeps/unix/sysv/linux/mips/ldsodefs.h2
-rw-r--r--sysdeps/unix/sysv/linux/mips/libc-abis3
19 files changed, 2062 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 3e2d4b0d7e..d9d679041a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+2014-12-31 Matthew Fortune <matthew.fortune@imgtec.com>
+
+ * elf/elf.h (PT_MIPS_ABIFLAGS): Define.
+ (Elf_MIPS_ABIFlags_v0): New structure.
+ (EF_MIPS_FP64): Define.
+ (MIPS_AFL_REG_NONE, MIPS_AFL_REG_32, MIPS_AFL_REG_64): Likewise.
+ (MIPS_AFL_REG_128, MIPS_AFL_ASE_DSP, MIPS_AFL_ASE_DSP64): Likewise.
+ (MIPS_AFL_ASE_DSPR2, MIPS_AFL_ASE_EVA, MIPS_AFL_ASE_MCU): Likewise.
+ (MIPS_AFL_ASE_MDMX, MIPS_AFL_ASE_MIPS3D, MIPS_AFL_ASE_MT): Likewise.
+ (MIPS_AFL_ASE_SMARTMIPS, MIPS_AFL_ASE_VIRT): Likewise.
+ (MIPS_AFL_ASE_VIRT64, MIPS_AFL_ASE_MSA, MIPS_AFL_ASE_MSA64): Likewise.
+ (MIPS_AFL_ASE_MIPS16, MIPS_AFL_ASE_MICROMIPS): Likewise.
+ (MIPS_AFL_ASE_XPA, MIPS_AFL_EXT_XLR, MIPS_AFL_EXT_OCTEON2): Likewise.
+ (MIPS_AFL_EXT_OCTEONP, MIPS_AFL_EXT_LOONGSON_3A): Likewise.
+ (MIPS_AFL_EXT_OCTEON, MIPS_AFL_EXT_5900, MIPS_AFL_EXT_4010): Likewise.
+ (MIPS_AFL_EXT_4100, MIPS_AFL_EXT_3900, MIPS_AFL_EXT_10000): Likewise.
+ (MIPS_AFL_EXT_SB1, MIPS_AFL_EXT_4111, MIPS_AFL_EXT_4120): Likewise.
+ (MIPS_AFL_EXT_5400, MIPS_AFL_EXT_5500): Likewise.
+ (MIPS_AFL_EXT_LOONGSON_2E, MIPS_AFL_EXT_LOONGSON_2F): Likewise.
+ (Val_GNU_MIPS_ABI_FP_ANY, Val_GNU_MIPS_ABI_FP_DOUBLE): New enum values.
+ (Val_GNU_MIPS_ABI_FP_SINGLE, Val_GNU_MIPS_ABI_FP_SOFT): Likewise.
+ (Val_GNU_MIPS_ABI_FP_OLD_64, Val_GNU_MIPS_ABI_FP_XX): Likewise.
+ (Val_GNU_MIPS_ABI_FP_64, Val_GNU_MIPS_ABI_FP_64A): Likewise.
+ (Val_GNU_MIPS_ABI_FP_MAX): Likewise.
+ * sysdeps/mips/Makefile [subdir=elf]: Add tst-abi-interlink,
+ tst-mode-switch-1, tst-mode-switch-2, tst-mode-switch-3 tests.
+ * sysdeps/mips/bits/linkmap.h (struct link_map_machine): Add fpmode
+ field.
+ * sysdeps/mips/dl-machine.h (elf_machine_matches_host): Reject
+ EF_MIPS_FP64.
+ * sysdeps/mips/dl-machine-reject-phdr.h: New file.
+ * sysdeps/mips/tst-abi-fp32mod.c: Likewise.
+ * sysdeps/mips/tst-abi-fpxxmod.c: Likewise.
+ * sysdeps/mips/tst-abi-fpxxomod.c: Likewise.
+ * sysdeps/mips/tst-abi-fp64mod.c: Likewise.
+ * sysdeps/mips/tst-abi-fp64amod.c: Likewise.
+ * sysdeps/mips/tst-abi-interlink.c: Likewise.
+ * sysdeps/mips/tst-mode-switch-1.c: Likewise.
+ * sysdeps/mips/tst-mode-switch-2.c: Likewise.
+ * sysdeps/mips/tst-mode-switch-3.c: Likewise.
+ * sysdeps/unix/sysv/linux/mips/configure.ac (o32-fpabi): Define to
+ record the current FP ABI extension.
+ (mips-mode-switch): Define to show if kernel headers support mode
+ switching.
+ * sysdeps/unix/sysv/linux/mips/configure: Regenerate.
+ * sysdeps/unix/sysv/linux/mips/ldsodefs.h: Increase maximum
+ supported SYSV ABI version to 3.
+ * sysdeps/unix/sysv/linux/mips/libc-abis: Add new MIPS_O32_FP64
+ feature.
+
2014-12-31 Rajalakshmi Srinivasaraghavan <raji@linux.vnet.ibm.com>
Adhemerval Zanella <azanella@linux.vnet.ibm.com>
diff --git a/elf/elf.h b/elf/elf.h
index 341cfa6c86..683224fb8a 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_FP64 512 /* Uses FP64 (12 callee-saved). */
#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
@@ -1631,9 +1632,10 @@ typedef struct
/* Legal values for p_type field of Elf32_Phdr. */
-#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */
-#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
-#define PT_MIPS_OPTIONS 0x70000002
+#define PT_MIPS_REGINFO 0x70000000 /* Register usage information. */
+#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+#define PT_MIPS_ABIFLAGS 0x70000003 /* FP mode requirement. */
/* Special program header types. */
@@ -1755,6 +1757,101 @@ typedef struct
typedef Elf32_Addr Elf32_Conflict;
+typedef struct
+{
+ /* Version of flags structure. */
+ Elf32_Half version;
+ /* The level of the ISA: 1-5, 32, 64. */
+ unsigned char isa_level;
+ /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */
+ unsigned char isa_rev;
+ /* The size of general purpose registers. */
+ unsigned char gpr_size;
+ /* The size of co-processor 1 registers. */
+ unsigned char cpr1_size;
+ /* The size of co-processor 2 registers. */
+ unsigned char cpr2_size;
+ /* The floating-point ABI. */
+ unsigned char fp_abi;
+ /* Processor-specific extension. */
+ Elf32_Word isa_ext;
+ /* Mask of ASEs used. */
+ Elf32_Word ases;
+ /* Mask of general flags. */
+ Elf32_Word flags1;
+ Elf32_Word flags2;
+} Elf_MIPS_ABIFlags_v0;
+
+/* Values for the register size bytes of an abi flags structure. */
+
+#define MIPS_AFL_REG_NONE 0x00 /* No registers. */
+#define MIPS_AFL_REG_32 0x01 /* 32-bit registers. */
+#define MIPS_AFL_REG_64 0x02 /* 64-bit registers. */
+#define MIPS_AFL_REG_128 0x03 /* 128-bit registers. */
+
+/* Masks for the ases word of an ABI flags structure. */
+
+#define MIPS_AFL_ASE_DSP 0x00000001 /* DSP ASE. */
+#define MIPS_AFL_ASE_DSPR2 0x00000002 /* DSP R2 ASE. */
+#define MIPS_AFL_ASE_EVA 0x00000004 /* Enhanced VA Scheme. */
+#define MIPS_AFL_ASE_MCU 0x00000008 /* MCU (MicroController) ASE. */
+#define MIPS_AFL_ASE_MDMX 0x00000010 /* MDMX ASE. */
+#define MIPS_AFL_ASE_MIPS3D 0x00000020 /* MIPS-3D ASE. */
+#define MIPS_AFL_ASE_MT 0x00000040 /* MT ASE. */
+#define MIPS_AFL_ASE_SMARTMIPS 0x00000080 /* SmartMIPS ASE. */
+#define MIPS_AFL_ASE_VIRT 0x00000100 /* VZ ASE. */
+#define MIPS_AFL_ASE_MSA 0x00000200 /* MSA ASE. */
+#define MIPS_AFL_ASE_MIPS16 0x00000400 /* MIPS16 ASE. */
+#define MIPS_AFL_ASE_MICROMIPS 0x00000800 /* MICROMIPS ASE. */
+#define MIPS_AFL_ASE_XPA 0x00001000 /* XPA ASE. */
+#define MIPS_AFL_ASE_MASK 0x00001fff /* All ASEs. */
+
+/* Values for the isa_ext word of an ABI flags structure. */
+
+#define MIPS_AFL_EXT_XLR 1 /* RMI Xlr instruction. */
+#define MIPS_AFL_EXT_OCTEON2 2 /* Cavium Networks Octeon2. */
+#define MIPS_AFL_EXT_OCTEONP 3 /* Cavium Networks OcteonP. */
+#define MIPS_AFL_EXT_LOONGSON_3A 4 /* Loongson 3A. */
+#define MIPS_AFL_EXT_OCTEON 5 /* Cavium Networks Octeon. */
+#define MIPS_AFL_EXT_5900 6 /* MIPS R5900 instruction. */
+#define MIPS_AFL_EXT_4650 7 /* MIPS R4650 instruction. */
+#define MIPS_AFL_EXT_4010 8 /* LSI R4010 instruction. */
+#define MIPS_AFL_EXT_4100 9 /* NEC VR4100 instruction. */
+#define MIPS_AFL_EXT_3900 10 /* Toshiba R3900 instruction. */
+#define MIPS_AFL_EXT_10000 11 /* MIPS R10000 instruction. */
+#define MIPS_AFL_EXT_SB1 12 /* Broadcom SB-1 instruction. */
+#define MIPS_AFL_EXT_4111 13 /* NEC VR4111/VR4181 instruction. */
+#define MIPS_AFL_EXT_4120 14 /* NEC VR4120 instruction. */
+#define MIPS_AFL_EXT_5400 15 /* NEC VR5400 instruction. */
+#define MIPS_AFL_EXT_5500 16 /* NEC VR5500 instruction. */
+#define MIPS_AFL_EXT_LOONGSON_2E 17 /* ST Microelectronics Loongson 2E. */
+#define MIPS_AFL_EXT_LOONGSON_2F 18 /* ST Microelectronics Loongson 2F. */
+
+/* Masks for the flags1 word of an ABI flags structure. */
+#define MIPS_AFL_FLAGS1_ODDSPREG 1 /* Uses odd single-precision registers. */
+
+/* Object attribute values. */
+enum
+{
+ /* Not tagged or not using any ABIs affected by the differences. */
+ Val_GNU_MIPS_ABI_FP_ANY = 0,
+ /* Using hard-float -mdouble-float. */
+ Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
+ /* Using hard-float -msingle-float. */
+ Val_GNU_MIPS_ABI_FP_SINGLE = 2,
+ /* Using soft-float. */
+ Val_GNU_MIPS_ABI_FP_SOFT = 3,
+ /* Using -mips32r2 -mfp64. */
+ Val_GNU_MIPS_ABI_FP_OLD_64 = 4,
+ /* Using -mfpxx. */
+ Val_GNU_MIPS_ABI_FP_XX = 5,
+ /* Using -mips32r2 -mfp64. */
+ Val_GNU_MIPS_ABI_FP_64 = 6,
+ /* Using -mips32r2 -mfp64 -mno-odd-spreg. */
+ Val_GNU_MIPS_ABI_FP_64A = 7,
+ /* Maximum allocated FP ABI value. */
+ Val_GNU_MIPS_ABI_FP_MAX = 7
+};
/* HPPA specific definitions. */
diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile
index a1526998e0..463b121758 100644
--- a/sysdeps/mips/Makefile
+++ b/sysdeps/mips/Makefile
@@ -26,3 +26,53 @@ CPPFLAGS-crtn.S += $(pic-ccflag)
endif
ASFLAGS-.os += $(pic-ccflag)
+
+ifeq ($(subdir),elf)
+ifneq ($(o32-fpabi),)
+tests += tst-abi-interlink
+
+fpabi-modules-names =
+fpabi_list =
+ifneq (,$(filter $(o32-fpabi),32 xx xxo))
+fpabi-modules-names += tst-abi-fp32mod
+CFLAGS-tst-abi-fp32mod.c += -mfp32
+endif
+ifneq (,$(filter $(o32-fpabi),xx))
+fpabi-modules-names += tst-abi-fpxxmod
+CFLAGS-tst-abi-fpxxmod.c += -mfpxx -mno-odd-spreg
+endif
+ifneq (,$(filter $(o32-fpabi),xx xxo))
+fpabi-modules-names += tst-abi-fpxxomod
+CFLAGS-tst-abi-fpxxomod.c += -mfpxx -modd-spreg
+endif
+ifneq (,$(filter $(o32-fpabi),xx 64a))
+fpabi-modules-names += tst-abi-fp64amod
+CFLAGS-tst-abi-fp64amod.c += -mfp64 -mno-odd-spreg
+endif
+ifneq (,$(filter $(o32-fpabi),xx xxo 64a 64))
+fpabi-modules-names += tst-abi-fp64mod
+CFLAGS-tst-abi-fp64mod.c += -mfp64 -modd-spreg
+endif
+modules-names += $(fpabi-modules-names)
+
+comma:=,
+empty:=
+space:=$(empty) $(empty)
+fpabi_list=$(subst $(space),$(comma),$(patsubst tst-abi-%mod,o_%,\
+ $(fpabi-modules-names)))
+CPPFLAGS-tst-abi-interlink.c += -DFPABI_LIST=$(fpabi_list)
+CPPFLAGS-tst-abi-interlink.c += -DFPABI_COUNT=$(words $(fpabi-modules-names))
+CPPFLAGS-tst-abi-interlink.c += -DFPABI_NATIVE=o_fp$(o32-fpabi)
+$(objpfx)tst-abi-interlink: $(libdl)
+$(objpfx)tst-abi-interlink.out: $(patsubst %,$(objpfx)%.so,\
+ $(fpabi-modules-names))
+endif
+
+ifeq ($(mips-mode-switch),yes)
+ifeq ($(o32-fpabi),xx)
+tests += tst-mode-switch-1 tst-mode-switch-2 tst-mode-switch-3
+$(objpfx)tst-mode-switch-1: $(shared-thread-library)
+$(objpfx)tst-mode-switch-2: $(shared-thread-library)
+endif
+endif
+endif
diff --git a/sysdeps/mips/bits/linkmap.h b/sysdeps/mips/bits/linkmap.h
index a6df7821e6..1fb9678a6d 100644
--- a/sysdeps/mips/bits/linkmap.h
+++ b/sysdeps/mips/bits/linkmap.h
@@ -1,4 +1,6 @@
struct link_map_machine
{
ElfW(Addr) plt; /* Address of .plt */
+ ElfW(Word) fpabi; /* FP ABI of the object */
+ unsigned int odd_spreg; /* Does the object require odd_spreg support? */
};
diff --git a/sysdeps/mips/dl-machine-reject-phdr.h b/sysdeps/mips/dl-machine-reject-phdr.h
new file mode 100644
index 0000000000..b277450c4d
--- /dev/null
+++ b/sysdeps/mips/dl-machine-reject-phdr.h
@@ -0,0 +1,326 @@
+/* Machine-dependent program header inspection for the ELF loader.
+ Copyright (C) 2014 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _DL_MACHINE_REJECT_PHDR_H
+#define _DL_MACHINE_REJECT_PHDR_H 1
+
+#include <unistd.h>
+#include <sys/prctl.h>
+
+#if defined PR_GET_FP_MODE && defined PR_SET_FP_MODE
+# define HAVE_PRCTL_FP_MODE 1
+#else
+# define HAVE_PRCTL_FP_MODE 0
+#endif
+
+/* Reject an object with a debug message. */
+#define REJECT(str, args...) \
+ { \
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) \
+ _dl_debug_printf (str, ##args); \
+ return true; \
+ }
+
+/* Search the program headers for the ABI Flags. */
+
+static inline const ElfW(Phdr) *
+find_mips_abiflags (const ElfW(Phdr) *phdr, ElfW(Half) phnum)
+{
+ const ElfW(Phdr) *ph;
+
+ for (ph = phdr; ph < &phdr[phnum]; ++ph)
+ if (ph->p_type == PT_MIPS_ABIFLAGS)
+ return ph;
+ return NULL;
+}
+
+/* Cache the FP ABI value from the PT_MIPS_ABIFLAGS program header. */
+
+static bool
+cached_fpabi_reject_phdr_p (struct link_map *l)
+{
+ if (l->l_mach.fpabi == 0)
+ {
+ const ElfW(Phdr) *ph = find_mips_abiflags (l->l_phdr, l->l_phnum);
+
+ if (ph)
+ {
+ Elf_MIPS_ABIFlags_v0 * mips_abiflags;
+ if (ph->p_filesz < sizeof (Elf_MIPS_ABIFlags_v0))
+ REJECT (" %s: malformed PT_MIPS_ABIFLAGS found\n", l->l_name);
+
+ mips_abiflags = (Elf_MIPS_ABIFlags_v0 *) (l->l_addr + ph->p_vaddr);
+
+ if (__glibc_unlikely (mips_abiflags->flags2 != 0))
+ REJECT (" %s: unknown MIPS.abiflags flags2: %u\n", l->l_name,
+ mips_abiflags->flags2);
+
+ l->l_mach.fpabi = mips_abiflags->fp_abi;
+ l->l_mach.odd_spreg = (mips_abiflags->flags1
+ & MIPS_AFL_FLAGS1_ODDSPREG) != 0;
+ }
+ else
+ {
+ l->l_mach.fpabi = -1;
+ l->l_mach.odd_spreg = true;
+ }
+ }
+ return false;
+}
+
+/* Return a description of the specified floating-point ABI. */
+
+static const char *
+fpabi_string (int fpabi)
+{
+ switch (fpabi)
+ {
+ case Val_GNU_MIPS_ABI_FP_ANY:
+ return "Hard or soft float";
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
+ return "Hard float (double precision)";
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
+ return "Hard float (single precision)";
+ case Val_GNU_MIPS_ABI_FP_SOFT:
+ return "Soft float";
+ case Val_GNU_MIPS_ABI_FP_OLD_64:
+ return "Unsupported FP64";
+ case Val_GNU_MIPS_ABI_FP_XX:
+ return "Hard float (32-bit CPU, Any FPU)";
+ case Val_GNU_MIPS_ABI_FP_64:
+ return "Hard float (32-bit CPU, 64-bit FPU)";
+ case Val_GNU_MIPS_ABI_FP_64A:
+ return "Hard float compat (32-bit CPU, 64-bit FPU)";
+ case -1:
+ return "Double precision, single precision or soft float";
+ default:
+ return "Unknown FP ABI";
+ }
+}
+
+/* A structure to describe the requirements of each FP ABI extension.
+ Each field says whether the ABI can be executed in that mode. The FR0 field
+ is actually overloaded and means 'default' FR mode for the ABI. I.e. For
+ O32 it is FR0 and for N32/N64 it is actually FR1. Since this logic is
+ focussed on the intricacies of mode management for O32 we call the field
+ FR0. */
+
+struct abi_req
+{
+ bool single;
+ bool soft;
+ bool fr0;
+ bool fr1;
+ bool fre;
+};
+
+/* FP ABI requirements for all Val_GNU_MIPS_ABI_FP_* values. */
+
+static const struct abi_req reqs[Val_GNU_MIPS_ABI_FP_MAX + 1] =
+ {{true, true, true, true, true}, /* Any */
+ {false, false, true, false, true}, /* Double-float */
+ {true, false, false, false, false}, /* Single-float */
+ {false, true, false, false, false}, /* Soft-float */
+ {false, false, false, false, false}, /* old-FP64 */
+ {false, false, true, true, true}, /* FPXX */
+ {false, false, false, true, false}, /* FP64 */
+ {false, false, false, true, true}}; /* FP64A */
+
+/* FP ABI requirements for objects without a PT_MIPS_ABIFLAGS segment. */
+
+static const struct abi_req none_req = { true, true, true, false, true };
+
+/* Return true iff ELF program headers are incompatible with the running
+ host. This verifies that floating-point ABIs are compatible and
+ re-configures the hardware mode if necessary. This code handles both the
+ DT_NEEDED libraries and the dlopen'ed libraries. It also accounts for the
+ impact of dlclose. */
+
+static bool __attribute_used__
+elf_machine_reject_phdr_p (const ElfW(Phdr) *phdr, uint_fast16_t phnum,
+ const char *buf, size_t len, struct link_map *map,
+ int fd)
+{
+ const ElfW(Phdr) *ph = find_mips_abiflags (phdr, phnum);
+ struct link_map *l;
+ Lmid_t nsid;
+ int in_abi = -1;
+ struct abi_req in_req;
+ Elf_MIPS_ABIFlags_v0 *mips_abiflags = NULL;
+ bool perfect_match = false;
+#if _MIPS_SIM == _ABIO32
+ unsigned int cur_mode = -1;
+# if HAVE_PRCTL_FP_MODE
+ bool cannot_mode_switch = false;
+
+ /* Get the current hardware mode. */
+ cur_mode = __prctl (PR_GET_FP_MODE);
+# endif
+#endif
+
+ /* Read the attributes section. */
+ if (ph != NULL)
+ {
+ ElfW(Addr) size = ph->p_filesz;
+
+ if (ph->p_offset + size <= len)
+ mips_abiflags = (Elf_MIPS_ABIFlags_v0 *) (buf + ph->p_offset);
+ else
+ {
+ mips_abiflags = alloca (size);
+ __lseek (fd, ph->p_offset, SEEK_SET);
+ if (__libc_read (fd, (void *) mips_abiflags, size) != size)
+ REJECT (" unable to read PT_MIPS_ABIFLAGS\n");
+ }
+
+ if (size < sizeof (Elf_MIPS_ABIFlags_v0))
+ REJECT (" contains malformed PT_MIPS_ABIFLAGS\n");
+
+ if (__glibc_unlikely (mips_abiflags->flags2 != 0))
+ REJECT (" unknown MIPS.abiflags flags2: %u\n", mips_abiflags->flags2);
+
+ in_abi = mips_abiflags->fp_abi;
+ }
+
+ /* ANY is compatible with anything. */
+ perfect_match |= (in_abi == Val_GNU_MIPS_ABI_FP_ANY);
+
+ /* Unknown ABIs are rejected. */
+ if (in_abi != -1 && in_abi > Val_GNU_MIPS_ABI_FP_MAX)
+ REJECT (" uses unknown FP ABI: %u\n", in_abi);
+
+ /* Obtain the initial requirements. */
+ in_req = (in_abi == -1) ? none_req : reqs[in_abi];
+
+ /* Check that the new requirement does not conflict with any currently
+ loaded object. */
+ for (nsid = 0; nsid < DL_NNS; ++nsid)
+ for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
+ {
+ struct abi_req existing_req;
+
+ if (cached_fpabi_reject_phdr_p (l))
+ return true;
+
+#if _MIPS_SIM == _ABIO32
+ /* A special case arises for O32 FP64 and FP64A where the kernel
+ pre-dates PT_MIPS_ABIFLAGS. These ABIs will be blindly loaded even
+ if the hardware mode is unavailable or disabled. In this
+ circumstance the prctl call to obtain the current mode will fail.
+ Detect this situation here and reject everything. This will
+ effectively prevent dynamically linked applications from failing in
+ unusual w