From patchwork Thu May 1 21:48:50 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Fortune X-Patchwork-Id: 785 Return-Path: X-Original-To: siddhesh@wilcox.dreamhost.com Delivered-To: siddhesh@wilcox.dreamhost.com Received: from homiemail-mx23.g.dreamhost.com (peon2454.g.dreamhost.com [208.113.200.127]) by wilcox.dreamhost.com (Postfix) with ESMTP id ACD0B360072 for ; Thu, 1 May 2014 14:49:05 -0700 (PDT) Received: by homiemail-mx23.g.dreamhost.com (Postfix, from userid 14307373) id 4F82363201174; Thu, 1 May 2014 14:49:05 -0700 (PDT) X-Original-To: glibc@patchwork.siddhesh.in Delivered-To: x14307373@homiemail-mx23.g.dreamhost.com Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by homiemail-mx23.g.dreamhost.com (Postfix) with ESMTPS id 1E1CD63200C73 for ; Thu, 1 May 2014 14:49:05 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id :content-type:mime-version; q=dns; s=default; b=Z5YDkB/wSGjT7CkC 9gfYWkl8b+OBCD+5dt7B1A0f+zUWmmRvVBkFTM3ylbjzsWlyMveIcGc0P0mWWYVZ oWpeR9YCgGldXcLYuFc2LkjgB9P9p0nloe9Zy746QQyL5sbiZLgy5IozD8SrYfcA VJIcxFoHhJyrFkHnmWs9+f75NNE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id :content-type:mime-version; s=default; bh=ML5+MQ9sNRW3LDsL7mcbn8 KQH7c=; b=RZG77+sT6utCCjDL042+Jmw4UorwA1o1pcSc44+8Qiw9exl9e3laT5 1SNSEl/yxJJeg11anrPQQ7ODKoRHWK+/zS3imcnaxgG/KXz6s1m6E1og4t/m5pz4 Yjwy6SjAju4jnL9fCE23QWyUZsm8jZJubWHkt/hY1qmZ5qhtlhuJQ= Received: (qmail 9639 invoked by alias); 1 May 2014 21:49:02 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 9625 invoked by uid 89); 1 May 2014 21:49:01 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mailapp01.imgtec.com From: Matthew Fortune To: "Joseph Myers (joseph@codesourcery.com)" CC: Richard Sandiford , Rich Fuhler , "macro@codesourcery.com" , "libc-alpha@sourceware.org" Subject: [RFC, PATCH, MIPS] Add support for O32 FPXX and program header based ABI information Date: Thu, 1 May 2014 21:48:50 +0000 Message-ID: <6D39441BF12EF246A7ABCE6654B0235351E3D7@LEMAIL01.le.imgtec.org> MIME-Version: 1.0 X-DH-Original-To: glibc@patchwork.siddhesh.in Hi Joseph, 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 * 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 + . */ + +#ifndef _SYS_AUXV_H +# error "Never include directly; use 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 #include #include +#include /* 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)); + 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"); + } + 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 #include +#define _SYS_AUXV_H 1 +#include + #ifdef __ASSEMBLER__ #include 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 <&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 <&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 . */ +#include +#if HAVE_MIPS_MODULE_FPXX_DIRECTIVE + .module fp=xx +#endif #include #include #include 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 . */ +#include +#if HAVE_MIPS_MODULE_FPXX_DIRECTIVE + .module fp=xx +#endif #include #include #include 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 . */ +#include +#if HAVE_MIPS_MODULE_FPXX_DIRECTIVE + .module fp=xx +#endif #include #include #include