This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC, PATCH, MIPS] Add support for O32 FPXX and program header based ABI information


On Fri, May 2, 2014 at 1:11 AM, Will Newton <will.newton@linaro.org> wrote:
> 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?

The hardware does not support the requested mode.

Thanks,
Andrew Pinski

>
>> +       }
>> +      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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]