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;
+}
+
/* 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
+ . */
+
+#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..86ca168 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,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
#include
+#define _SYS_AUXV_H 1
+#include
+
#ifdef __ASSEMBLER__
#include
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