This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [RFC, PATCH, MIPS] Add support for O32 FPXX and program header based ABI information
- From: Will Newton <will dot newton at linaro dot org>
- To: Matthew Fortune <Matthew dot Fortune at imgtec dot com>
- Cc: "Joseph Myers (joseph at codesourcery dot com)" <joseph at codesourcery dot com>, Richard Sandiford <rdsandiford at googlemail dot com>, Rich Fuhler <Rich dot Fuhler at imgtec dot com>, "macro at codesourcery dot com" <macro at codesourcery dot com>, "libc-alpha at sourceware dot org" <libc-alpha at sourceware dot org>
- Date: Fri, 2 May 2014 09:11:36 +0100
- Subject: Re: [RFC, PATCH, MIPS] Add support for O32 FPXX and program header based ABI information
- Authentication-results: sourceware.org; auth=none
- References: <6D39441BF12EF246A7ABCE6654B0235351E3D7 at LEMAIL01 dot le dot imgtec dot org>
On 1 May 2014 22:48, Matthew Fortune <Matthew.Fortune@imgtec.com> wrote:
Hi Matthew,
> Attached is an initial patch to support the O32 FPXX ABI as described here:
>
> https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
>
> This has been discussed at length on GCC and binutils mailing lists and has
> approval in principle from MIPS kernel developers at Imagination.
>
> The proposed ABI was initially reviewed/discussed on the GCC mailing
> list starting from the following posts:
>
> http://gcc.gnu.org/ml/gcc/2014-02/msg00415.html
> http://gcc.gnu.org/ml/gcc/2014-03/msg00191.html
>
> Then refined up to the current spec on binutils with the latest patch here.
>
> http://sourceware.org/ml/binutils/2014-05/msg00002.html
>
> To implement this feature I need an additional hook during the loading of
> objects to allow a target to inspect the headers (and segments they point
> at) to decide if the library is compatible or not. I have made a simple
> attempt at this but am quite willing to adapt to better suggestions.
>
> The current implementation tracks the individual ABI requirements of each
> loaded module and caches the information so that program headers are only
> inspected once per library. This provides the greatest control but could
> theoretically be reduced to simply recording the current state of a process
> with a single global value. Since this is an implementation detail this too
> is open to debate.
>
> I think I need to do something relating to caching objects but quite
> honestly have no idea on that front. I've used the work from maciej on
> NAN2008 handling as a reference for the areas I need to modify for this
> implementation but haven't figured that part out.
>
> I'm also not entirely sure how to go about writing tests for this in glibc
> but will look through the test framework to see if anything is possible. I
> have attached a basic test that allows all combinations of O32 FP32,
> O32 FPXX and O32 FP64 modules to be loaded and tested manually. I have a
> hacked patch for qemu to read the new PT_MIPS_ABIFLAGS which I have been
> using to test this; I can make that available but will need to rebase to
> a public qemu release.
>
> The corresponding patch to implement O32 FPXX in GCC will hopefully be
> posted tomorrow.
>
> Regards,
> Matthew
>
> 2014-05-01 Matthew Fortune <matthew.fortune@imgtec.com>
>
> * config.h/in (HAVE_MIPS_MODULE_FPXX_DIRECTIVE): Undefine.
> * elf/dl-load.c (open_verify): Add optional hook for phdr check.
> * elf/elf.h (PT_MIPS_ABIFLAGS): Define.
> (Elf_ABIFlags_v0): New structure.
> (AFL_REG_NONE, AFL_REG_32, AFL_REG_64, AFL_REG_128): Define.
> (AFL_ASE_DSP, AFL_ASE_DSP64, AFL_ASE_DSPR2, AFL_ASE_EVA): Likewise.
> (AFL_ASE_MCU, AFL_ASE_MDMX, AFL_ASE_MIPS3D, AFL_ASE_MT): Likewise.
> (AFL_ASE_SMARTMIPS, AFL_ASE_VIRT, AFL_ASE_VIRT64, AFL_ASE_MSA): Likewise.
> (AFL_ASE_MSA64, AFL_ASE_MIPS16, AFL_ASE_MICROMIPS): Likewise.
> (AFL_EXT_XLR, AFL_EXT_OCTEON2, AFL_EXT_OCTEONP): Likewise.
> (AFL_EXT_LOONGSON_3A, AFL_EXT_OCTEON, AFL_EXT_5900): Likewise.
> (AFL_EXT_4010, AFL_EXT_4100, AFL_EXT_3900, AFL_EXT_10000): Likewise.
> (AFL_EXT_SB1, AFL_EXT_4111, AFL_EXT_4120, AFL_EXT_5400): Likewise.
> (AFL_EXT_5500, AFL_EXT_LOONGSON_2E, 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): Likewise.
> * sysdeps/mips/bits/hwcap.h: New file.
> * sysdeps/mips/bits/linkmap.h (struct link_map_machine): Add fpmode
> field.
> * sysdeps/mips/dl-machine.h: Include unistd.h.
> (ELF_MACHINE_NEEDS_PHDR_CHECK): Define.
> (find_mips_abiflags): New static inline function.
> (switch_frmode_to): New static no-inline function.
> (mips_fp_abi, elf_machine_phdr_check): new static function.
> * sysdeps/mips/dl-procinfo.c (_dl_mips_cap_flags): Declare.
> * sysdeps/mips/dl-procinfo.h (_DL_HWCAP_COUNT): Define.
> (HWCAP_IMPORTANT): Define.
> (_dl_procinfo): New static inline function.
> (_dl_hwcap_string, _dl_string_hwcap): Likewise.
> * sysdeps/unix/mips/sysdep.h (_SYS_AUXV_H): Define.
> (bits/hwcap.h): Include.
> * sysdeps/unix/sysv/linux/mips/configure.ac: Check for .module fpxx
> (HAVE_MIPS_MODULE_FPXX_DIRECTIVE): Define.
> * sysdeps/unix/sysv/linux/mips/configure: Regenerate.
> * sysdeps/unix/sysv/linux/mips/getcontext.S
> (HAVE_MIPS_MODULE_FPXX_DIRECTIVE): Use.
> * sysdeps/unix/sysv/linux/mips/setcontext.S: Likewise.
> * sysdeps/unix/sysv/linux/mips/swapcontext.S: Likewise.
> ---
> config.h.in | 6 +-
> elf/dl-load.c | 7 +
> elf/elf.h | 97 ++++++++++++-
> sysdeps/mips/bits/hwcap.h | 23 +++
> sysdeps/mips/bits/linkmap.h | 1 +
> sysdeps/mips/dl-machine.h | 218 ++++++++++++++++++++++++++++
> sysdeps/mips/dl-procinfo.c | 16 ++
> sysdeps/mips/dl-procinfo.h | 50 +++++-
> sysdeps/unix/mips/sysdep.h | 3 +
> sysdeps/unix/sysv/linux/mips/configure | 27 ++++
> sysdeps/unix/sysv/linux/mips/configure.ac | 15 ++
> sysdeps/unix/sysv/linux/mips/getcontext.S | 4 +
> sysdeps/unix/sysv/linux/mips/setcontext.S | 4 +
> sysdeps/unix/sysv/linux/mips/swapcontext.S | 4 +
> 14 files changed, 462 insertions(+), 13 deletions(-)
> create mode 100644 sysdeps/mips/bits/hwcap.h
>
> diff --git a/config.h.in b/config.h.in
> index 40797e7..05da98a 100644
> --- a/config.h.in
> +++ b/config.h.in
> @@ -241,8 +241,12 @@
> /* The pt_chown binary is being built and used by grantpt. */
> #undef HAVE_PT_CHOWN
>
> -/* ports/sysdeps/mips/configure.in */
> +/* sysdeps/mips/configure.in */
> /* Define if using the IEEE 754-2008 NaN encoding on the MIPS target. */
> #undef HAVE_MIPS_NAN2008
>
> +/* sysdeps/unix/sysv/linux/mips/configure.in */
> +/* Define if the assembler supports the .module fp=xx directive. */
> +#undef HAVE_MIPS_MODULE_FPXX_DIRECTIVE
> +
> #endif
> diff --git a/elf/dl-load.c b/elf/dl-load.c
> index 6501ff2..43aacdc 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -1866,6 +1866,13 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
> }
> }
>
> +#ifdef ELF_MACHINE_NEEDS_PHDR_CHECK
> + if (!__builtin_expect (
> + elf_machine_phdr_check (phdr, ehdr->e_phnum, fbp->buf, fbp->len,
> + fd, loader), 1))
> + goto close_and_out;
> +#endif
> +
> /* Check .note.ABI-tag if present. */
> for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
> if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
> diff --git a/elf/elf.h b/elf/elf.h
> index 40e87b2..dccdee9 100644
> --- a/elf/elf.h
> +++ b/elf/elf.h
> @@ -1631,9 +1631,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 +1756,96 @@ 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;
> + /* Mask of processor-specific extensions. */
> + Elf32_Word isa_ext;
> + /* Mask of ASEs used. */
> + Elf32_Word ases;
> + /* Mask of general flags. */
> + Elf32_Word flags1;
> + Elf32_Word flags2;
> +} Elf_ABIFlags_v0;
> +
> +/* Values for the register size bytes of an abi flags structure. */
> +
> +#define AFL_REG_NONE 0x00 /* No registers. */
> +#define AFL_REG_32 0x01 /* 32-bit registers. */
> +#define AFL_REG_64 0x02 /* 64-bit registers. */
> +#define AFL_REG_128 0x03 /* 128-bit registers. */
> +
> +/* Masks for the ases word of an ABI flags structure. */
> +
> +#define AFL_ASE_DSP 0x00000001 /* DSP ASE. */
> +#define AFL_ASE_DSP64 0x00000002 /* DSP ASE (64-bit). */
> +#define AFL_ASE_DSPR2 0x00000004 /* DSP R2 ASE. */
> +#define AFL_ASE_EVA 0x00000008 /* Enhanced VA Scheme. */
> +#define AFL_ASE_MCU 0x00000010 /* MCU (MicroController) ASE. */
> +#define AFL_ASE_MDMX 0x00000020 /* MDMX ASE. */
> +#define AFL_ASE_MIPS3D 0x00000040 /* MIPS-3D ASE. */
> +#define AFL_ASE_MT 0x00000080 /* MT ASE. */
> +#define AFL_ASE_SMARTMIPS 0x00000100 /* SmartMIPS ASE. */
> +#define AFL_ASE_VIRT 0x00000200 /* VZ ASE. */
> +#define AFL_ASE_VIRT64 0x00000400 /* VZ ASE (64-bit). */
> +#define AFL_ASE_MSA 0x00000800 /* MSA ASE. */
> +#define AFL_ASE_MSA64 0x00001000 /* MSA ASE (64-bit). */
> +#define AFL_ASE_MIPS16 0x00002000 /* MIPS16 ASE. */
> +#define AFL_ASE_MICROMIPS 0x00004000 /* MICROMIPS ASE. */
> +#define AFL_ASE_XPA 0x00002000 /* XPA ASE. */
> +
> +/* Masks for the isa_ext word of an ABI flags structure. */
> +
> +#define AFL_EXT_XLR 0x00000020 /* RMI Xlr instruction. */
> +#define AFL_EXT_OCTEON2 0x00000100 /* Cavium Networks Octeon2. */
> +#define AFL_EXT_OCTEONP 0x00000200 /* Cavium Networks OcteonP. */
> +#define AFL_EXT_LOONGSON_3A 0x00000400 /* Loongson 3A. */
> +#define AFL_EXT_OCTEON 0x00000800 /* Cavium Networks Octeon. */
> +#define AFL_EXT_5900 0x00004000 /* MIPS R5900 instruction. */
> +#define AFL_EXT_4650 0x00010000 /* MIPS R4650 instruction. */
> +#define AFL_EXT_4010 0x00020000 /* LSI R4010 instruction. */
> +#define AFL_EXT_4100 0x00040000 /* NEC VR4100 instruction. */
> +#define AFL_EXT_3900 0x00080000 /* Toshiba R3900 instruction. */
> +#define AFL_EXT_10000 0x00100000 /* MIPS R10000 instruction. */
> +#define AFL_EXT_SB1 0x00200000 /* Broadcom SB-1 instruction. */
> +#define AFL_EXT_4111 0x00400000 /* NEC VR4111/VR4181 instruction. */
> +#define AFL_EXT_4120 0x00800000 /* NEC VR4120 instruction. */
> +#define AFL_EXT_5400 0x01000000 /* NEC VR5400 instruction. */
> +#define AFL_EXT_5500 0x02000000 /* NEC VR5500 instruction. */
> +#define AFL_EXT_LOONGSON_2E 0x40000000 /* ST Micro Loongson 2E. */
> +#define AFL_EXT_LOONGSON_2F 0x80000000 /* ST Micro Loongson 2F. */
> +
> +/* 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
> +};
>
> /* HPPA specific definitions. */
>
> diff --git a/sysdeps/mips/bits/hwcap.h b/sysdeps/mips/bits/hwcap.h
> new file mode 100644
> index 0000000..96575d2
> --- /dev/null
> +++ b/sysdeps/mips/bits/hwcap.h
> @@ -0,0 +1,23 @@
> +/* Defines for bits in AT_HWCAP.
> + 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 _SYS_AUXV_H
> +# error "Never include <bits/hwcap.h> directly; use <sys/auxv.h> instead."
> +#endif
> +
> +#define HWCAP_MIPS_UFR 0x00000001
> diff --git a/sysdeps/mips/bits/linkmap.h b/sysdeps/mips/bits/linkmap.h
> index a6df782..dfbc3be 100644
> --- a/sysdeps/mips/bits/linkmap.h
> +++ b/sysdeps/mips/bits/linkmap.h
> @@ -1,4 +1,5 @@
> struct link_map_machine
> {
> ElfW(Addr) plt; /* Address of .plt */
> + ElfW(Word) fpmode; /* Overall FP mode */
> };
> diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h
> index 5a07c0b..b10c228 100644
> --- a/sysdeps/mips/dl-machine.h
> +++ b/sysdeps/mips/dl-machine.h
> @@ -32,6 +32,7 @@
> #include <sgidefs.h>
> #include <sys/asm.h>
> #include <dl-tls.h>
> +#include <unistd.h>
>
> /* The offset of gp from GOT might be system-dependent. It's set by
> ld. The same value is also */
> @@ -107,6 +108,223 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
> }
> }
>
> +#define ELF_MACHINE_NEEDS_PHDR_CHECK
> +
> +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;
> +}
> +
> +#if _MIPS_SIM == _ABIO32
> +/* Modify the mode of the floating-point registers. This function must not
> + be inlined as it relies on the calling-convention to only need to save
> + restore the callee-saved registers around the mode switch. */
> +
> +static __attribute__ ((noinline)) void
> +switch_frmode_to (int newmode)
> +{
> + asm volatile
> + ("addu $sp, $sp, -48\n"
> + "sdc1 $f20, 0($sp)\n"
> + "sdc1 $f22, 8($sp)\n"
> + "sdc1 $f24, 16($sp)\n"
> + "sdc1 $f26, 24($sp)\n"
> + "sdc1 $f28, 32($sp)\n"
> + "sdc1 $f30, 40($sp)\n"
> + "beq %0, $0, 1f\n"
> + "ctc1 $0, $4\n"
> + "b 2f\n"
> + "1:\n"
> + "ctc1 $0, $1\n"
> + "2:\n"
> + "ldc1 $f20, 0($sp)\n"
> + "ldc1 $f22, 8($sp)\n"
> + "ldc1 $f24, 16($sp)\n"
> + "ldc1 $f26, 24($sp)\n"
> + "ldc1 $f28, 32($sp)\n"
> + "ldc1 $f30, 40($sp)\n"
> + "addu $sp, $sp, -48\n" :: "r"(newmode));
> +}
> +#endif
> +
> +static const char *
> +mips_fp_abi (int val)
> +{
> + switch (val)
> + {
> + case Val_GNU_MIPS_ABI_FP_ANY:
> + return "no float";
> + case Val_GNU_MIPS_ABI_FP_DOUBLE:
> + return "Hard float (DP)";
> + case Val_GNU_MIPS_ABI_FP_SINGLE:
> + return "Hard float (SP)";
> + 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)";
> + default:
> + return "Unknown FP ABI";
> + }
> +}
> +
> +static int __attribute_used__
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> + char * buf, int len, int fd, struct link_map * map)
> +{
> + const ElfW(Phdr) *ph = find_mips_abiflags (phdr, phnum);
> + struct link_map *l;
> + Lmid_t nsid;
> + int req_abi = Val_GNU_MIPS_ABI_FP_DOUBLE;
> + Elf_ABIFlags_v0 *mips_abiflags = NULL;
> +
> + /* Read the attributes section. */
> + if (ph != NULL)
> + {
> + ElfW(Addr) size = ph->p_filesz;
> +
> + if (ph->p_offset + size <= (size_t) len)
> + mips_abiflags = (Elf_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)
> + {
> + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
> + _dl_debug_printf (" Unable to read PT_MIPS_ABIFLAGS\n");
> + return 0;
> + }
> + }
> + if (size < sizeof (Elf_ABIFlags_v0))
> + {
> + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
> + _dl_debug_printf (" contains malformed PT_MIPS_ABIFLAGS\n");
> + return 0;
> + }
> + req_abi = mips_abiflags->fp_abi;
> + }
> +
> + /* ANY is compatible with anything. */
> + if (req_abi == Val_GNU_MIPS_ABI_FP_ANY)
> + return 1;
> +
> + /* Check that the new mode 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)
> + {
> + bool success = true;
> + if (l->l_mach.fpmode == 0)
> + {
> + l->l_mach.fpmode = Val_GNU_MIPS_ABI_FP_DOUBLE;
> + ph = find_mips_abiflags (l->l_phdr, l->l_phnum);
> + if (ph)
> + {
> + if (ph->p_filesz < sizeof (Elf_ABIFlags_v0))
> + {
> + if (__builtin_expect (GLRO(dl_debug_mask)
> + & DL_DEBUG_LIBS, 0))
> + _dl_debug_printf (" malformed PT_MIPS_ABIFLAGS found\n");
> + return 0;
> + }
> +
> + mips_abiflags = (Elf_ABIFlags_v0 *) (l->l_addr + ph->p_vaddr);
> + l->l_mach.fpmode = mips_abiflags->fp_abi;
> + }
> + }
> + switch (req_abi)
> + {
> + case Val_GNU_MIPS_ABI_FP_ANY:
> + /* Can't happen, see above. */
> + break;
> + case Val_GNU_MIPS_ABI_FP_DOUBLE:
> + if (l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_DOUBLE
> +#if _MIPS_SIM == _ABIO32
> + && l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_XX
> +#endif
> + && l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_ANY)
> + success = false;
> + break;
> + case Val_GNU_MIPS_ABI_FP_SINGLE:
> + if (l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_SINGLE
> + && l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_ANY)
> + success = false;
> + break;
> + case Val_GNU_MIPS_ABI_FP_SOFT:
> + if (l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_SOFT
> + && l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_ANY)
> + success = false;
> + break;
> +#if _MIPS_SIM == _ABIO32
> + case Val_GNU_MIPS_ABI_FP_XX:
> + if (l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_XX
> + && l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_DOUBLE
> + && l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_64
> + && l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_ANY)
> + success = false;
> + break;
> + case Val_GNU_MIPS_ABI_FP_64:
> + if (l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_64
> + && l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_XX
> + && l->l_mach.fpmode != Val_GNU_MIPS_ABI_FP_ANY)
> + success = false;
> + break;
> +#endif
> + default:
> + success = false;
> + }
> +
> + if (!success)
> + {
> + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
> + _dl_debug_printf (" uses %s, already loaded %s\n",
> + mips_fp_abi (req_abi),
> + mips_fp_abi (l->l_mach.fpmode));
> + return 0;
> + }
> + }
> +
> +#if _MIPS_SIM == _ABIO32
> + if (req_abi == Val_GNU_MIPS_ABI_FP_DOUBLE
> + || req_abi == Val_GNU_MIPS_ABI_FP_64)
> + {
> + if (GLRO(dl_hwcap) & HWCAP_MIPS_UFR)
> + {
> + int status;
> + /* Obtain UFR mode information. */
> + asm volatile ("cfc1 %0,$1\n": "=r"(status));
> + if (status == 0 && req_abi == Val_GNU_MIPS_ABI_FP_64)
> + switch_frmode_to (1);
> + else if (status == 1 && req_abi == Val_GNU_MIPS_ABI_FP_DOUBLE)
> + switch_frmode_to (0);
> +
> + asm volatile ("cfc1 %0,$1\n": "=r"(status));
I would be inclined to make these inline asm statements into a
function with a descriptive name, and potentially the status values
could usefully be named too.
> + if ((status == 0 && req_abi == Val_GNU_MIPS_ABI_FP_64)
> + || (status == 1 && req_abi == Val_GNU_MIPS_ABI_FP_DOUBLE))
> + _dl_signal_error (0, map->l_name, NULL, "Unable to set FP mode");
Under what circumstances can this error occur?
> + }
> + else if (req_abi == Val_GNU_MIPS_ABI_FP_64)
> + {
> + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
> + _dl_debug_printf (" requires FR mode switch but UFR is not supported\n");
> + return 0;
> + }
> +#endif
> + }
> +
> + return 1;
> +}
> +
> static inline ElfW(Addr) *
> elf_mips_got_from_gpreg (ElfW(Addr) gpreg)
> {
> diff --git a/sysdeps/mips/dl-procinfo.c b/sysdeps/mips/dl-procinfo.c
> index 4a3dbf3..6972b7c 100644
> --- a/sysdeps/mips/dl-procinfo.c
> +++ b/sysdeps/mips/dl-procinfo.c
> @@ -59,5 +59,21 @@ PROCINFO_CLASS const char _dl_mips_platforms[4][11]
> ,
> #endif
>
> +#if !defined PROCINFO_DECL && defined SHARED
> + ._dl_mips_cap_flags
> +#else
> +PROCINFO_CLASS const char _dl_mips_cap_flags[1][4]
> +#endif
> +#ifndef PROCINFO_DECL
> += {
> + "ufr"
> + }
> +#endif
> +#if !defined SHARED || defined PROCINFO_DECL
> +;
> +#else
> +,
> +#endif
> +
> #undef PROCINFO_DECL
> #undef PROCINFO_CLASS
> diff --git a/sysdeps/mips/dl-procinfo.h b/sysdeps/mips/dl-procinfo.h
> index b2b7702..d50d8cf 100644
> --- a/sysdeps/mips/dl-procinfo.h
> +++ b/sysdeps/mips/dl-procinfo.h
> @@ -50,18 +50,50 @@ _dl_string_platform (const char *str)
> return -1;
> };
>
> -/* We cannot provide a general printing function. */
> -#define _dl_procinfo(type, word) -1
> +#define _DL_HWCAP_COUNT 1
>
> -/* There are no hardware capabilities defined. */
> -#define _dl_hwcap_string(idx) ""
> +#define HWCAP_IMPORTANT (HWCAP_MIPS_UFR)
>
> -/* By default there is no important hardware capability. */
> -#define HWCAP_IMPORTANT (0)
> +static inline int
> +__attribute__ ((unused))
> +_dl_procinfo (unsigned int type, unsigned long int word)
> +{
> + int i;
> +
> + /* Fallback to unknown output mechanism. */
> + if (type == AT_HWCAP2)
> + return -1;
> +
> + _dl_printf ("AT_HWCAP: ");
> +
> + for (i = 0; i < _DL_HWCAP_COUNT; ++i)
> + if (word & (1 << i))
> + _dl_printf (" %s", GLRO(dl_mips_cap_flags)[i]);
> +
> + _dl_printf ("\n");
> +
> + return 0;
> +}
> +
> +static inline const char *
> +__attribute__ ((unused))
> +_dl_hwcap_string (int idx)
> +{
> + return GLRO(dl_mips_cap_flags)[idx];
> +};
>
> -/* We don't have any hardware capabilities. */
> -#define _DL_HWCAP_COUNT 0
> +static inline int
> +__attribute__ ((unused))
> +_dl_string_hwcap (const char *str)
> +{
> + int i;
>
> -#define _dl_string_hwcap(str) (-1)
> + for (i = 0; i < _DL_HWCAP_COUNT; i++)
> + {
> + if (strcmp (str, GLRO(dl_mips_cap_flags)[i]) == 0)
> + return i;
> + }
> + return -1;
> +};
>
> #endif /* dl-procinfo.h */
> diff --git a/sysdeps/unix/mips/sysdep.h b/sysdeps/unix/mips/sysdep.h
> index d59fac0..7c930ef 100644
> --- a/sysdeps/unix/mips/sysdep.h
> +++ b/sysdeps/unix/mips/sysdep.h
> @@ -19,6 +19,9 @@
> #include <sgidefs.h>
> #include <sysdeps/unix/sysdep.h>
>
> +#define _SYS_AUXV_H 1
> +#include <bits/hwcap.h>
> +
> #ifdef __ASSEMBLER__
>
> #include <regdef.h>
> diff --git a/sysdeps/unix/sysv/linux/mips/configure b/sysdeps/unix/sysv/linux/mips/configure
> index e8b0d7b..db6c8ff 100644
> --- a/sysdeps/unix/sysv/linux/mips/configure
> +++ b/sysdeps/unix/sysv/linux/mips/configure
> @@ -268,6 +268,33 @@ fi
> config_vars="$config_vars
> default-abi = ${libc_mips_abi}_${libc_mips_float}${libc_mips_nan}"
>
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for .module fp=xx support" >&5
> +$as_echo_n "checking for .module fp=xx support... " >&6; }
> +if ${libc_cv_asm_module_fpxx_directive+:} false; then :
> + $as_echo_n "(cached) " >&6
> +else
> + cat > conftest.s <<EOF
> +.module fp=xx
> +EOF
> +if { ac_try='${CC-cc} -c $ASFLAGS conftest.s 1>&5'
> + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
> + (eval $ac_try) 2>&5
> + ac_status=$?
> + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> + test $ac_status = 0; }; }; then
> + libc_cv_asm_module_fpxx_directive=yes
> +else
> + libc_cv_asm_module_fpxx_directive=no
> +fi
> +rm -f conftest*
> +fi
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_module_fpxx_directive" >&5
> +$as_echo "$libc_cv_asm_module_fpxx_directive" >&6; }
> +if test $libc_cv_asm_module_fpxx_directive = yes; then
> + $as_echo "#define HAVE_MIPS_MODULE_FPXX_DIRECTIVE 1" >>confdefs.h
> +
> +fi
> +
> case "$prefix" in
> /usr | /usr/)
> # 64-bit libraries on bi-arch platforms go in /lib64 instead of /lib.
> diff --git a/sysdeps/unix/sysv/linux/mips/configure.ac b/sysdeps/unix/sysv/linux/mips/configure.ac
> index 7087a14..cef2666 100644
> --- a/sysdeps/unix/sysv/linux/mips/configure.ac
> +++ b/sysdeps/unix/sysv/linux/mips/configure.ac
> @@ -58,6 +58,21 @@ fi
> LIBC_CONFIG_VAR([default-abi],
> [${libc_mips_abi}_${libc_mips_float}${libc_mips_nan}])
>
> +AC_CACHE_CHECK(for .module fp=xx support,
> + libc_cv_asm_module_fpxx_directive, [dnl
> +cat > conftest.s <<EOF
> +.module fp=xx
> +EOF
> +if AC_TRY_COMMAND(${CC-cc} -c $ASFLAGS conftest.s 1>&AS_MESSAGE_LOG_FD); then
> + libc_cv_asm_module_fpxx_directive=yes
> +else
> + libc_cv_asm_module_fpxx_directive=no
> +fi
> +rm -f conftest*])
> +if test $libc_cv_asm_module_fpxx_directive = yes; then
> + AC_DEFINE(HAVE_MIPS_MODULE_FPXX_DIRECTIVE)
> +fi
> +
> case "$prefix" in
> /usr | /usr/)
> # 64-bit libraries on bi-arch platforms go in /lib64 instead of /lib.
> diff --git a/sysdeps/unix/sysv/linux/mips/getcontext.S b/sysdeps/unix/sysv/linux/mips/getcontext.S
> index 1e0a277..14e7448 100644
> --- a/sysdeps/unix/sysv/linux/mips/getcontext.S
> +++ b/sysdeps/unix/sysv/linux/mips/getcontext.S
> @@ -17,6 +17,10 @@
> License along with the GNU C Library. If not, see
> <http://www.gnu.org/licenses/>. */
>
> +#include <config.h>
> +#if HAVE_MIPS_MODULE_FPXX_DIRECTIVE
> + .module fp=xx
> +#endif
> #include <sysdep.h>
> #include <sys/asm.h>
> #include <sys/fpregdef.h>
> diff --git a/sysdeps/unix/sysv/linux/mips/setcontext.S b/sysdeps/unix/sysv/linux/mips/setcontext.S
> index beeb2a5..217590c 100644
> --- a/sysdeps/unix/sysv/linux/mips/setcontext.S
> +++ b/sysdeps/unix/sysv/linux/mips/setcontext.S
> @@ -17,6 +17,10 @@
> License along with the GNU C Library. If not, see
> <http://www.gnu.org/licenses/>. */
>
> +#include <config.h>
> +#if HAVE_MIPS_MODULE_FPXX_DIRECTIVE
> + .module fp=xx
> +#endif
> #include <sysdep.h>
> #include <sys/asm.h>
> #include <sys/fpregdef.h>
> diff --git a/sysdeps/unix/sysv/linux/mips/swapcontext.S b/sysdeps/unix/sysv/linux/mips/swapcontext.S
> index 2a79976..1989e57 100644
> --- a/sysdeps/unix/sysv/linux/mips/swapcontext.S
> +++ b/sysdeps/unix/sysv/linux/mips/swapcontext.S
> @@ -17,6 +17,10 @@
> License along with the GNU C Library. If not, see
> <http://www.gnu.org/licenses/>. */
>
> +#include <config.h>
> +#if HAVE_MIPS_MODULE_FPXX_DIRECTIVE
> + .module fp=xx
> +#endif
> #include <sysdep.h>
> #include <sys/asm.h>
> #include <sys/fpregdef.h>
> --
> 1.7.1
>
--
Will Newton
Toolchain Working Group, Linaro