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.
This commit is contained in:
Matthew Fortune 2014-06-01 00:16:25 +01:00
parent f59ad976ed
commit 0bd956720c
19 changed files with 2062 additions and 4 deletions

View File

@ -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>

103
elf/elf.h
View File

@ -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. */

View File

@ -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

View File

@ -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? */
};

View File

@ -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 ways but there is nothing we can do to help static
applications. */
if ((l->l_mach.fpabi == Val_GNU_MIPS_ABI_FP_64A
|| l->l_mach.fpabi == Val_GNU_MIPS_ABI_FP_64)
&& cur_mode == -1)
REJECT (" found %s running in the wrong mode\n",
fpabi_string (l->l_mach.fpabi));
#endif
/* Found a perfect match, success. */
perfect_match |= (in_abi == l->l_mach.fpabi);
/* Unknown ABIs are rejected. */
if (l->l_mach.fpabi != -1 && l->l_mach.fpabi > Val_GNU_MIPS_ABI_FP_MAX)
REJECT (" found unknown FP ABI: %u\n", l->l_mach.fpabi);
existing_req = (l->l_mach.fpabi == -1 ? none_req
: reqs[l->l_mach.fpabi]);
/* Merge requirements. */
in_req.soft &= existing_req.soft;
in_req.single &= existing_req.single;
in_req.fr0 &= existing_req.fr0;
in_req.fr1 &= existing_req.fr1;
in_req.fre &= existing_req.fre;
/* If there is at least one mode which is still usable then the new
object can be loaded. */
if (in_req.single || in_req.soft || in_req.fr1 || in_req.fr0
|| in_req.fre)
{
#if _MIPS_SIM == _ABIO32 && HAVE_PRCTL_FP_MODE
/* Account for loaded ABIs which prohibit mode switching. */
if (l->l_mach.fpabi == Val_GNU_MIPS_ABI_FP_XX)
cannot_mode_switch |= l->l_mach.odd_spreg;
#endif
}
else
REJECT (" uses %s, already loaded %s\n",
fpabi_string (in_abi),
fpabi_string (l->l_mach.fpabi));
}
#if _MIPS_SIM == _ABIO32
/* At this point we know that the newly loaded object is compatible with all
existing objects but the hardware mode may not be correct. */
if ((in_req.fr1 || in_req.fre || in_req.fr0)
&& !perfect_match)
{
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
_dl_debug_printf (" needs %s%s mode\n", in_req.fr0 ? "FR0 or " : "",
(in_req.fre && !in_req.fr1) ? "FRE" : "FR1");
/* If the PR_GET_FP_MODE is not supported then only FR0 is available.
If the overall requirements cannot be met by FR0 then reject the
object. */
if (cur_mode == -1)
return !in_req.fr0;
# if HAVE_PRCTL_FP_MODE
{
unsigned int fr1_mode = PR_FP_MODE_FR;
/* It is not possible to change the mode of a thread which may be
executing FPXX code with odd-singles. If an FPXX object with
odd-singles is loaded then just check the current mode is OK. This
can be either the FR1 mode or FR0 if the requirements are met by
FR0. */
if (cannot_mode_switch)
return (!(in_req.fre && cur_mode == (PR_FP_MODE_FR | PR_FP_MODE_FRE))
&& !(in_req.fr1 && cur_mode == PR_FP_MODE_FR)
&& !(in_req.fr0 && cur_mode == 0));
/* If the overall requirements can be satisfied by FRE but not FR1 then
fr1_mode must become FRE. */
if (in_req.fre && !in_req.fr1)
fr1_mode |= PR_FP_MODE_FRE;
/* Set the new mode. Use fr1_mode if the requirements cannot be met by
FR0. */
if (!in_req.fr0)
return __prctl (PR_SET_FP_MODE, fr1_mode) != 0;
else if (__prctl (PR_SET_FP_MODE, /* fr0_mode */ 0) != 0)
{
/* Setting FR0 can validly fail on an R6 core so retry with the FR1
mode as a fall back. */
if (errno != ENOTSUP)
return true;
return __prctl (PR_SET_FP_MODE, fr1_mode) != 0;
}
}
# endif /* HAVE_PRCTL_FP_MODE */
}
#endif /* _MIPS_SIM == _ABIO32 */
return false;
}
#endif /* dl-machine-reject-phdr.h */

View File

