From patchwork Fri Nov 20 07:31:00 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Maciej W. Rozycki" X-Patchwork-Id: 9755 Received: (qmail 37911 invoked by alias); 20 Nov 2015 07:31:12 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 37888 invoked by uid 89); 20 Nov 2015 07:31:10 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=AWL, BAYES_00, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mailapp01.imgtec.com Date: Fri, 20 Nov 2015 07:31:00 +0000 From: "Maciej W. Rozycki" To: CC: Matthew Fortune , Daniel Sanders , Leonid Yegoshin Subject: [RFC PATCH 5/5] MIPS: Add IEEE Std 754 NaN interlinking support In-Reply-To: Message-ID: References: User-Agent: Alpine 2.00 (DEB 1167 2008-08-23) MIME-Version: 1.0 Add the dynamic loading part of IEEE Std 754 NaN interlinking support, as per "MIPS ABI Extension for IEEE Std 754 Non-Compliant Interlinking" : * interpret the MIPS_AFL_FLAGS1_IEEE and MIPS_AFL_FLAGS2_RELAXED flags in the PT_MIPS_ABIFLAGS segment of binaries processed, * interpret the AT_FLAGS entry in the auxiliary vector supplied by the kernel, * accept or reject ELF executables (where explicitly loaded) and dynamic shared objects accordingly, in the run-time loader, * handle relaxed IEEE Std 754 compliance mode binaries in `ld.so.cache', * handle kernel IEEE Std 754 compliance mode switching via prctl(2) in explicit `ld.so' invocation. Also add messages for ENOEXEC and ELIBBAD error codes produced with code added here to `ld.so's minimal `__strerror_r' implementation. Other codes such as ENOSYS or EOPNOTSUPP may be produced by the kernel in response to the prctl(2) syscall. Let's not pull in the whole list though. * elf/elf.h (MIPS_AFL_FLAGS1_IEEE): New macro. (MIPS_AFL_FLAGS2_NOWARN, MIPS_AFL_FLAGS2_RELAXED): Likewise. (AV_FLAGS_MIPS_RELAXED): Likewise. * include/link.h (link_map) [NEED_L_EFLAGS]: Add `l_eflags' struct member. * sysdeps/generic/ldconfig.h (FLAG_MIPS_LIB32_RELAXED): New macro. (FLAG_MIPS64_LIBN32_RELAXED): Likewise. (FLAG_MIPS64_LIBN64_RELAXED): Likewise. * sysdeps/mips/dl-machine-main-map-setup.h: New file. * sysdeps/mips/dl-machine-reject-phdr.h (elf_machine_reject_phdr_p): Permit MIPS_AFL_FLAGS2_RELAXED set in `mips_abiflags'. Reject relaxed IEEE Std 754 compliance mode libraries in the strict IEEE Std 754 compliance mode. * sysdeps/mips/dl-machine.h (ELF_MACHINE_NAN2008): Move macro definition along with the associated consistency check over to sysdeps/mips/ldsodefs.h. (elf_machine_matches_host): Do not reject libraries using the opposite NaN encoding in the relaxed IEEE Std 754 compliance mode. * sysdeps/mips/ldsodefs.h (ELF_MACHINE_NAN2008): Add macro definition along with the associated consistency check moved from sysdeps/mips/dl-machine.h. * sysdeps/mips/linkmap.h (link_map_machine): Convert `odd_spreg' member to a bitfield. Add `ieee' and `relaxed' members. (NEED_L_EFLAGS): New macro. * sysdeps/unix/sysv/linux/mips/dl-cache.h (_DL_CACHE_OTHER_ID): New macro. (_DL_CACHE_RELAXED_ID): Likewise. [_DL_CACHE_DEFAULT_ID]: Remove condition. (_dl_cache_check_flags): Rewrite for relaxed IEEE Std 754 compliance mode handling. * elf/cache.c (print_entry): Handle the FLAG_MIPS_LIB32_RELAXED, FLAG_MIPS64_LIBN32_RELAXED and FLAG_MIPS64_LIBN64_RELAXED flags in entries. * elf/dl-load.c (_dl_map_object_from_fd) [NEED_L_EFLAGS]: Record the ELF file header flags in the link map newly created. * elf/dl-minimal.c (__strerror_r) : New cases with messages for error codes. * sysdeps/mips/dl-abiflags-cache.c (__mips_abiflags_cache): Permit MIPS_AFL_FLAGS2_RELAXED set in `mips_abiflags'. Record any MIPS_AFL_FLAGS1_IEEE and MIPS_AFL_FLAGS2_RELAXED flags set. * sysdeps/unix/sysv/linux/mips/readelflib.c (check_ptr): New macro. (get_relaxed): Likewise. (process_elf_file): Handle relaxed IEEE Std 754 compliance mode binaries. --- glibc-mips-nan-interlink.diff Index: glibc/elf/cache.c =================================================================== --- glibc.orig/elf/cache.c 2015-11-16 18:45:47.523597318 +0000 +++ glibc/elf/cache.c 2015-11-16 19:19:32.978099770 +0000 @@ -114,6 +114,15 @@ print_entry (const char *lib, int flag, case FLAG_MIPS64_LIBN64_NAN2008: fputs (",64bit,nan2008", stdout); break; + case FLAG_MIPS_LIB32_RELAXED: + fputs (",relaxed", stdout); + break; + case FLAG_MIPS64_LIBN32_RELAXED: + fputs (",N32,relaxed", stdout); + break; + case FLAG_MIPS64_LIBN64_RELAXED: + fputs (",64bit,relaxed", stdout); + break; case 0: break; default: Index: glibc/elf/dl-load.c =================================================================== --- glibc.orig/elf/dl-load.c 2015-11-16 19:19:18.815602519 +0000 +++ glibc/elf/dl-load.c 2015-11-16 19:19:32.981146011 +0000 @@ -1018,6 +1018,9 @@ _dl_map_object_from_fd (const char *name l->l_entry = header->e_entry; type = header->e_type; l->l_phnum = header->e_phnum; +#ifdef NEED_L_EFLAGS + l->l_eflags = header->e_flags; +#endif maplength = header->e_phnum * sizeof (ElfW(Phdr)); if (header->e_phoff + maplength <= (size_t) fbp->len) Index: glibc/elf/dl-minimal.c =================================================================== --- glibc.orig/elf/dl-minimal.c 2015-11-16 18:45:47.558974685 +0000 +++ glibc/elf/dl-minimal.c 2015-11-16 19:19:32.985198148 +0000 @@ -178,9 +178,15 @@ __strerror_r (int errnum, char *buf, siz case EIO: msg = (char *) "Input/output error"; break; + case ENOEXEC: + msg = (char *) "Exec format error"; + break; case EACCES: msg = (char *) "Permission denied"; break; + case ELIBBAD: + msg = (char *) "Accessing a corrupted shared library"; + break; default: /* No need to check buffer size, all calls in the dynamic linker provide enough space. */ Index: glibc/elf/elf.h =================================================================== --- glibc.orig/elf/elf.h 2015-11-16 18:45:47.612452757 +0000 +++ glibc/elf/elf.h 2015-11-16 19:19:32.996292254 +0000 @@ -1858,7 +1858,18 @@ typedef struct #define MIPS_AFL_EXT_LOONGSON_2F 18 /* ST Microelectronics Loongson 2F. */ /* Masks for the flags1 word of an ABI flags structure. */ + #define MIPS_AFL_FLAGS1_ODDSPREG 1 /* Uses odd single-precision registers. */ +#define MIPS_AFL_FLAGS1_IEEE 2 /* IEEE Std 754 compliance mode selection + requested. */ + +/* Masks for the flags2 word of an ABI flags structure. */ + +#define MIPS_AFL_FLAGS2_NOWARN 1 /* Do not warn on linking a strict object + in the IEEE Std 754 relaxed compliance + mode. */ +#define MIPS_AFL_FLAGS2_RELAXED 2 /* IEEE Std 754 relaxed compliance mode + selected. */ /* Object attribute values. */ enum @@ -1883,6 +1894,10 @@ enum Val_GNU_MIPS_ABI_FP_MAX = 7 }; +/* Masks for the value passed in an AT_FLAGS auxiliary vector entry. */ + +#define AV_FLAGS_MIPS_RELAXED (1U << 25) /* Relaxed IEEE Std 754 mode. */ + /* HPPA specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ Index: glibc/include/link.h =================================================================== --- glibc.orig/include/link.h 2015-11-16 18:45:47.663487267 +0000 +++ glibc/include/link.h 2015-11-16 19:19:33.007514833 +0000 @@ -127,6 +127,9 @@ struct link_map ElfW(Addr) l_entry; /* Entry point location. */ ElfW(Half) l_phnum; /* Number of program header entries. */ ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */ +#ifdef NEED_L_EFLAGS + ElfW (Word) l_eflags; /* A copy of ELF header's e_flags. */ +#endif /* Array of DT_NEEDED dependencies and their dependencies, in dependency order for symbol lookup (with and without Index: glibc/sysdeps/generic/ldconfig.h =================================================================== --- glibc.orig/sysdeps/generic/ldconfig.h 2015-11-16 18:45:47.705295568 +0000 +++ glibc/sysdeps/generic/ldconfig.h 2015-11-16 19:19:33.018684063 +0000 @@ -42,6 +42,9 @@ #define FLAG_MIPS_LIB32_NAN2008 0x0c00 #define FLAG_MIPS64_LIBN32_NAN2008 0x0d00 #define FLAG_MIPS64_LIBN64_NAN2008 0x0e00 +#define FLAG_MIPS_LIB32_RELAXED 0x0f00 +#define FLAG_MIPS64_LIBN32_RELAXED 0x1000 +#define FLAG_MIPS64_LIBN64_RELAXED 0x1100 /* Name of auxiliary cache. */ #define _PATH_LDCONFIG_AUX_CACHE "/var/cache/ldconfig/aux-cache" Index: glibc/sysdeps/mips/dl-abiflags-cache.c =================================================================== --- glibc.orig/sysdeps/mips/dl-abiflags-cache.c 2015-11-16 19:19:31.544056463 +0000 +++ glibc/sysdeps/mips/dl-abiflags-cache.c 2015-11-16 19:19:33.022772233 +0000 @@ -49,18 +49,29 @@ __mips_abiflags_cache (struct link_map * mips_abiflags = (Elf_MIPS_ABIFlags_v0 *) (l->l_addr + ph->p_vaddr); - if (__glibc_unlikely (mips_abiflags->flags2 != 0)) - FAIL (" %s: unknown MIPS.abiflags flags2: %u\n", l->l_name, - mips_abiflags->flags2); + Elf32_Word flags1 = mips_abiflags->flags1; + Elf32_Word flags2 = mips_abiflags->flags2; + + if (__glibc_unlikely ((flags2 & ~MIPS_AFL_FLAGS2_RELAXED) != 0)) + FAIL (" %s: unknown MIPS.abiflags flags2: %u\n", + l->l_name, flags2); + + if (__glibc_unlikely ((flags1 & MIPS_AFL_FLAGS1_IEEE) == 0 + && (flags2 & MIPS_AFL_FLAGS2_RELAXED) != 0)) + FAIL (" %s: unsupported MIPS.abiflags flags1/flags2: %u/%u\n", + l->l_name, flags1, flags2); l->l_mach.fpabi = mips_abiflags->fp_abi; - l->l_mach.odd_spreg = (mips_abiflags->flags1 - & MIPS_AFL_FLAGS1_ODDSPREG) != 0; + l->l_mach.odd_spreg = (flags1 & MIPS_AFL_FLAGS1_ODDSPREG) != 0; + l->l_mach.ieee = (flags1 & MIPS_AFL_FLAGS1_IEEE) != 0; + l->l_mach.relaxed = (flags2 & MIPS_AFL_FLAGS2_RELAXED) != 0; } else { l->l_mach.fpabi = -1; l->l_mach.odd_spreg = true; + l->l_mach.ieee = false; + l->l_mach.relaxed = false; } } return true; Index: glibc/sysdeps/mips/dl-machine-main-map-setup.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ glibc/sysdeps/mips/dl-machine-main-map-setup.h 2015-11-16 19:19:33.025837918 +0000 @@ -0,0 +1,114 @@ +/* Machine-dependent main link map setup for the ELF loader, MIPS version. + Copyright (C) 2015 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 _DL_MACHINE_MAIN_MAP_SETUP +#define _DL_MACHINE_MAIN_MAP_SETUP 1 + +#include +#include +#include + +#include + +#ifndef PR_SET_IEEE754_MODE +# define PR_SET_IEEE754_MODE 48 + +# define PR_IEEE754_MODE_LEGACY 0 /* Legacy mode. */ +# define PR_IEEE754_MODE_STRICT 1 /* Strict mode. */ +# define PR_IEEE754_MODE_RELAXED 2 /* Relaxed mode. */ + +# define PR_IEEE754_MODE_NAN_LEGACY 0 /* Set legacy NaN encoding. */ +# define PR_IEEE754_MODE_NAN_2008 1 /* Set 2008 NaN encoding. */ +#endif /* PR_SET_IEEE754_MODE */ + +#define AV_FLAGS_SYSTEM_SHIFT 24 /* System AT_FLAGS shift. */ + +/* Set up machine-dependent parts of the main link map. Return 0 + if successful. */ + +static inline int +elf_machine_main_map_setup (struct link_map *map, bool rtld_is_main) +{ + if (!__mips_abiflags_cache (map)) + return ENOEXEC; + +#ifdef SHARED + /* Handle the 2008-NaN vs legacy-NaN compatibility check for the + main executable loaded through ld.so invoked directly. */ + if (rtld_is_main) + { + struct link_map *rtld_map = &GL (dl_rtld_map); + + if (!__mips_abiflags_cache (rtld_map)) + return ELIBBAD; + + uintptr_t flags = GLRO (dl_flags) & ((1UL << AV_FLAGS_SYSTEM_SHIFT) - 1); + ElfW (Word) map_nan2008 = map->l_eflags & EF_MIPS_NAN2008; + bool map_nan_opposite = map_nan2008 != ELF_MACHINE_NAN2008; + int nan = (map_nan2008 ? PR_IEEE754_MODE_NAN_2008 + : PR_IEEE754_MODE_NAN_LEGACY); + int res; + + if (FILE_IEEE_STRICT (map)) + { + if (FILE_IEEE_RELAXED (rtld_map) || map_nan_opposite) + return ELIBBAD; + if (FLAGS_IEEE_RELAXED (GLRO (dl_flags))) + { + res = prctl (PR_SET_IEEE754_MODE, PR_IEEE754_MODE_STRICT, nan); + if (res < 0) + return errno; + flags |= res << AV_FLAGS_SYSTEM_SHIFT; + GLRO (dl_flags) = flags; + } + } + + if (FILE_IEEE_RELAXED (map) + && (FLAGS_IEEE_STRICT (GLRO (dl_flags)) || map_nan_opposite)) + { + res = prctl (PR_SET_IEEE754_MODE, PR_IEEE754_MODE_RELAXED, nan); + if (res < 0) + return errno; + flags |= res << AV_FLAGS_SYSTEM_SHIFT; + GLRO (dl_flags) = flags; + } + + if (FILE_IEEE_LEGACY (map)) + { + if (FILE_IEEE_LEGACY (rtld_map) + && FLAGS_IEEE_STRICT (GLRO (dl_flags)) && map_nan_opposite) + return ELIBBAD; + if (!FILE_IEEE_LEGACY (rtld_map) || map_nan_opposite) + { + res = prctl (PR_SET_IEEE754_MODE, PR_IEEE754_MODE_LEGACY, nan); + if (res < 0) + return errno; + flags |= res << AV_FLAGS_SYSTEM_SHIFT; + if (FLAGS_IEEE_STRICT (flags) + && (FILE_IEEE_RELAXED (rtld_map) || map_nan_opposite)) + return ELIBBAD; + GLRO (dl_flags) = flags; + } + } + } +#endif + + return 0; +} + +#endif /* dl-machine-main-map-setup.h */ Index: glibc/sysdeps/mips/dl-machine-reject-phdr.h =================================================================== --- glibc.orig/sysdeps/mips/dl-machine-reject-phdr.h 2015-11-16 19:19:31.578840360 +0000 +++ glibc/sysdeps/mips/dl-machine-reject-phdr.h 2015-11-16 19:19:33.027867492 +0000 @@ -115,6 +115,8 @@ elf_machine_reject_phdr_p (const ElfW(Ph struct link_map *l; Lmid_t nsid; int in_abi = -1; + bool ieee = false; + bool relaxed = false; struct abi_req in_req; Elf_MIPS_ABIFlags_v0 *mips_abiflags = NULL; bool perfect_match = false; @@ -146,12 +148,36 @@ elf_machine_reject_phdr_p (const ElfW(Ph if (size < sizeof (Elf_MIPS_ABIFlags_v0)) REJECT (" contains malformed PT_MIPS_ABIFLAGS\n"); - if (__glibc_unlikely (mips_abiflags->flags2 != 0)) - REJECT (" unknown MIPS.abiflags flags2: %u\n", mips_abiflags->flags2); + Elf32_Word flags1 = mips_abiflags->flags1; + Elf32_Word flags2 = mips_abiflags->flags2; + + if (__glibc_unlikely ((flags2 & ~MIPS_AFL_FLAGS2_RELAXED) != 0)) + REJECT (" unknown MIPS.abiflags flags2: %u\n", flags2); + + if (__glibc_unlikely ((flags1 & MIPS_AFL_FLAGS1_IEEE) == 0 + && (flags2 & MIPS_AFL_FLAGS2_RELAXED) != 0)) + REJECT (" unsupported MIPS.abiflags flags1/flags2: %u/%u\n", + flags1, flags2); in_abi = mips_abiflags->fp_abi; + ieee = (mips_abiflags->flags1 & MIPS_AFL_FLAGS1_IEEE) != 0; + relaxed = (mips_abiflags->flags2 & MIPS_AFL_FLAGS2_RELAXED) != 0; } + /* A 2008-NaN vs legacy-NaN mode check for strict IEEE Std 754 compliance + executables will have already been made in `elf_machine_matches_host'. + All that remains to be done for such executables is to guarantee we + don't pull a relaxed IEEE Std 754 compliance DSO into one. + + Again, watch out for the case where there's no main map. This happens + when an executable is being loaded through ld.so invoked directly. The + check is deferred to `elf_machine_main_map_setup' then. */ + struct link_map *main_map = GL (dl_ns)[LM_ID_BASE]._ns_loaded; + if (main_map != NULL + && FLAGS_IEEE_STRICT (GLRO (dl_flags)) + && ieee && relaxed) + return true; + /* ANY is compatible with anything. */ perfect_match |= (in_abi == Val_GNU_MIPS_ABI_FP_ANY); Index: glibc/sysdeps/mips/dl-machine.h =================================================================== --- glibc.orig/sysdeps/mips/dl-machine.h 2015-11-16 18:45:47.767072146 +0000 +++ glibc/sysdeps/mips/dl-machine.h 2015-11-16 19:19:33.039004979 +0000 @@ -83,16 +83,6 @@ do { if ((l)->l_info[DT_MIPS (RLD_MAP_RE (ElfW(Addr)) (r); \ } while (0) -#if ((defined __mips_nan2008 && !defined HAVE_MIPS_NAN2008) \ - || (!defined __mips_nan2008 && defined HAVE_MIPS_NAN2008)) -# error "Configuration inconsistency: __mips_nan2008 != HAVE_MIPS_NAN2008, overridden CFLAGS?" -#endif -#ifdef __mips_nan2008 -# define ELF_MACHINE_NAN2008 EF_MIPS_NAN2008 -#else -# define ELF_MACHINE_NAN2008 0 -#endif - /* Return nonzero iff ELF header is compatible with the running host. */ static inline int __attribute_used__ elf_machine_matches_host (const ElfW(Ehdr) *ehdr) @@ -103,8 +93,15 @@ elf_machine_matches_host (const ElfW(Ehd return 0; #endif - /* Don't link 2008-NaN and legacy-NaN objects together. */ - if ((ehdr->e_flags & EF_MIPS_NAN2008) != ELF_MACHINE_NAN2008) + /* If we're in a strict IEEE Std 754 compliance executable, then don't + link 2008-NaN and legacy-NaN objects together. Watch out for the + case where there's no main map. This happens when an executable is + being loaded through ld.so invoked directly. The check is deferred + to `elf_machine_main_map_setup' then. */ + struct link_map *main_map = GL (dl_ns)[LM_ID_BASE]._ns_loaded; + if (main_map != NULL + && FLAGS_IEEE_STRICT (GLRO (dl_flags)) + && (ehdr->e_flags & EF_MIPS_NAN2008) != ELF_MACHINE_NAN2008) return 0; /* Ensure that the old O32 FP64 ABI is never loaded, it is not supported Index: glibc/sysdeps/mips/ldsodefs.h =================================================================== --- glibc.orig/sysdeps/mips/ldsodefs.h 2015-11-16 18:45:47.779230991 +0000 +++ glibc/sysdeps/mips/ldsodefs.h 2015-11-16 19:19:33.043078738 +0000 @@ -146,4 +146,20 @@ typedef struct #undef ELF64_R_INFO #define ELF64_R_INFO(sym, type) ELF64_MIPS_R_INFO ((sym), (type)) +#if ((defined __mips_nan2008 && !defined HAVE_MIPS_NAN2008) \ + || (!defined __mips_nan2008 && defined HAVE_MIPS_NAN2008)) +# error "Configuration inconsistency: __mips_nan2008 != HAVE_MIPS_NAN2008, overridden CFLAGS?" +#endif +#ifdef __mips_nan2008 +# define ELF_MACHINE_NAN2008 EF_MIPS_NAN2008 +#else +# define ELF_MACHINE_NAN2008 0 +#endif + +#define FLAGS_IEEE_RELAXED(f) (!FLAGS_IEEE_STRICT (f)) +#define FLAGS_IEEE_STRICT(f) (!((f) & AV_FLAGS_MIPS_RELAXED)) +#define FILE_IEEE_RELAXED(l) ((l)->l_mach.ieee && (l)->l_mach.relaxed) +#define FILE_IEEE_STRICT(l) ((l)->l_mach.ieee && !(l)->l_mach.relaxed) +#define FILE_IEEE_LEGACY(l) (!(l)->l_mach.ieee) + #endif Index: glibc/sysdeps/mips/linkmap.h =================================================================== --- glibc.orig/sysdeps/mips/linkmap.h 2015-11-16 19:19:28.267518460 +0000 +++ glibc/sysdeps/mips/linkmap.h 2015-11-16 19:19:33.046102538 +0000 @@ -20,5 +20,11 @@ struct link_map_machine { ElfW (Addr) plt; /* Address of .plt. */ ElfW (Word) fpabi; /* FP ABI of the object. */ - unsigned int odd_spreg; /* Odd single-precision registers used? */ + unsigned int odd_spreg:1; /* Odd single-precision registers used? */ + unsigned int ieee:1; /* IEEE Std 754 compliance mode selection + requested? */ + unsigned int relaxed:1; /* IEEE Std 754 relaxed compliance mode + selected? */ }; + +#define NEED_L_EFLAGS Index: glibc/sysdeps/unix/sysv/linux/mips/dl-cache.h =================================================================== --- glibc.orig/sysdeps/unix/sysv/linux/mips/dl-cache.h 2015-11-16 18:45:47.824613202 +0000 +++ glibc/sysdeps/unix/sysv/linux/mips/dl-cache.h 2015-11-16 19:19:33.059455958 +0000 @@ -23,29 +23,64 @@ # error "Configuration inconsistency: __mips_nan2008 != HAVE_MIPS_NAN2008, overridden CFLAGS?" #endif -/* Redefine the cache ID for new ABIs and 2008 NaN support; legacy o32 - keeps using the generic check. */ #ifdef __mips_nan2008 # if _MIPS_SIM == _ABIO32 # define _DL_CACHE_DEFAULT_ID (FLAG_MIPS_LIB32_NAN2008 | FLAG_ELF_LIBC6) +# define _DL_CACHE_OTHER_ID FLAG_ELF_LIBC6 # elif _MIPS_SIM == _ABI64 # define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN64_NAN2008 | FLAG_ELF_LIBC6) +# define _DL_CACHE_OTHER_ID (FLAG_MIPS64_LIBN64 | FLAG_ELF_LIBC6) # elif _MIPS_SIM == _ABIN32 # define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN32_NAN2008 | FLAG_ELF_LIBC6) +# define _DL_CACHE_OTHER_ID (FLAG_MIPS64_LIBN32 | FLAG_ELF_LIBC6) # endif #else -# if _MIPS_SIM == _ABI64 +# if _MIPS_SIM == _ABIO32 +# define _DL_CACHE_DEFAULT_ID FLAG_ELF_LIBC6 +# define _DL_CACHE_OTHER_ID (FLAG_MIPS_LIB32_NAN2008 | FLAG_ELF_LIBC6) +# elif _MIPS_SIM == _ABI64 # define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN64 | FLAG_ELF_LIBC6) +# define _DL_CACHE_OTHER_ID (FLAG_MIPS64_LIBN64_NAN2008 | FLAG_ELF_LIBC6) # elif _MIPS_SIM == _ABIN32 # define _DL_CACHE_DEFAULT_ID (FLAG_MIPS64_LIBN32 | FLAG_ELF_LIBC6) +# define _DL_CACHE_OTHER_ID (FLAG_MIPS64_LIBN32_NAN2008 | FLAG_ELF_LIBC6) # endif #endif - -#ifdef _DL_CACHE_DEFAULT_ID -# define _dl_cache_check_flags(flags) \ - ((flags) == _DL_CACHE_DEFAULT_ID) +#if _MIPS_SIM == _ABIO32 +# define _DL_CACHE_RELAXED_ID (FLAG_MIPS_LIB32_RELAXED | FLAG_ELF_LIBC6) +#elif _MIPS_SIM == _ABI64 +# define _DL_CACHE_RELAXED_ID (FLAG_MIPS64_LIBN64_RELAXED | FLAG_ELF_LIBC6) +#elif _MIPS_SIM == _ABIN32 +# define _DL_CACHE_RELAXED_ID (FLAG_MIPS64_LIBN32_RELAXED | FLAG_ELF_LIBC6) #endif +#define _dl_cache_check_flags(flags) \ + ({ \ + bool ok; \ + \ + switch (flags) \ + { \ + case FLAG_ELF: \ + if (_DL_CACHE_OTHER_ID == FLAG_ELF_LIBC6) \ + ok = GL (dl_ns)[LM_ID_BASE]._ns_loaded->l_mach.relaxed; \ + else \ + ok = _DL_CACHE_DEFAULT_ID == FLAG_ELF_LIBC6; \ + break; \ + case _DL_CACHE_DEFAULT_ID: \ + ok = true; \ + break; \ + case _DL_CACHE_OTHER_ID: \ + case _DL_CACHE_RELAXED_ID: \ + ok = GL (dl_ns)[LM_ID_BASE]._ns_loaded->l_mach.relaxed; \ + break; \ + default: \ + ok = false; \ + break; \ + } \ + \ + ok; \ + }) + #define add_system_dir(dir) \ do \ { \ Index: glibc/sysdeps/unix/sysv/linux/mips/readelflib.c =================================================================== --- glibc.orig/sysdeps/unix/sysv/linux/mips/readelflib.c 2015-11-16 18:45:47.861849442 +0000 +++ glibc/sysdeps/unix/sysv/linux/mips/readelflib.c 2015-11-16 19:19:33.064588851 +0000 @@ -19,6 +19,64 @@ License along with the GNU C Library. If not, see . */ +/* check_ptr checks that a pointer is in the mmaped file and doesn't + point outside it. */ +#undef check_ptr +#define check_ptr(ptr, size) \ + do \ + { \ + void *_ptr = (ptr); \ + \ + if (_ptr < file_contents \ + || _ptr + size > file_contents + file_length) \ + { \ + error (0, 0, _("file %s is truncated\n"), file_name); \ + return 1; \ + } \ + } \ + while (0); + +#define get_relaxed(elfsz) \ + ({ \ + bool relaxed = false; \ + Elf##elfsz##_Phdr *seg; \ + int i; \ + \ + for (i = 0, seg = elf_header.eh##elfsz->e_phoff + file_contents; \ + i < elf_header.eh##elfsz->e_phnum; \ + i++, seg++) \ + { \ + check_ptr (seg, sizeof (*seg)); \ + if (seg->p_type == PT_MIPS_ABIFLAGS) \ + { \ + Elf_MIPS_ABIFlags_v0 *abiflags; \ + \ + if (seg->p_filesz < sizeof (*abiflags)) \ + { \ + error (0, 0, \ + _("Malformed PT_MIPS_ABIFLAGS in file %s.\n"), \ + file_name); \ + return 1; \ + } \ + \ + abiflags = seg->p_offset + file_contents; \ + check_ptr (abiflags, sizeof (*abiflags)); \ + \ + if ((abiflags->flags2 & ~MIPS_AFL_FLAGS2_RELAXED) != 0) \ + { \ + error (0, 0, \ + _("Unknown MIPS.abiflags flags2 %x in file %s.\n"), \ + abiflags->flags2, file_name); \ + return 1; \ + } \ + \ + relaxed = (abiflags->flags2 & MIPS_AFL_FLAGS2_RELAXED) != 0; \ + break; \ + } \ + } \ + \ + relaxed; \ + }) int process_elf32_file (const char *file_name, const char *lib, int *flag, unsigned int *osversion, char **soname, @@ -51,11 +109,15 @@ process_elf_file (const char *file_name, { Elf32_Word flags = elf_header.eh32->e_flags; int nan2008 = (flags & EF_MIPS_NAN2008) != 0; + bool relaxed = get_relaxed (32); /* n32 libraries are always libc.so.6+, o32 only if 2008 NaN. */ if ((flags & EF_MIPS_ABI2) != 0) - *flag = (nan2008 ? FLAG_MIPS64_LIBN32_NAN2008 + *flag = (relaxed ? FLAG_MIPS64_LIBN32_RELAXED + : nan2008 ? FLAG_MIPS64_LIBN32_NAN2008 : FLAG_MIPS64_LIBN32) | FLAG_ELF_LIBC6; + else if (relaxed) + *flag = FLAG_MIPS_LIB32_RELAXED | FLAG_ELF_LIBC6; else if (nan2008) *flag = FLAG_MIPS_LIB32_NAN2008 | FLAG_ELF_LIBC6; } @@ -69,8 +131,10 @@ process_elf_file (const char *file_name, { Elf64_Word flags = elf_header.eh64->e_flags; int nan2008 = (flags & EF_MIPS_NAN2008) != 0; + bool relaxed = get_relaxed (64); - *flag = (nan2008 ? FLAG_MIPS64_LIBN64_NAN2008 + *flag = (relaxed ? FLAG_MIPS64_LIBN64_RELAXED + : nan2008 ? FLAG_MIPS64_LIBN64_NAN2008 : FLAG_MIPS64_LIBN64) | FLAG_ELF_LIBC6; } }