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: [PATCHv2, MIPS] Add support for O32 FPXX and program header based ABI information


On 14 May 2014 15:46, Matthew Fortune <Matthew.Fortune@imgtec.com> wrote:

Hi Matthew,

> I've updated the patch based on the comments.
>
> I couldn't change the error message about failing to set the FR mode
> as suggested because dl_signal_error does not support formatters. I did
> however add debug diagnostics to state what mode change was being
> attempted and this can be used in conjunction with the error to find out
> what was happening. The diagnostic will also be useful simply to know
> when a module triggers a successful mode change too.
>
> The AFL* flags have been updated in line with changes to binutils FPXX
> support.
>
> The HAVE_MIPS_MODULE_FPXX_DIRECTIVE macro/configure test is no longer
> needed owing to a change in how the assembler handles inferring an FP
> ABI.
>
> I have not yet tested all the FP ABI combinations but have covered the
> ones which are related to FPXX. I am working through the rest as well
> as n32/n64 ABIs.
>
> I'm not sure what I should do for testing/checking the changes to all
> the dl-machine.h files... I built an aarch64 version of glibc to check
> at least one still builds and the same code is placed in all dl-machine.h
> files. Each file appears to have a different whitespace policy so I left
> either one or two newlines between functions depending on the file.
>
> I would also like to add in another feature to check for the presence
> of MSA in an object and reject it if HWCAP_MIPS_MSA is not set.  With
> that in place users can construct MSA and non-MSA optimised libraries
> and place the MSA library first in the search path and get the best
> supported by the host.  This is possible because the MSA extension
> makes no changes to the calling convention. Does that sound OK?
>
> Regards,
> Matthew
>
> 2014-05-14  Matthew Fortune  <matthew.fortune@imgtec.com>
>
>         * elf/dl-load.c (open_verify): Add 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): Likewise.
>         (AFL_ASE_MSA, AFL_ASE_MSA64, AFL_ASE_MIPS16): Likewise.
>         (AFL_ASE_MICROMIPS, AFL_ASE_XPA): 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.
>         (find_mips_abiflags): New static inline function.
>         (switch_frmode_to): New static no-inline function.
>         (mips_fp_abi_string, 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/aarch64/dl-machine.h
>         (elf_machine_phdr_check): New static function.
>         * sysdeps/alpha/dl-machine.h: Likewise.
>         * sysdeps/arm/dl-machine.h: Likewise.
>         * sysdeps/generic/dl-machine.h: Likewise.
>         * sysdeps/hppa/dl-machine.h: Likewise.
>         * sysdeps/i386/dl-machine.h: Likewise.
>         * sysdeps/ia64/dl-machine.h: Likewise.
>         * sysdeps/m68k/dl-machine.h: Likewise.
>         * sysdeps/microblaze/dl-machine.h: Likewise.
>         * sysdeps/powerpc/powerpc32/dl-machine.h: Likewise.
>         * sysdeps/powerpc/powerpc64/dl-machine.h: Likewise.
>         * sysdeps/s390/s390-32/dl-machine.h: Likewise.
>         * sysdeps/s390/s390-64/dl-machine.h: Likewise.
>         * sysdeps/sh/dl-machine.h: Likewise.
>         * sysdeps/sparc/sparc32/dl-machine.h: Likewise.
>         * sysdeps/sparc/sparc64/dl-machine.h: Likewise.
>         * sysdeps/tile/dl-machine.h: Likewise.
>         * sysdeps/x86_64/dl-machine.h: Likewise.
> ---
>  elf/dl-load.c                          |    5 +
>  elf/elf.h                              |   94 ++++++++++++-
>  sysdeps/aarch64/dl-machine.h           |    9 ++
>  sysdeps/alpha/dl-machine.h             |    9 ++
>  sysdeps/arm/dl-machine.h               |   10 ++
>  sysdeps/generic/dl-machine.h           |    8 +
>  sysdeps/hppa/dl-machine.h              |    9 ++
>  sysdeps/i386/dl-machine.h              |   10 ++
>  sysdeps/ia64/dl-machine.h              |    8 +
>  sysdeps/m68k/dl-machine.h              |   10 ++
>  sysdeps/microblaze/dl-machine.h        |    9 ++
>  sysdeps/mips/bits/hwcap.h              |   23 +++
>  sysdeps/mips/bits/linkmap.h            |    1 +
>  sysdeps/mips/dl-machine.h              |  242 ++++++++++++++++++++++++++++++++
>  sysdeps/mips/dl-procinfo.c             |   16 ++
>  sysdeps/mips/dl-procinfo.h             |   50 ++++++--
>  sysdeps/powerpc/powerpc32/dl-machine.h |    9 ++
>  sysdeps/powerpc/powerpc64/dl-machine.h |    8 +
>  sysdeps/s390/s390-32/dl-machine.h      |   10 ++
>  sysdeps/s390/s390-64/dl-machine.h      |    9 ++
>  sysdeps/sh/dl-machine.h                |   10 ++
>  sysdeps/sparc/sparc32/dl-machine.h     |    9 ++
>  sysdeps/sparc/sparc64/dl-machine.h     |    9 ++
>  sysdeps/tile/dl-machine.h              |   10 ++
>  sysdeps/unix/mips/sysdep.h             |    3 +
>  sysdeps/x86_64/dl-machine.h            |    8 +
>  27 files changed, 587 insertions(+), 13 deletions(-)
>  create mode 100644 sysdeps/mips/bits/hwcap.h
>
> diff --git a/elf/dl-load.c b/elf/dl-load.c
> index cfa7f25..201bf18 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -1697,6 +1697,11 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
>             }
>         }
>
> +      if (!__glibc_likely (
> +            elf_machine_phdr_check (phdr, ehdr->e_phnum, fbp->buf, fbp->len,
> +                                    fd, loader)))
> +       goto close_and_out;
> +
>        /* 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..8d83b47 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,93 @@ 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_DSPR2          0x00000002 /* DSP R2 ASE.  */
> +#define AFL_ASE_EVA            0x00000004 /* Enhanced VA Scheme.  */
> +#define AFL_ASE_MCU            0x00000008 /* MCU (MicroController) ASE.  */
> +#define AFL_ASE_MDMX           0x00000010 /* MDMX ASE.  */
> +#define AFL_ASE_MIPS3D         0x00000020 /* MIPS-3D ASE.  */
> +#define AFL_ASE_MT             0x00000040 /* MT ASE.  */
> +#define AFL_ASE_SMARTMIPS      0x00000080 /* SmartMIPS ASE.  */
> +#define AFL_ASE_VIRT           0x00000100 /* VZ ASE.  */
> +#define AFL_ASE_MSA            0x00000200 /* MSA ASE.  */
> +#define AFL_ASE_MIPS16         0x00000400 /* MIPS16 ASE.  */
> +#define AFL_ASE_MICROMIPS      0x00000800 /* MICROMIPS ASE.  */
> +#define AFL_ASE_XPA            0x00001000 /* XPA ASE.  */
> +
> +/* Values for the isa_ext word of an ABI flags structure.  */
> +
> +#define AFL_EXT_XLR            1   /* RMI Xlr instruction.  */
> +#define AFL_EXT_OCTEON2                2   /* Cavium Networks Octeon2.  */
> +#define AFL_EXT_OCTEONP                3   /* Cavium Networks OcteonP.  */
> +#define AFL_EXT_LOONGSON_3A    4   /* Loongson 3A.  */
> +#define AFL_EXT_OCTEON         5   /* Cavium Networks Octeon.  */
> +#define AFL_EXT_5900           6   /* MIPS R5900 instruction.  */
> +#define AFL_EXT_4650           7   /* MIPS R4650 instruction.  */
> +#define AFL_EXT_4010           8   /* LSI R4010 instruction.  */
> +#define AFL_EXT_4100           9   /* NEC VR4100 instruction.  */
> +#define AFL_EXT_3900           10  /* Toshiba R3900 instruction.  */
> +#define AFL_EXT_10000          11  /* MIPS R10000 instruction.  */
> +#define AFL_EXT_SB1            12  /* Broadcom SB-1 instruction.  */
> +#define AFL_EXT_4111           13  /* NEC VR4111/VR4181 instruction.  */
> +#define AFL_EXT_4120           14  /* NEC VR4120 instruction.  */
> +#define AFL_EXT_5400           15  /* NEC VR5400 instruction.  */
> +#define AFL_EXT_5500           16  /* NEC VR5500 instruction.  */
> +#define AFL_EXT_LOONGSON_2E    17  /* ST Microelectronics Loongson 2E.  */
> +#define AFL_EXT_LOONGSON_2F    18  /* ST Microelectronics 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/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
> index 997c860..9770e3d 100644
> --- a/sysdeps/aarch64/dl-machine.h
> +++ b/sysdeps/aarch64/dl-machine.h
> @@ -32,6 +32,15 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
>    return ehdr->e_machine == EM_AARCH64;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}