@ -99,6 +99,11 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
if ((ehdr->e_flags & EF_MIPS_NAN2008) != ELF_MACHINE_NAN2008)
return 0;
/* Ensure that the old O32 FP64 ABI is never loaded, it is not supported
on linux. */
if (ehdr->e_flags & EF_MIPS_FP64)
return 0;
switch (ehdr->e_machine)
{
case EM_MIPS:

View File

@ -0,0 +1,22 @@
/* 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/>. */
int
fp32 (void)
{
return 1;
}

View File

@ -0,0 +1,22 @@
/* 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/>. */
int
fp64a (void)
{
return 7;
}

View File

@ -0,0 +1,22 @@
/* 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/>. */
int
fp64 (void)
{
return 6;
}

View File

@ -0,0 +1,22 @@
/* 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/>. */
int
fpxx (void)
{
return 5;
}

View File

@ -0,0 +1,22 @@
/* 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/>. */
int
fpxxo (void)
{
return 5 + 100;
}

View File

@ -0,0 +1,844 @@
/* 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/>. */
#include <sys/prctl.h>
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#if defined PR_GET_FP_MODE && defined PR_SET_FP_MODE
# define HAVE_PRCTL_FP_MODE 1
# define FR1_MODE (PR_FP_MODE_FR)
# define FRE_MODE (PR_FP_MODE_FR | PR_FP_MODE_FRE)
#else
# define HAVE_PRCTL_FP_MODE 0
# define FR1_MODE 0x1
# define FRE_MODE 0x2
#endif
#define STR_VAL(VAL) #VAL
#define N_STR(VAL) STR_VAL(VAL)
#define START_STATE(NAME) \
case s_ ## NAME: \
{ \
switch (obj) \
{
#define END_STATE \
default: \
return false; \
} \
break; \
}
#define NEXT(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
current_fp_state = s_ ## NEXT_STATE; \
break;
#define NEXT_REQ_FR1(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
{ \
if (has_fr1) \
current_fp_state = s_ ## NEXT_STATE; \
else \
return false; \
} \
break;
#define NEXT_REQ_FR0(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
{ \
if (!is_r6 \
|| (is_r6 && has_fr1 && has_fre)) \
current_fp_state = s_ ## NEXT_STATE; \
else \
return false; \
} \
break;
#define NEXT_REQ_FRE(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
{ \
if (has_fr1 && has_fre) \
current_fp_state = s_ ## NEXT_STATE; \
else \
return false; \
} \
break;
#define NEXT_NO_MODE_CHANGE(OBJ, NEXT_STATE) \
case o_ ## OBJ: \
{ \
if (current_mode_valid_p (s_ ## NEXT_STATE)) \
{ \
current_fp_state = s_ ## NEXT_STATE; \
cant_change_mode = true; \
} \
else \
return false; \
} \
break;
static const char * const shared_lib_names[] =
{
"tst-abi-fpanymod.so", "tst-abi-fpsoftmod.so", "tst-abi-fpsinglemod.so",
"tst-abi-fp32mod.so", "tst-abi-fp64mod.so", "tst-abi-fp64amod.so",
"tst-abi-fpxxmod.so", "tst-abi-fpxxomod.so"
};
struct fp_mode_req
{
int mode1;
int mode2;
int mode3;
};
enum fp_obj
{
o_any,
o_soft,
o_single,
o_fp32,
o_fp64,
o_fp64a,
o_fpxx,
o_fpxxo,
o_max
};
enum fp_state
{
s_any,
s_soft,
s_single,
s_fp32,
s_fpxx,
s_fpxxo,
s_fp64a,
s_fp64,
s_fpxxo_fpxx,
s_fp32_fpxx,
s_fp32_fpxxo,
s_fp32_fpxxo_fpxx,
s_fp32_fp64a_fpxx,
s_fp32_fp64a_fpxxo,
s_fp32_fp64a_fpxxo_fpxx,
s_fp64a_fp32,
s_fp64a_fpxx,
s_fp64a_fpxxo,
s_fp64a_fp64,
s_fp64a_fp64_fpxx,
s_fp64a_fp64_fpxxo,
s_fp64a_fpxx_fpxxo,
s_fp64a_fp64_fpxxo_fpxx,
s_fp64_fpxx,
s_fp64_fpxxo,
s_fp64_fpxx_fpxxo
};
static int current_fp_mode;
static bool cant_change_mode = false;
static bool has_fr1 = false;
static bool has_fre = false;
static bool is_r6 = false;
static unsigned int fp_obj_count[o_max];
void * shared_lib_ptrs[o_max];
static enum fp_state current_fp_state = s_any;
static enum fp_obj test_objects[FPABI_COUNT] = { FPABI_LIST };
/* This function will return the valid FP modes for the specified state. */
static struct fp_mode_req
compute_fp_modes (enum fp_state state)
{
struct fp_mode_req requirements;
requirements.mode1 = -1;
requirements.mode2 = -1;
requirements.mode3 = -1;
switch (state)
{
case s_single:
{
if (is_r6)
requirements.mode1 = FR1_MODE;
else
{
requirements.mode1 = 0;
requirements.mode2 = FR1_MODE;
}
break;
}
case s_fp32:
case s_fp32_fpxx:
case s_fp32_fpxxo:
case s_fp32_fpxxo_fpxx:
{
if (is_r6)
requirements.mode1 = FRE_MODE;
else
{
requirements.mode1 = 0;
requirements.mode2 = FRE_MODE;
}
break;
}
case s_fpxx:
case s_fpxxo:
case s_fpxxo_fpxx:
case s_any:
case s_soft:
{
if (is_r6)
{
requirements.mode1 = FR1_MODE;
requirements.mode2 = FRE_MODE;
}
else
{
requirements.mode1 = 0;
requirements.mode2 = FR1_MODE;
requirements.mode3 = FRE_MODE;
}
break;
}
case s_fp64a:
case s_fp64a_fpxx:
case s_fp64a_fpxxo:
case s_fp64a_fpxx_fpxxo:
{
requirements.mode1 = FR1_MODE;
requirements.mode2 = FRE_MODE;
break;
}
case s_fp64:
case s_fp64_fpxx:
case s_fp64_fpxxo:
case s_fp64_fpxx_fpxxo:
case s_fp64a_fp64:
case s_fp64a_fp64_fpxx:
case s_fp64a_fp64_fpxxo:
case s_fp64a_fp64_fpxxo_fpxx:
{
requirements.mode1 = FR1_MODE;
break;
}
case s_fp64a_fp32:
case s_fp32_fp64a_fpxx:
case s_fp32_fp64a_fpxxo:
case s_fp32_fp64a_fpxxo_fpxx:
{
requirements.mode1 = FRE_MODE;
break;
}
}
return requirements;
}
/* Check the current mode is suitable for the specified state. */
static bool
current_mode_valid_p (enum fp_state s)
{
struct fp_mode_req req = compute_fp_modes (s);
return (req.mode1 == current_fp_mode
|| req.mode2 == current_fp_mode
|| req.mode3 == current_fp_mode);
}
/* Run the state machine by adding a new object. */
static bool
set_next_fp_state (enum fp_obj obj)
{
cant_change_mode = false;
switch (current_fp_state)
{
START_STATE(soft)
NEXT(soft,soft)
NEXT(any,soft)
END_STATE
START_STATE(single)
NEXT(single,single)
NEXT(any,single)
END_STATE
START_STATE(any)
NEXT_REQ_FR0(fp32, fp32)
NEXT(fpxx, fpxx)
NEXT(fpxxo, fpxxo)
NEXT_REQ_FR1(fp64a, fp64a)
NEXT_REQ_FR1(fp64, fp64)
NEXT(any,any)
NEXT(soft,soft)
NEXT(single,single)
END_STATE
START_STATE(fp32)
NEXT_REQ_FR0(fp32,fp32)
NEXT(fpxx, fp32_fpxx)
NEXT(fpxxo, fp32_fpxxo)
NEXT_REQ_FRE(fp64a, fp64a_fp32)
NEXT(any,fp32)
END_STATE
START_STATE(fpxx)
NEXT_REQ_FR0(fp32, fp32_fpxx)
NEXT_REQ_FR1(fp64, fp64_fpxx)
NEXT_REQ_FR1(fp64a, fp64a_fpxx)
NEXT(fpxxo, fpxxo_fpxx)
NEXT(fpxx,fpxx)
NEXT(any,fpxx)
END_STATE
START_STATE(fpxxo)
NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo)
NEXT_NO_MODE_CHANGE(fp64, fp64_fpxxo)
NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(fpxx, fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxxo,fpxxo)
NEXT_NO_MODE_CHANGE(any,fpxxo)
END_STATE
START_STATE(fp64a)
NEXT_REQ_FRE(fp32, fp64a_fp32)
NEXT_REQ_FR1(fp64, fp64a_fp64)
NEXT(fpxxo, fp64a_fpxxo)
NEXT(fpxx, fp64a_fpxx)
NEXT_REQ_FR1(fp64a, fp64a)
NEXT(any, fp64a)
END_STATE
START_STATE(fp64)
NEXT_REQ_FR1(fp64a, fp64a_fp64)
NEXT(fpxxo, fp64_fpxxo)
NEXT(fpxx, fp64_fpxx)
NEXT_REQ_FR1(fp64, fp64)
NEXT(any, fp64)
END_STATE
START_STATE(fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp64, fp64_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fpxx, fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxxo, fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(any, fpxxo_fpxx)
END_STATE
START_STATE(fp32_fpxx)
NEXT_REQ_FR0(fp32, fp32_fpxx)
NEXT(fpxx, fp32_fpxx)
NEXT(fpxxo, fp32_fpxxo_fpxx)
NEXT_REQ_FRE(fp64a, fp32_fp64a_fpxx)
NEXT(any, fp32_fpxx)
END_STATE
START_STATE(fp32_fpxxo)
NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo)
NEXT_NO_MODE_CHANGE(fpxxo, fp32_fpxxo)
NEXT_NO_MODE_CHANGE(fpxx, fp32_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(any, fp32_fpxxo)
END_STATE
START_STATE(fp32_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp32, fp32_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxxo, fp32_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxx, fp32_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(any, fp32_fpxxo_fpxx)
END_STATE
START_STATE(fp64a_fp32)
NEXT_REQ_FRE(fp32, fp64a_fp32)
NEXT_REQ_FRE(fp64a, fp64a_fp32)
NEXT(fpxxo, fp32_fp64a_fpxxo)
NEXT(fpxx, fp32_fp64a_fpxx)
NEXT(any, fp64a_fp32)
END_STATE
START_STATE(fp64a_fpxx)
NEXT_REQ_FRE(fp32, fp32_fp64a_fpxx)
NEXT_REQ_FR1(fp64a, fp64a_fpxx)
NEXT(fpxx, fp64a_fpxx)
NEXT(fpxxo, fp64a_fpxx_fpxxo)
NEXT_REQ_FR1(fp64, fp64a_fp64_fpxx)
NEXT(any, fp64a_fpxx)
END_STATE
START_STATE(fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(fpxx, fp64a_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo)
NEXT_NO_MODE_CHANGE(any, fp64a_fpxxo)
END_STATE
START_STATE(fp64a_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp64a, fp64a_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fpxx, fp64a_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(any, fp64a_fpxx_fpxxo)
END_STATE
START_STATE(fp64_fpxx)
NEXT_REQ_FR1(fp64a, fp64a_fp64_fpxx)
NEXT(fpxxo, fp64_fpxx_fpxxo)
NEXT(fpxx, fp64_fpxx)
NEXT_REQ_FR1(fp64, fp64_fpxx)
NEXT(any, fp64_fpxx)
END_STATE
START_STATE(fp64_fpxxo)
NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo)
NEXT_NO_MODE_CHANGE(fpxxo, fp64_fpxxo)
NEXT_NO_MODE_CHANGE(fpxx, fp64_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fp64, fp64_fpxxo)
NEXT_NO_MODE_CHANGE(any, fp64_fpxxo)
END_STATE
START_STATE(fp64_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxxo, fp64_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fpxx, fp64_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(fp64, fp64_fpxx_fpxxo)
NEXT_NO_MODE_CHANGE(any, fp64_fpxx_fpxxo)
END_STATE
START_STATE(fp64a_fp64)
NEXT_REQ_FR1(fp64a, fp64a_fp64)
NEXT(fpxxo, fp64a_fp64_fpxxo)
NEXT(fpxx, fp64a_fp64_fpxx)
NEXT_REQ_FR1(fp64, fp64a_fp64)
NEXT(any, fp64a_fp64)
END_STATE
START_STATE(fp64a_fp64_fpxx)
NEXT_REQ_FR1(fp64a, fp64a_fp64_fpxx)
NEXT(fpxxo, fp64a_fp64_fpxxo_fpxx)
NEXT(fpxx, fp64a_fp64_fpxx)
NEXT_REQ_FR1(fp64, fp64a_fp64_fpxx)
NEXT(any, fp64a_fp64_fpxx)
END_STATE
START_STATE(fp64a_fp64_fpxxo)
NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo)
NEXT_NO_MODE_CHANGE(fpxx, fp64a_fp64_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fp64_fpxxo)
NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo)
NEXT_NO_MODE_CHANGE(any, fp64a_fp64_fpxxo)
END_STATE
START_STATE(fp64a_fp64_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp64a, fp64a_fp64_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxx, fp64a_fp64_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxxo, fp64a_fp64_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp64, fp64a_fp64_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(any, fp64a_fp64_fpxxo_fpxx)
END_STATE
START_STATE(fp32_fp64a_fpxx)
NEXT_REQ_FRE(fp32, fp32_fp64a_fpxx)
NEXT_REQ_FRE(fp64a, fp32_fp64a_fpxx)
NEXT(fpxxo, fp32_fp64a_fpxxo_fpxx)
NEXT(fpxx, fp32_fp64a_fpxx)
NEXT(any, fp32_fp64a_fpxx)
END_STATE
START_STATE(fp32_fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(fpxx, fp32_fp64a_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxxo, fp32_fp64a_fpxxo)
NEXT_NO_MODE_CHANGE(any, fp32_fp64a_fpxxo)
END_STATE
START_STATE(fp32_fp64a_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp32, fp32_fp64a_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fp64a, fp32_fp64a_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxx, fp32_fp64a_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(fpxxo, fp32_fp64a_fpxxo_fpxx)
NEXT_NO_MODE_CHANGE(any, fp32_fp64a_fpxxo_fpxx)
END_STATE
}
if (obj != o_max)
fp_obj_count[obj]++;
return true;
}
/* Run the state machine by removing an object. */
static bool
remove_object (enum fp_obj obj)
{
if (obj == o_max)
return false;
fp_obj_count[obj]--;
/* We can't change fp state until all the objects
of a particular type have been unloaded. */
if (fp_obj_count[obj] != 0)
return false;
switch (current_fp_state)
{
START_STATE(soft)
NEXT(soft,any)
END_STATE
START_STATE(single)
NEXT(single,any)
END_STATE
START_STATE(any)
NEXT(any,any)
END_STATE
START_STATE(fp32)
NEXT (fp32,any)
END_STATE
START_STATE(fpxx)
NEXT (fpxx,any)
END_STATE
START_STATE(fpxxo)
NEXT (fpxxo,any)
END_STATE
START_STATE(fp64a)
NEXT(fp64a, any)
END_STATE
START_STATE(fp64)
NEXT(fp64, any)
END_STATE
START_STATE(fpxxo_fpxx)
NEXT(fpxx, fpxxo)
NEXT(fpxxo, fpxx)
END_STATE
START_STATE(fp32_fpxx)
NEXT(fp32, fpxx)
NEXT(fpxx, fp32)
END_STATE
START_STATE(fp32_fpxxo)
NEXT(fp32, fpxxo)
NEXT(fpxxo, fp32)
END_STATE
START_STATE(fp32_fpxxo_fpxx)
NEXT(fp32, fpxxo_fpxx)
NEXT(fpxxo, fp32_fpxx)
NEXT(fpxx, fp32_fpxxo)
END_STATE
START_STATE(fp64a_fp32)
NEXT(fp32, fp64a)
NEXT(fp64a, fp32)
END_STATE
START_STATE(fp64a_fpxx)
NEXT(fp64a, fpxx)
NEXT(fpxx, fp64a)
END_STATE
START_STATE(fp64a_fpxxo)
NEXT(fp64a, fpxxo)
NEXT(fpxxo, fp64a)
END_STATE
START_STATE(fp64a_fpxx_fpxxo)
NEXT(fp64a, fpxxo_fpxx)
NEXT(fpxx, fp64a_fpxxo)
NEXT(fpxxo, fp64a_fpxx)
END_STATE
START_STATE(fp64_fpxx)
NEXT(fpxx, fp64)
NEXT(fp64, fpxx)
END_STATE
START_STATE(fp64_fpxxo)
NEXT(fpxxo, fp64)
NEXT(fp64, fpxxo)
END_STATE
START_STATE(fp64_fpxx_fpxxo)
NEXT(fp64, fpxxo_fpxx)
NEXT(fpxxo, fp64_fpxx)
NEXT(fpxx, fp64_fpxxo)
END_STATE
START_STATE(fp64a_fp64)
NEXT(fp64a, fp64)
NEXT(fp64, fp64a)
END_STATE
START_STATE(fp64a_fp64_fpxx)
NEXT(fp64a, fp64_fpxx)
NEXT(fpxx, fp64a_fp64)
NEXT(fp64, fp64a_fpxx)
END_STATE
START_STATE(fp64a_fp64_fpxxo)
NEXT(fp64a, fp64_fpxxo)
NEXT(fpxxo, fp64a_fp64)
NEXT(fp64, fp64a_fpxxo)
END_STATE
START_STATE(fp64a_fp64_fpxxo_fpxx)
NEXT(fp64a, fp64_fpxx_fpxxo)
NEXT(fpxx, fp64a_fp64_fpxxo)
NEXT(fpxxo, fp64a_fp64_fpxx)
NEXT(fp64, fp64a_fpxx_fpxxo)
END_STATE
START_STATE(fp32_fp64a_fpxx)
NEXT(fp32, fp64a_fpxx)
NEXT(fp64a, fp32_fpxx)
NEXT(fpxx, fp64a_fp32)
END_STATE
START_STATE(fp32_fp64a_fpxxo)
NEXT(fp32, fp64a_fpxxo)
NEXT(fp64a, fp32_fpxxo)
NEXT(fpxxo, fp64a_fp32)
END_STATE
START_STATE(fp32_fp64a_fpxxo_fpxx)
NEXT(fp32, fp64a_fpxx_fpxxo)
NEXT(fp64a, fp32_fpxxo_fpxx)
NEXT(fpxx, fp32_fp64a_fpxxo)
NEXT(fpxxo, fp32_fp64a_fpxx)
END_STATE
}
return true;
}
static int
mode_transition_valid_p (void)
{
int prev_fp_mode;
/* Get the current fp mode. */
prev_fp_mode = current_fp_mode;
#if HAVE_PRCTL_FP_MODE
current_fp_mode = prctl (PR_GET_FP_MODE);
/* If the prctl call fails assume the core only has FR0 mode support. */
if (current_fp_mode == -1)
current_fp_mode = 0;
#endif
if (!current_mode_valid_p (current_fp_state))
return 0;
/* Check if mode changes are not allowed but a mode change happened. */
if (cant_change_mode
&& current_fp_mode != prev_fp_mode)
return 0;
return 1;
}
/* Load OBJ and check that it was/was not loaded correctly. */
bool
load_object (enum fp_obj obj)
{
bool should_load = set_next_fp_state (obj);
shared_lib_ptrs[obj] = dlopen (shared_lib_names[obj], RTLD_LAZY);
/* If we expected an error and the load was successful then fail. */
if (!should_load && (shared_lib_ptrs[obj] != 0))
return false;
if (should_load && (shared_lib_ptrs[obj] == 0))
return false;
if (!mode_transition_valid_p ())
return false;
return true;
}
/* Remove an object and check the state remains valid. */
bool
unload_object (enum fp_obj obj)
{
if (!shared_lib_ptrs[obj])
return true;
remove_object (obj);
if (dlclose (shared_lib_ptrs[obj]) != 0)
return false;
shared_lib_ptrs[obj] = 0;
if (!mode_transition_valid_p ())
return false;
return true;
}
/* Load every permuation of OBJECTS. */
static bool
test_permutations (enum fp_obj objects[], int count)
{
int i;
for (i = 0 ; i < count ; i++)
{
if (!load_object (objects[i]))
return false;
if (count > 1)
{
enum fp_obj new_objects[count - 1];
int j;
int k = 0;
for (j = 0 ; j < count ; j++)
{
if (j != i)
new_objects[k++] = objects[j];
}
if (!test_permutations (new_objects, count - 1))
return false;
}
if (!unload_object (objects[i]))
return false;
}
return true;
}
int
do_test (void)
{
#if HAVE_PRCTL_FP_MODE
/* Determine available hardware support and current mode. */
current_fp_mode = prctl (PR_GET_FP_MODE);
/* If the prctl call fails assume the core only has FR0 mode support. */
if (current_fp_mode == -1)
current_fp_mode = 0;
else
{
if (prctl (PR_SET_FP_MODE, 0) != 0)
{
if (errno == ENOTSUP)
is_r6 = true;
else
{
printf ("unexpected error from PR_SET_FP_MODE, 0: %m\n");
return 1;
}
}
if (prctl (PR_SET_FP_MODE, PR_FP_MODE_FR) != 0)
{
if (errno != ENOTSUP)
{
printf ("unexpected error from PR_SET_FP_MODE, "
"PR_FP_MODE_FR: %m\n");
return 1;
}
}
else
has_fr1 = true;
if (prctl (PR_SET_FP_MODE, PR_FP_MODE_FR | PR_FP_MODE_FRE) != 0)
{
if (errno != ENOTSUP)
{
printf ("unexpected error from PR_SET_FP_MODE, "
"PR_FP_MODE_FR | PR_FP_MODE_FRE: %m\n");
return 1;
}
}
else
has_fre = true;
if (prctl (PR_SET_FP_MODE, current_fp_mode) != 0)
{
printf ("unable to restore initial FP mode: %m\n");
return 1;
}
}
if ((is_r6 && !(current_fp_mode & PR_FP_MODE_FR))
|| (!has_fr1 && (current_fp_mode & PR_FP_MODE_FR))
|| (!has_fre && (current_fp_mode & PR_FP_MODE_FRE)))
{
puts ("Inconsistency detected between initial FP mode "
"and supported FP modes\n");
return 1;
}
#else
current_fp_mode = 0;
#endif
/* Set up the initial state from executable and LDSO. Assumptions:
1) All system libraries have the same ABI as ld.so.
2) Due to the fact that ld.so is tested by invoking it directly
rather than via an interpreter, there is no point in varying
the ABI of the test program. Instead the ABI only varies for
the shared libraries which get loaded. */
if (!set_next_fp_state (FPABI_NATIVE))
{
puts ("Unable to enter initial ABI state\n");
return 1;
}
/* Compare the computed state with the hardware state. */
if (!mode_transition_valid_p ())
return 1;
/* Run all possible test permutations. */
if (!test_permutations (test_objects, FPABI_COUNT))
{
puts ("Mode checks failed\n");
return 1;
}
return 0;
}
#define TEST_FUNCTION do_test ()
#include "../../test-skeleton.c"

View File

@ -0,0 +1,123 @@
/* 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/>. */
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/prctl.h>
#if __mips_fpr != 0 || _MIPS_SPFPSET != 16
# error This test requires -mfpxx -mno-odd-spreg
#endif
/* This test verifies that mode changes do not clobber register state
in other threads. */
static volatile int finished;
static int mode[6] =
{
0,
PR_FP_MODE_FR,
PR_FP_MODE_FR | PR_FP_MODE_FRE,
PR_FP_MODE_FR,
0,
PR_FP_MODE_FR | PR_FP_MODE_FRE
};
static void *
thread_function (void * arg __attribute__ ((unused)))
{
volatile int i = 0;
volatile float f = 0.0;
volatile double d = 0.0;
while (!finished)
{
if ((float) i != f || (double) i != d)
{
printf ("unexpected value: i(%d) f(%f) d(%f)\n", i, f, d);
exit (1);
}
if (i == 100)
{
i = 0;
f = 0.0;
d = 0.0;
}
i++;
f++;
d++;
}
return NULL;
}
int
main (void)
{
int count = sysconf (_SC_NPROCESSORS_ONLN);
if (count <= 0)
count = 1;
count *= 4;
pthread_t th[count];
int i;
int result = 0;
for (i = 0; i < count; ++i)
if (pthread_create (&th[i], NULL, thread_function, 0) != 0)
{
printf ("creation of thread %d failed\n", i);
exit (1);
}
for (i = 0 ; i < 1000000 ; i++)
{
if (prctl (PR_SET_FP_MODE, mode[i % 6]) != 0
&& errno != ENOTSUP)
{
printf ("prctl PR_SET_FP_MODE failed: %m\n");
exit (1);
}
}
finished = 1;
for (i = 0; i < count; ++i)
{
void *v;
if (pthread_join (th[i], &v) != 0)
{
printf ("join of thread %d failed\n", i);
result = 1;
}
else if (v != NULL)
{
printf ("join %d successful, but child failed\n", i);
result = 1;
}
else
printf ("join %d successful\n", i);
}
return result;
}

View File

@ -0,0 +1,163 @@
/* 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/>. */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <pthread.h>
#include <sys/prctl.h>
#if __mips_fpr != 0 || _MIPS_SPFPSET != 16
# error This test requires -mfpxx -mno-odd-spreg
#endif
/* This test verifies that all threads in a process see a mode
change when any thread causes a mode change. */
static int mode[6] =
{
0,
PR_FP_MODE_FR,
PR_FP_MODE_FR | PR_FP_MODE_FRE,
PR_FP_MODE_FR,
0,
PR_FP_MODE_FR | PR_FP_MODE_FRE
};
static volatile int current_mode;
static volatile int finished;
static pthread_barrier_t barr_ready;
static pthread_barrier_t barr_cont;
static void *
thread_function (void * arg __attribute__ ((unused)))
{
while (!finished)
{
int res = pthread_barrier_wait (&barr_ready);
if (res != 0 && res != PTHREAD_BARRIER_SERIAL_THREAD)
{
printf ("barrier wait failed: %m\n");
exit (1);
}
int mode = prctl (PR_GET_FP_MODE);
if (mode != current_mode)
{
printf ("unexpected mode: %d != %d\n", mode, current_mode);
exit (1);
}
res = pthread_barrier_wait (&barr_cont);
if (res != 0 && res != PTHREAD_BARRIER_SERIAL_THREAD)
{
printf ("barrier wait failed: %m\n");
exit (1);
}
}
return NULL;
}
int
main (void)
{
int count = sysconf (_SC_NPROCESSORS_ONLN);
if (count <= 0)
count = 1;
count *= 4;
pthread_t th[count];
int i;
int result = 0;
if (pthread_barrier_init (&barr_ready, NULL, count + 1) != 0)
{
printf ("failed to initialize barrier: %m\n");
exit (1);
}
if (pthread_barrier_init (&barr_cont, NULL, count + 1) != 0)
{
printf ("failed to initialize barrier: %m\n");
exit (1);
}
for (i = 0; i < count; ++i)
if (pthread_create (&th[i], NULL, thread_function, 0) != 0)
{
printf ("creation of thread %d failed\n", i);
exit (1);
}
for (i = 0 ; i < 7 ; i++)
{
if (prctl (PR_SET_FP_MODE, mode[i % 6]) != 0)
{
if (errno != ENOTSUP)
{
printf ("prctl PR_SET_FP_MODE failed: %m");
exit (1);
}
}
else
current_mode = mode[i % 6];
int res = pthread_barrier_wait (&barr_ready);
if (res != 0 && res != PTHREAD_BARRIER_SERIAL_THREAD)
{
printf ("barrier wait failed: %m\n");
exit (1);
}
if (i == 6)
finished = 1;
res = pthread_barrier_wait (&barr_cont);
if (res != 0 && res != PTHREAD_BARRIER_SERIAL_THREAD)
{
printf ("barrier wait failed: %m\n");
exit (1);
}
}
for (i = 0; i < count; ++i)
{
void *v;
if (pthread_join (th[i], &v) != 0)
{
printf ("join of thread %d failed\n", i);
result = 1;
}
else if (v != NULL)
{
printf ("join %d successful, but child failed\n", i);
result = 1;
}
else
printf ("join %d successful\n", i);
}
return result;
}

View File

@ -0,0 +1,90 @@
/* 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/>. */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <setjmp.h>
#include <sys/prctl.h>
#if __mips_fpr != 0 || _MIPS_SPFPSET != 16
# error This test requires -mfpxx -mno-odd-spreg
#endif
/* This test verifies that mode changes between a setjmp and longjmp do
not corrupt the state of callee-saved registers. */
static int mode[6] =
{
0,
PR_FP_MODE_FR,
PR_FP_MODE_FR | PR_FP_MODE_FRE,
PR_FP_MODE_FR,
0,
PR_FP_MODE_FR | PR_FP_MODE_FRE
};
static jmp_buf env;
float check1 = 2.0;
double check2 = 3.0;
int
main (void)
{
int i;
int result = 0;
for (i = 0 ; i < 7 ; i++)
{
int retval;
register float test1 __asm ("$f20");
register double test2 __asm ("$f22");
/* Hide what we are doing to $f20 and $f22 from the compiler. */
__asm __volatile ("l.s %0,%2\n"
"l.d %1,%3\n"
: "=f" (test1), "=f" (test2)
: "m" (check1), "m" (check2));
retval = setjmp (env);
/* Make sure the compiler knows we want to access the variables
via the named registers again. */
__asm __volatile ("" : : "f" (test1), "f" (test2));
if (test1 != check1 || test2 != check2)
{
printf ("Corrupt register detected: $20 %f = %f, $22 %f = %f\n",
test1, check1, test2, check2);
result = 1;
}
if (retval == 0)
{
if (prctl (PR_SET_FP_MODE, mode[i % 6]) != 0
&& errno != ENOTSUP)
{
printf ("prctl PR_SET_FP_MODE failed: %m");
exit (1);
}
longjmp (env, 0);
}
}
return result;
}

View File

@ -105,6 +105,148 @@ 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
libc_mips_o32_fp=
if test x"$libc_mips_abi" = xo32 -a x"$libc_mips_float" = xhard; then
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if !defined(__mips_fpr)
#error Missing FPR sizes
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if (__mips_fpr != 32)
#error Not FP32
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
libc_mips_o32_fp=32
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if (__mips_fpr != 0) || !defined(_MIPS_SPFPSET) || (_MIPS_SPFPSET != 16)
#error Not FPXX (without odd single-precision registers)
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
libc_mips_o32_fp=xx
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if (__mips_fpr != 0)
#error Not FPXX (with odd single precision registers)
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
libc_mips_o32_fp=xxo
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if (__mips_fpr != 64) || !defined(_MIPS_SPFPSET) || (_MIPS_SPFPSET != 16)
#error Not FP64A
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
libc_mips_o32_fp=64a
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if (__mips_fpr != 64)
#error Not FP64
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
libc_mips_o32_fp=64
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
config_vars="$config_vars
o32-fpabi = ${libc_mips_o32_fp}"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <linux/prctl.h>
#if !defined(PR_GET_FP_MODE) || !defined(PR_SET_FP_MODE)
#error New prctl support for setting FP modes not found
#endif
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
libc_mips_mode_switch=yes
else
libc_mips_mode_switch=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
config_vars="$config_vars
mips-mode-switch = ${libc_mips_mode_switch}"
{ $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; }

View File

@ -44,6 +44,59 @@ 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_mips_o32_fp=
if test x"$libc_mips_abi" = xo32 -a x"$libc_mips_float" = xhard; then
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
#if !defined(__mips_fpr)
#error Missing FPR sizes
#endif])],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
#if (__mips_fpr != 32)
#error Not FP32
#endif])],
[libc_mips_o32_fp=32],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
#if (__mips_fpr != 0) || !defined(_MIPS_SPFPSET) || (_MIPS_SPFPSET != 16)
#error Not FPXX (without odd single-precision registers)
#endif])],
[libc_mips_o32_fp=xx],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
#if (__mips_fpr != 0)
#error Not FPXX (with odd single precision registers)
#endif])],
[libc_mips_o32_fp=xxo],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
#if (__mips_fpr != 64) || !defined(_MIPS_SPFPSET) || (_MIPS_SPFPSET != 16)
#error Not FP64A
#endif])],
[libc_mips_o32_fp=64a],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
#if (__mips_fpr != 64)
#error Not FP64
#endif])],
[libc_mips_o32_fp=64],
[])])])])])],
[])
fi
LIBC_CONFIG_VAR([o32-fpabi],[${libc_mips_o32_fp}])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
#include <linux/prctl.h>
#if !defined(PR_GET_FP_MODE) || !defined(PR_SET_FP_MODE)
#error New prctl support for setting FP modes not found
#endif])],
[libc_mips_mode_switch=yes],
[libc_mips_mode_switch=no])
LIBC_CONFIG_VAR([mips-mode-switch],[${libc_mips_mode_switch}])
AC_CACHE_CHECK([whether the compiler is using the 2008 NaN encoding],
libc_cv_mips_nan2008, [AC_EGREP_CPP(yes, [dnl
#ifdef __mips_nan2008

View File

@ -34,7 +34,7 @@ extern void _dl_static_init (struct link_map *map);
#undef VALID_ELF_ABIVERSION
#define VALID_ELF_ABIVERSION(osabi,ver) \
(ver == 0 \
|| (osabi == ELFOSABI_SYSV && ver < 2) \
|| (osabi == ELFOSABI_SYSV && ver < 4) \
|| (osabi == ELFOSABI_GNU && ver < LIBC_ABI_MAX))
#endif /* ldsodefs.h */

View File

@ -11,3 +11,6 @@ MIPS_PLT mips*-*-linux*
# Unique symbol definitions for C++.
# Architecture independent, all ELF targets (== all targets)
UNIQUE
#
# MIPS O32 FP64
MIPS_O32_FP64 mips*-*-linux*