I'm wondering whether the types could be improved here:

1. Should it return bool?
2. Should buf be const?
3. Should len be ssize_t?
4. The spacing around '*' is inconsistent.

> +
>  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
>     first element of the GOT. */
>  static inline ElfW(Addr) __attribute__ ((unused))
> diff --git a/sysdeps/alpha/dl-machine.h b/sysdeps/alpha/dl-machine.h
> index 63db19c..9e65706 100644
> --- a/sysdeps/alpha/dl-machine.h
> +++ b/sysdeps/alpha/dl-machine.h
> @@ -42,6 +42,15 @@ elf_machine_matches_host (const Elf64_Ehdr *ehdr)
>    return ehdr->e_machine == EM_ALPHA;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
>  /* Return the link-time address of _DYNAMIC.  The multiple-got-capable
>     linker no longer allocates the first .got entry for this.  But not to
>     worry, no special tricks are needed.  */
> diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h
> index 899b256..9bf4b89 100644
> --- a/sysdeps/arm/dl-machine.h
> +++ b/sysdeps/arm/dl-machine.h
> @@ -38,6 +38,16 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>  }
>
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
> +
>  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
>     first element of the GOT.  */
>  static inline Elf32_Addr __attribute__ ((unused))
> diff --git a/sysdeps/generic/dl-machine.h b/sysdeps/generic/dl-machine.h
> index d7a2b60..c036ec3 100644
> --- a/sysdeps/generic/dl-machine.h
> +++ b/sysdeps/generic/dl-machine.h
> @@ -33,6 +33,14 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>      }
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
>
>  /* Return the link-time address of _DYNAMIC.  */
>  static inline Elf32_Addr
> diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
> index ba21f07..423d51c 100644
> --- a/sysdeps/hppa/dl-machine.h
> +++ b/sysdeps/hppa/dl-machine.h
> @@ -72,6 +72,15 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>    return ehdr->e_machine == EM_PARISC;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
>  /* Return the link-time address of _DYNAMIC.  */
>  static inline Elf32_Addr
>  elf_machine_dynamic (void) __attribute__ ((const));
> diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
> index 368bee2..6541c20 100644
> --- a/sysdeps/i386/dl-machine.h
> +++ b/sysdeps/i386/dl-machine.h
> @@ -34,6 +34,16 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>  }
>
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
> +
>  #ifdef PI_STATIC_AND_HIDDEN
>
>  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
> diff --git a/sysdeps/ia64/dl-machine.h b/sysdeps/ia64/dl-machine.h
> index 853e6fd..dfc6377 100644
> --- a/sysdeps/ia64/dl-machine.h
> +++ b/sysdeps/ia64/dl-machine.h
> @@ -54,6 +54,14 @@ elf_machine_matches_host (const Elf64_Ehdr *ehdr)
>    return ehdr->e_machine == EM_IA_64;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
>
>  /* Return the link-time address of _DYNAMIC.  */
>  static inline Elf64_Addr __attribute__ ((unused, const))
> diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
> index 3ec9862..68f62d7 100644
> --- a/sysdeps/m68k/dl-machine.h
> +++ b/sysdeps/m68k/dl-machine.h
> @@ -33,6 +33,16 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>  }
>
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
> +
>  /* Return the link-time address of _DYNAMIC.
>     This must be inlined in a function which uses global data.  */
>  static inline Elf32_Addr
> diff --git a/sysdeps/microblaze/dl-machine.h b/sysdeps/microblaze/dl-machine.h
> index 848e822..be7fe49 100644
> --- a/sysdeps/microblaze/dl-machine.h
> +++ b/sysdeps/microblaze/dl-machine.h
> @@ -31,6 +31,15 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>    return (ehdr->e_machine == EM_MICROBLAZE);
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
>  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
>     first element of the GOT.  This must be inlined in a function which
>     uses global data.  */
> 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..86ca168 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,247 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
>      }
>  }
>
> +/* 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;
> +}
> +
> +#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));
> +}
> +
> +/* Obtain the current FR mode setting.  */
> +
> +static inline int
> +get_frmode (void)
> +{
> +  int frmode;
> +  asm volatile ("cfc1 %0,$1\n": "=r"(frmode));
> +  return frmode;
> +}
> +#endif
> +
> +/* Return a description of the specified floating-point ABI.  */
> +
> +static const char *
> +mips_fp_abi_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)";
> +    default:
> +      return "Unknown FP ABI";
> +    }
> +}
> +
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  This verifies that floating-point ABIs are compatible and
> +   re-configures the hardware FR mode if necessary.  */
> +
> +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 (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
> +               _dl_debug_printf ("   Unable to read PT_MIPS_ABIFLAGS\n");
> +             return 0;
> +           }
> +       }
> +      if (size < sizeof (Elf_ABIFlags_v0))
> +       {
> +         if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
> +           _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 (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
> +                     _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 (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
> +             _dl_debug_printf ("   uses %s, already loaded %s\n",
> +                               mips_fp_abi_string (req_abi),
> +                               mips_fp_abi_string (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 frmode;
> +         /* Obtain current FR mode via UFR.  */
> +         frmode = get_frmode ();
> +         if (frmode == 0 && req_abi == Val_GNU_MIPS_ABI_FP_64)
> +           {
> +             if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
> +               _dl_debug_printf ("   setting FR mode to 1\n");
> +             switch_frmode_to (1);
> +           }
> +         else if (frmode == 1 && req_abi == Val_GNU_MIPS_ABI_FP_DOUBLE)
> +           {
> +             if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
> +               _dl_debug_printf ("   setting FR mode to 0\n");
> +             switch_frmode_to (0);
> +           }
> +
> +         frmode = get_frmode ();
> +         if ((frmode == 0 && req_abi == Val_GNU_MIPS_ABI_FP_64)
> +             || (frmode == 1 && req_abi == Val_GNU_MIPS_ABI_FP_DOUBLE))
> +           _dl_signal_error (0, map->l_name, NULL,
> +                             "hardware failed to set FR mode");
> +       }
> +      else if (req_abi == Val_GNU_MIPS_ABI_FP_64)
> +       {
> +         if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
> +           _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/powerpc/powerpc32/dl-machine.h b/sysdeps/powerpc/powerpc32/dl-machine.h
> index 23b610f..2572eea 100644
> --- a/sysdeps/powerpc/powerpc32/dl-machine.h
> +++ b/sysdeps/powerpc/powerpc32/dl-machine.h
> @@ -36,6 +36,15 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>    return ehdr->e_machine == EM_PPC;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
>  /* Return the value of the GOT pointer.  */
>  static inline Elf32_Addr * __attribute__ ((const))
>  ppc_got (void)
> diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h
> index bc99183..f0434b2 100644
> --- a/sysdeps/powerpc/powerpc64/dl-machine.h
> +++ b/sysdeps/powerpc/powerpc64/dl-machine.h
> @@ -80,6 +80,14 @@ elf_host_tolerates_class (const Elf64_Ehdr *ehdr)
>    return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
>
>  /* Return the run-time load address of the shared object, assuming it
>     was originally linked at zero.  */
> diff --git a/sysdeps/s390/s390-32/dl-machine.h b/sysdeps/s390/s390-32/dl-machine.h
> index 4fd2745..bbf7ba1 100644
> --- a/sysdeps/s390/s390-32/dl-machine.h
> +++ b/sysdeps/s390/s390-32/dl-machine.h
> @@ -46,6 +46,16 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>  }
>
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
> +
>  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
>     first element of the GOT.  This must be inlined in a function which
>     uses global data.  */
> diff --git a/sysdeps/s390/s390-64/dl-machine.h b/sysdeps/s390/s390-64/dl-machine.h
> index 2f37169..e480261 100644
> --- a/sysdeps/s390/s390-64/dl-machine.h
> +++ b/sysdeps/s390/s390-64/dl-machine.h
> @@ -41,6 +41,15 @@ elf_machine_matches_host (const Elf64_Ehdr *ehdr)
>          && ehdr->e_ident[EI_CLASS] == ELFCLASS64;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
>  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
>     first element of the GOT.  This must be inlined in a function which
>     uses global data.  */
> diff --git a/sysdeps/sh/dl-machine.h b/sysdeps/sh/dl-machine.h
> index 4f3db89..ba2223e 100644
> --- a/sysdeps/sh/dl-machine.h
> +++ b/sysdeps/sh/dl-machine.h
> @@ -33,6 +33,16 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>  }
>
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
> +
>  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
>     first element of the GOT.  This must be inlined in a function which
>     uses global data.  */
> diff --git a/sysdeps/sparc/sparc32/dl-machine.h b/sysdeps/sparc/sparc32/dl-machine.h
> index e7d31b4..65a849f 100644
> --- a/sysdeps/sparc/sparc32/dl-machine.h
> +++ b/sysdeps/sparc/sparc32/dl-machine.h
> @@ -48,6 +48,15 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
>      return 0;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
>  /* We have to do this because elf_machine_{dynamic,load_address} can be
>     invoked from functions that have no GOT references, and thus the compiler
>     has no obligation to load the PIC register.  */
> diff --git a/sysdeps/sparc/sparc64/dl-machine.h b/sysdeps/sparc/sparc64/dl-machine.h
> index ef4ad4c..05f2669 100644
> --- a/sysdeps/sparc/sparc64/dl-machine.h
> +++ b/sysdeps/sparc/sparc64/dl-machine.h
> @@ -37,6 +37,15 @@ elf_machine_matches_host (const Elf64_Ehdr *ehdr)
>    return ehdr->e_machine == EM_SPARCV9;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
>  /* We have to do this because elf_machine_{dynamic,load_address} can be
>     invoked from functions that have no GOT references, and thus the compiler
>     has no obligation to load the PIC register.  */
> diff --git a/sysdeps/tile/dl-machine.h b/sysdeps/tile/dl-machine.h
> index d686a65..8fa86d2 100644
> --- a/sysdeps/tile/dl-machine.h
> +++ b/sysdeps/tile/dl-machine.h
> @@ -53,6 +53,16 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
>  }
>
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
> +
> +
>  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
>     first element of the GOT.  This must be inlined in a function which
>     uses global data.  */
> 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/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
> index 8df04a9..290c405 100644
> --- a/sysdeps/x86_64/dl-machine.h
> +++ b/sysdeps/x86_64/dl-machine.h
> @@ -34,6 +34,14 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
>    return ehdr->e_machine == EM_X86_64;
>  }
>
> +/* Return nonzero iff ELF program headers are compatible with the running
> +   host.  */
> +static inline int
> +elf_machine_phdr_check (const ElfW(Phdr) *phdr, ElfW(Half) phnum,
> +                       char * buf, int len, int fd, struct link_map * map)
> +{
> +  return 1;
> +}
>
>  /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
>     first element of the GOT.  This must be inlined in a function which
> --
> 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]