about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog168
-rw-r--r--NEWS13
-rw-r--r--elf/get-dynamic-info.h5
-rw-r--r--iconv/Makefile2
-rw-r--r--iconv/gconv_simple.c16
-rw-r--r--iconv/tst-iconv8.c50
-rw-r--r--iconv/tst-iconv_prog.sh284
-rw-r--r--iconvdata/ibm1364.c14
-rw-r--r--sysdeps/powerpc/fpu/fedisblxcpt.c26
-rw-r--r--sysdeps/powerpc/fpu/feenablxcpt.c27
-rw-r--r--sysdeps/powerpc/fpu/fegetexcept.c2
-rw-r--r--sysdeps/powerpc/fpu/fegetmode.c2
-rw-r--r--sysdeps/powerpc/fpu/feholdexcpt.c7
-rw-r--r--sysdeps/powerpc/fpu/fenv_libc.h169
-rw-r--r--sysdeps/powerpc/fpu/fenv_private.h129
-rw-r--r--sysdeps/powerpc/fpu/fesetenv.c27
-rw-r--r--sysdeps/powerpc/fpu/fesetmode.c18
-rw-r--r--sysdeps/powerpc/fpu/feupdateenv.c17
18 files changed, 749 insertions, 227 deletions
diff --git a/ChangeLog b/ChangeLog
index bc2f4aae69..14d2cdd690 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -209,6 +209,174 @@
 	* malloc/malloc.c (__malloc_info): Remove unwanted leading
 	whitespace.
 
+2019-10-02  Paul A. Clarke  <pc@us.ibm.com>
+
+	* sysdeps/powerpc/fpu/fenv_private.h:
+	(__TEST_AND_BEGIN_NON_STOP): New.
+	(__TEST_AND_END_NON_STOP): New.
+	(libc_feholdexcept_setround_ppc): Use __TEST_AND_BEGIN_NON_STOP.
+	(__libc_femergeenv_ppc): Use __TEST_AND_BEGIN_NON_STOP and
+	__TEST_AND_END_NON_STOP.
+	(libc_feholdsetround_noex_ppc_ctx): Use __TEST_AND_END_NON_STOP.
+
+2019-09-27  Paul A. Clarke  <pc@us.ibm.com>
+
+	* sysdeps/powerpc/fpu/fenv_libc.h (fesetenv_mode): Rename to
+	fesetenv_control.
+	* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Accommodate
+	rename of fesetenv_mode to fegetenv_control.
+	* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Likewise.
+	* sysdeps/powerpc/fpu/fesetmode.c (fesetmode): Likewise.
+	* sysdeps/powerpc/fpu/fenv_private.h (__libc_femergeenv_ppc): Likewise.
+	(libc_feholdsetround_noex_ppc_ctx): Likewise.
+
+2019-09-27  Paul A. Clarke  <pc@us.ibm.com>
+
+	* sysdeps/powerpc/fpu/fenv_private.h
+	(libc_feholdsetround_noex_ppc_ctx): Call fesetenv_mode instead
+	of fesetenv_register.
+
+2019-09-27  Paul A. Clarke  <pc@us.ibm.com>
+
+	* sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_status): Rename to
+	fegetenv_control.
+	* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Accommodate
+	rename of fegetenv_status to fegetenv_control.
+	* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Likewise.
+	* sysdeps/powerpc/fpu/fegetexcept.c (__fegetexcept): Likewise.
+	* sysdeps/powerpc/fpu/fegetmode.c (fegetmode): Likewise.
+	* sysdeps/powerpc/fpu/fesetenv.c (__fesetenv): Likewise.
+	* sysdeps/powerpc/fpu/fesetmode.c (fesetmode): Likewise.
+
+2019-09-27  Paul A. Clarke  <pc@us.ibm.com>
+
+	* sysdeps/powerpc/fpu/fenv_libc.h (__fesetround_inline): Use
+	'mffscrn' instruction on POWER9.
+	(__fesetround_inline_nocheck): Likewise.
+
+2019-09-27  Paul A. Clarke  <pc@us.ibm.com>
+
+	* sysdeps/powerpc/fpu/fenv_libc.h (FPSCR_EXCEPTIONS_MASK):  New.
+	* sysdeps/powerpc/fpu/fenv_private.h (__libc_femergeenv_ppc):  Optimize
+	to write FPSCR control only, if exceptions have not changed.
+
+2019-09-27  Paul A. Clarke  <pc@us.ibm.com>
+
+	* sysdeps/powerpc/fpu/fenv_libc.h:
+	(__TEST_AND_ENTER_NON_STOP): New.
+	(__TEST_AND_EXIT_NON_STOP): New.
+	* sysdeps/powerpc/fpu/fenv_private.h
+	(_FPU_ALL_TRAPS): Delete, replace with FPSCR_ENABLES_MASK.
+	(_FPU_MASK_RN): Delete.
+	(_FPU_MASK_NOT_RN_NI): Delete.
+	(_FPU_MASK_TRAPS_RN): Delete, replace with ~FPSCR_CONTROL_MASK.
+	(_FPU_MASK_FRAC_INEX_RET_CC): Delete, replace with ~FPSCR_STATUS_MASK.
+	(__libc_feholdbits_ppc): Delete, move code into
+	libc_feholdexcept_setround_ppc.
+	(libc_feholdexcept_ppc): Delete.
+	(libc_fesetround_ppc): Delete.
+	(libc_fetestexcept_ppc): Delete.
+	(libc_feholdsetround_ppc): Delete.
+	(__libc_femergeenv_ppc): Use __TEST_AND_ENTER/EXIT_NON_STOP.
+	(libc_feholdsetround_noex_ppc_ctx): Likewise.
+	(libc_feupdateenv_test_ppc): Use FPSCR defines.
+	* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Use
+	__TEST_AND_ENTER_NON_STOP.
+	* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Likewise.
+	* sysdeps/powerpc/fpu/feholdexcpt.c (__feholdexcept): Likewise.
+	* sysdeps/powerpc/fpu/fesetenv.c (__fesetenv): Likewise.
+	* sysdeps/powerpc/fpu/fesetmode.c (fesetmode): Likewise.
+	* sysdeps/powerpc/fpu/feupdateenv.c (__feupdateenv): Likewise.
+	(_FPU_MASK_ALL): Delete.
+
+2019-09-19  Paul A. Clarke  <pc@us.ibm.com>
+    
+	* sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_and_set_rn): New.
+	(__fe_mffscrn): New.
+	* sysdeps/powerpc/fpu/fenv_private.h (libc_feholdsetround_ppc_ctx):
+	Do not clear enable bits, remove obsolete code, use
+	fegetenv_and_set_rn.
+	(libc_feresetround_ppc): Remove obsolete code, use
+	fegetenv_and_set_rn.
+
+2019-08-28  Paul A. Clarke  <pc@us.ibm.com>
+    
+    	* sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_status_ISA300):  Delete.
+    	(fegetenv_status):  Generate 'mffsl' unconditionally.
+
+2019-08-28  Paul A. Clarke  <pc@us.ibm.com>
+    
+    	* sysdeps/powerpc/fpu/fesetenv.c (__fesetenv):  Utilize lightweight
+    	FPSCR read.
+    	(_FPU_MASK_ALL):  Delete.
+
+2019-08-28  Paul A. Clarke  <pc@us.ibm.com>
+    
+    	* sysdeps/powerpc/fpu/fenv_private.h (libc_feholdsetround_ppc_ctx):
+    	Utilize lightweight FPSCR read if possible, set fewer FPSCR bits
+    	if possible.
+    	(libc_feresetround_ppc):  Replace call to __libc_femergeenv_ppc
+    	with simpler required steps, set fewer FPSCR bits if possible.
+
+2019-08-28  Paul A. Clarke  <pc@us.ibm.com>
+    
+    	* sysdeps/powerpc/fpu/fenv_libc.h (fesetenv_mode): New.
+    	(FPSCR_FPRF_MASK): New. (FPSCR_STATUS_MASK): New.
+    	* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Use lighter-
+    	weight access to FPSCR; remove unnecessary second FPSCR read and
+    	validate.
+    	* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Likewise.
+    	* sysdeps/powerpc/fpu/fesetmode.c (fesetmode): Use lighter-weight
+    	access to FPSCR; Use macros in fenv_libc.h in favor of local.
+
+2019-08-28  Paul A. Clarke  <pc@us.ibm.com>
+    
+    	* sysdeps/powerpc/fpu/fenv_libc.h: Define FPSCR bitmasks.
+    	(fenv_reg_to_exceptions): Replace bitwise operations with mask-shift.
+    	(fenv_exceptions_to_reg): New.
+    	* sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Replace bitwise
+    	operation with call to fenv_exceptions_to_reg().
+    	* sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Likewise.
+
+2019-09-20  Joseph Myers  <joseph@codesourcery.com>
+
+	* sysdeps/unix/sysv/linux/riscv/vfork.S: Do not include
+	<linux/sched.h>.
+	(CLONE_VM): New macro.
+	(CLONE_VFORK): Likewise.
+
+2019-09-14  Aurelien Jarno  <aurelien@aurel32.net>
+
+	[BZ #24986]
+        * sysdeps/unix/alpha/getegid.S: Move to ...
+	* sysdeps/unix/sysv/linux/alpha/getegid.S: ... here.
+        * sysdeps/unix/alpha/geteuid.S: Move to ...
+	* sysdeps/unix/sysv/linux/alpha/geteuid.S: ... here.
+        * sysdeps/unix/alpha/getppid.S: Move to ...
+	* sysdeps/unix/sysv/linux/alpha/getppid.S: ... here
+
+2019-09-08  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+	* sysdeps/hppa/fpu/libm-test-ulps: Update.
+
+2019-09-03  Aurelien Jarno  <aurelien@aurel32.net>
+
+	* sysdeps/alpha/fpu/libm-test-ulps: Regenerated using GCC 9.2.
+
+2019-08-28  Rafal Luzynski  <digitalfreak@lingonborough.com>
+
+	[BZ #24682]
+	* NEWS: Mention this bug fixed.
+	* localedata/locales/bo_CN (first_weekday): Add, set to 2 (Monday).
+	* localedata/locales/ug_CN (first_weekday): Likewise.
+	* localedata/locales/zh_CN (first_weekday): Likewise.
+
+2019-08-01  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #24867]
+	* malloc/malloc.c (__malloc_info): Remove unwanted leading
+	whitespace.
+
 2019-08-01  Carlos O'Donell <carlos@redhat.com>
 
 	* version.h (RELEASE): Set to "stable".
diff --git a/NEWS b/NEWS
index 8715fd7d2b..64fa988e42 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,19 @@ CVE-2020-1751: A defect in the PowerPC backtrace function could cause an
 CVE-2020-1752: A use-after-free vulnerability in the glob function when
   expanding ~user has been fixed.
 
+CVE-2020-27618: An infinite loop has been fixed in the iconv program when
+  invoked with input containing redundant shift sequences in the IBM1364,
+  IBM1371, IBM1388, IBM1390, or IBM1399 character sets.
+
+CVE-2020-29562: An assertion failure has been fixed in the iconv function
+  when invoked with UCS4 input containing an invalid character.
+
+  CVE-2021-3326: An assertion failure during conversion from the
+  ISO-20220-JP-3 character set using the iconv function has been fixed.
+  This assertion was triggered by certain valid inputs in which the
+  converted output contains a combined sequence of two wide characters
+  crossing a buffer boundary.  Reported by Tavis Ormandy.
+
 The following bugs are resolved with this release:
 
   [20019] NULL pointer dereference in libc.so.6 IFUNC due to uninitialized GOT
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
index 75fbb88f78..7ea645d03f 100644
--- a/elf/get-dynamic-info.h
+++ b/elf/get-dynamic-info.h
@@ -142,10 +142,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
   assert (info[DT_FLAGS] == NULL
 	  || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0);
 #endif
-#if defined RTLD_BOOTSTRAP || defined STATIC_PIE_BOOTSTRAP
-  assert (info[DT_RUNPATH] == NULL);
-  assert (info[DT_RPATH] == NULL);
-#else
+#if ! defined RTLD_BOOTSTRAP && ! defined STATIC_PIE_BOOTSTRAP
   if (info[DT_FLAGS] != NULL)
     {
       /* Flags are used.  Translate to the old form where available.
diff --git a/iconv/Makefile b/iconv/Makefile
index 74cd9bf860..5f9104ee19 100644
--- a/iconv/Makefile
+++ b/iconv/Makefile
@@ -44,7 +44,7 @@ CFLAGS-linereader.c += -DNO_TRANSLITERATION
 CFLAGS-simple-hash.c += -I../locale
 
 tests	= tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 \
-	  tst-iconv7 tst-iconv-mt
+	  tst-iconv7 tst-iconv8 tst-iconv-mt
 
 others		= iconv_prog iconvconfig
 install-others-programs	= $(inst_bindir)/iconv
diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c
index 75ce8fb1f4..5902c28f0c 100644
--- a/iconv/gconv_simple.c
+++ b/iconv/gconv_simple.c
@@ -239,11 +239,9 @@ ucs4_internal_loop (struct __gconv_step *step,
   int flags = step_data->__flags;
   const unsigned char *inptr = *inptrp;
   unsigned char *outptr = *outptrp;
-  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
   int result;
-  size_t cnt;
 
-  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+  for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
     {
       uint32_t inval;
 
@@ -307,11 +305,9 @@ ucs4_internal_loop_unaligned (struct __gconv_step *step,
   int flags = step_data->__flags;
   const unsigned char *inptr = *inptrp;
   unsigned char *outptr = *outptrp;
-  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
   int result;
-  size_t cnt;
 
-  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+  for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
     {
       if (__glibc_unlikely (inptr[0] > 0x80))
 	{
@@ -613,11 +609,9 @@ ucs4le_internal_loop (struct __gconv_step *step,
   int flags = step_data->__flags;
   const unsigned char *inptr = *inptrp;
   unsigned char *outptr = *outptrp;
-  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
   int result;
-  size_t cnt;
 
-  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+  for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
     {
       uint32_t inval;
 
@@ -684,11 +678,9 @@ ucs4le_internal_loop_unaligned (struct __gconv_step *step,
   int flags = step_data->__flags;
   const unsigned char *inptr = *inptrp;
   unsigned char *outptr = *outptrp;
-  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
   int result;
-  size_t cnt;
 
-  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+  for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
     {
       if (__glibc_unlikely (inptr[3] > 0x80))
 	{
diff --git a/iconv/tst-iconv8.c b/iconv/tst-iconv8.c
new file mode 100644
index 0000000000..0b92b19f66
--- /dev/null
+++ b/iconv/tst-iconv8.c
@@ -0,0 +1,50 @@
+/* Test iconv behavior on UCS4 conversions with //IGNORE.
+   Copyright (C) 2020 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/>.  */
+
+/* Derived from BZ #26923 */
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  iconv_t cd = iconv_open ("UTF-8//IGNORE", "ISO-10646/UCS4/");
+  TEST_VERIFY_EXIT (cd != (iconv_t) -1);
+
+  /*
+   * Convert sequence beginning with an irreversible character into buffer that
+   * is too small.
+   */
+  char input[12] = "\xe1\x80\xa1" "AAAAAAAAA";
+  char *inptr = input;
+  size_t insize = sizeof (input);
+  char output[6];
+  char *outptr = output;
+  size_t outsize = sizeof (output);
+
+  TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == -1);
+  TEST_VERIFY (errno == E2BIG);
+
+  TEST_VERIFY_EXIT (iconv_close (cd) != -1);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/iconv/tst-iconv_prog.sh b/iconv/tst-iconv_prog.sh
new file mode 100644
index 0000000000..d8db7b335c
--- /dev/null
+++ b/iconv/tst-iconv_prog.sh
@@ -0,0 +1,284 @@
+#!/bin/bash
+# Test for some known iconv(1) hangs from bug 19519, and miscellaneous
+# iconv(1) program error conditions.
+# Copyright (C) 2020 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
+# <https://www.gnu.org/licenses/>.
+
+codir=$1
+test_wrapper_env="$2"
+run_program_env="$3"
+
+# We have to have some directories in the library path.
+LIBPATH=$codir:$codir/iconvdata
+
+# How the start the iconv(1) program.  $from is not defined/expanded yet.
+ICONV='
+$codir/elf/ld.so --library-path $LIBPATH --inhibit-rpath ${from}.so
+$codir/iconv/iconv_prog
+'
+ICONV="$test_wrapper_env $run_program_env $ICONV"
+
+# List of known hangs;
+# Gathered by running an exhaustive 2 byte input search against glibc-2.28
+hangarray=(
+"\x00\x23;-c;ANSI_X3.110;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa1;-c;ARMSCII-8;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa1;-c;ASMO_449;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;BIG5;UTF-8//TRANSLIT//IGNORE"
+"\x00\xff;-c;BIG5HKSCS;UTF-8//TRANSLIT//IGNORE"
+"\x00\xff;-c;BRF;UTF-8//TRANSLIT//IGNORE"
+"\x00\xff;-c;BS_4730;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1250;UTF-8//TRANSLIT//IGNORE"
+"\x00\x98;-c;CP1251;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1252;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1253;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1254;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1255;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1257;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1258;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;CP932;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;CSA_Z243.4-1985-1;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;CSA_Z243.4-1985-2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;DEC-MCS;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;DIN_66003;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;DS_2089;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-AT-DE;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-AT-DE-A;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-CA-FR;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-DK-NO;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-DK-NO-A;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-ES;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-ES-A;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-ES-S;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-FI-SE;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-FI-SE-A;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-FR;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-IS-FRISS;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-IT;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-PT;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-UK;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-US;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ES;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ES2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-CN;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-JISX0213;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-JP;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-JP-MS;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-KR;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-TW;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GB18030;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GB_1988-80;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GBK;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GOST_19768-74;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GREEK7;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GREEK7-OLD;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GREEK-CCITT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-GREEK8;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-ROMAN8;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-ROMAN9;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-THAI8;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-TURKISH8;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM038;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM1004;UTF-8//TRANSLIT//IGNORE"
+"\x00\xff;-c;IBM1008;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM1046;UTF-8//TRANSLIT//IGNORE"
+"\x00\x51;-c;IBM1132;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa0;-c;IBM1133;UTF-8//TRANSLIT//IGNORE"
+"\x00\xce;-c;IBM1137;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE"
+"\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE"
+"\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE"
+"\x00\x0f;-c;IBM1364;UTF-8"
+"\x0e\x0e;-c;IBM1364;UTF-8"
+"\x00\x0f;-c;IBM1371;UTF-8"
+"\x0e\x0e;-c;IBM1371;UTF-8"
+"\x00\x0f;-c;IBM1388;UTF-8"
+"\x0e\x0e;-c;IBM1388;UTF-8"
+"\x00\x0f;-c;IBM1390;UTF-8"
+"\x0e\x0e;-c;IBM1390;UTF-8"
+"\x00\x0f;-c;IBM1399;UTF-8"
+"\x0e\x0e;-c;IBM1399;UTF-8"
+"\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM281;UTF-8//TRANSLIT//IGNORE"
+"\x00\x57;-c;IBM290;UTF-8//TRANSLIT//IGNORE"
+"\x00\x45;-c;IBM420;UTF-8//TRANSLIT//IGNORE"
+"\x00\x68;-c;IBM423;UTF-8//TRANSLIT//IGNORE"
+"\x00\x70;-c;IBM424;UTF-8//TRANSLIT//IGNORE"
+"\x00\x53;-c;IBM4517;UTF-8//TRANSLIT//IGNORE"
+"\x00\x53;-c;IBM4899;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa5;-c;IBM4909;UTF-8//TRANSLIT//IGNORE"
+"\x00\xdc;-c;IBM4971;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM803;UTF-8//TRANSLIT//IGNORE"
+"\x00\x91;-c;IBM851;UTF-8//TRANSLIT//IGNORE"
+"\x00\x9b;-c;IBM856;UTF-8//TRANSLIT//IGNORE"
+"\x00\xd5;-c;IBM857;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM864;UTF-8//TRANSLIT//IGNORE"
+"\x00\x94;-c;IBM868;UTF-8//TRANSLIT//IGNORE"
+"\x00\x94;-c;IBM869;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM874;UTF-8//TRANSLIT//IGNORE"
+"\x00\x6a;-c;IBM875;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM880;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM891;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM903;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM904;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM905;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM9066;UTF-8//TRANSLIT//IGNORE"
+"\x00\x48;-c;IBM918;UTF-8//TRANSLIT//IGNORE"
+"\x00\x57;-c;IBM930;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM932;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM933;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM935;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM937;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM939;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM943;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;INIS;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;INIS-8;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;INIS-CYRILLIC;UTF-8//TRANSLIT//IGNORE"
+"\x00\xec;-c;ISIRI-3342;UTF-8//TRANSLIT//IGNORE"
+"\x00\xec;-c;ISO_10367-BOX;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-CN;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-CN-EXT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-JP;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-JP-2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-JP-3;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-KR;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO_2033;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO_5427;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO_5427-EXT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO_5428;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa4;-c;ISO_6937;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa0;-c;ISO_6937-2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-8859-11;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa5;-c;ISO-8859-3;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-8859-6;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-8859-7;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-8859-8;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;ISO-IR-197;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;ISO-IR-209;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IT;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;JIS_C6220-1969-RO;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;JIS_C6229-1984-B;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;JOHAB;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;JUS_I.B1.002;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;KOI-8;UTF-8//TRANSLIT//IGNORE"
+"\x00\x88;-c;KOI8-T;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;KSC5636;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;LATIN-GREEK;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;LATIN-GREEK-1;UTF-8//TRANSLIT//IGNORE"
+"\x00\xf6;-c;MAC-IS;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;MSZ_7795.3;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NATS-DANO;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NATS-SEFI;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NC_NC00-10;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NF_Z_62-010;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NF_Z_62-010_1973;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NS_4551-1;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NS_4551-2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;PT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;PT2;UTF-8//TRANSLIT//IGNORE"
+"\x00\x98;-c;RK1048;UTF-8//TRANSLIT//IGNORE"
+"\x00\x98;-c;SEN_850200_B;UTF-8//TRANSLIT//IGNORE"
+"\x00\x98;-c;SEN_850200_C;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;Shift_JISX0213;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;SJIS;UTF-8//TRANSLIT//IGNORE"
+"\x00\x23;-c;T.61-8BIT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;TIS-620;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;TSCII;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;UHC;UTF-8//TRANSLIT//IGNORE"
+"\x00\xd8;-c;UNICODE;UTF-8//TRANSLIT//IGNORE"
+"\x00\xdc;-c;UTF-16;UTF-8//TRANSLIT//IGNORE"
+"\xdc\x00;-c;UTF-16BE;UTF-8//TRANSLIT//IGNORE"
+"\x00\xdc;-c;UTF-16LE;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;UTF-7;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;WIN-SAMI-2;UTF-8//TRANSLIT//IGNORE"
+)
+
+# List of option combinations that *should* lead to an error
+errorarray=(
+# Converting from/to invalid character sets should cause error
+"\x00\x00;;INVALID;INVALID"
+"\x00\x00;;INVALID;UTF-8"
+"\x00\x00;;UTF-8;INVALID"
+)
+
+# Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret
+execute_test ()
+{
+  eval PROG=\"$ICONV\"
+  echo -en "$twobyte" \
+    | timeout -k 4 3 $PROG $c -f $from -t "$to" &>/dev/null
+  ret=$?
+}
+
+check_hangtest_result ()
+{
+  if [ "$ret" -eq "124" ] || [ "$ret" -eq "137" ]; then # timeout/hang
+    result="HANG"
+  else
+    if [ "$ret" -eq "139" ]; then # segfault
+      result="SEGFAULT"
+    else
+      if [ "$ret" -gt "127" ]; then # unexpected error
+        result="UNEXPECTED"
+      else
+        result="OK"
+      fi
+    fi
+  fi
+
+  echo -n "$result: from: \"$from\", to: \"$to\","
+  echo    " input \"$twobyte\", flags \"$c\""
+
+  if [ "$result" != "OK" ]; then
+    exit 1
+  fi
+}
+
+for hangcommand in "${hangarray[@]}"; do
+  twobyte="$(echo "$hangcommand" | cut -d";" -f 1)"
+  c="$(echo "$hangcommand" | cut -d";" -f 2)"
+  from="$(echo "$hangcommand" | cut -d";" -f 3)"
+  to="$(echo "$hangcommand" | cut -d";" -f 4)"
+  execute_test
+  check_hangtest_result
+done
+
+check_errtest_result ()
+{
+  if [ "$ret" -eq "1" ]; then # we errored out as expected
+    result="PASS"
+  else
+    result="FAIL"
+  fi
+  echo -n "$result: from: \"$from\", to: \"$to\","
+  echo    " input \"$twobyte\", flags \"$c\", return code $ret"
+
+  if [ "$result" != "PASS" ]; then
+    exit 1
+  fi
+}
+
+for errorcommand in "${errorarray[@]}"; do
+  twobyte="$(echo "$errorcommand" | cut -d";" -f 1)"
+  c="$(echo "$errorcommand" | cut -d";" -f 2)"
+  from="$(echo "$errorcommand" | cut -d";" -f 3)"
+  to="$(echo "$errorcommand" | cut -d";" -f 4)"
+  execute_test
+  check_errtest_result
+done
diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c
index 32ebe5a406..65d35871f1 100644
--- a/iconvdata/ibm1364.c
+++ b/iconvdata/ibm1364.c
@@ -158,24 +158,14 @@ enum
 									      \
     if (__builtin_expect (ch, 0) == SO)					      \
       {									      \
-	/* Shift OUT, change to DBCS converter.  */			      \
-	if (curcs == db)						      \
-	  {								      \
-	    result = __GCONV_ILLEGAL_INPUT;				      \
-	    break;							      \
-	  }								      \
+	/* Shift OUT, change to DBCS converter (redundant escape okay).  */   \
 	curcs = db;							      \
 	++inptr;							      \
 	continue;							      \
       }									      \
     if (__builtin_expect (ch, 0) == SI)					      \
       {									      \
-	/* Shift IN, change to SBCS converter.  */			      \
-	if (curcs == sb)						      \
-	  {								      \
-	    result = __GCONV_ILLEGAL_INPUT;				      \
-	    break;							      \
-	  }								      \
+	/* Shift IN, change to SBCS converter (redundant escape okay).  */    \
 	curcs = sb;							      \
 	++inptr;							      \
 	continue;							      \
diff --git a/sysdeps/powerpc/fpu/fedisblxcpt.c b/sysdeps/powerpc/fpu/fedisblxcpt.c
index 2872b1b21f..70dbc65a7e 100644
--- a/sysdeps/powerpc/fpu/fedisblxcpt.c
+++ b/sysdeps/powerpc/fpu/fedisblxcpt.c
@@ -26,32 +26,24 @@ fedisableexcept (int excepts)
   int result, new;
 
   /* Get current exception mask to return.  */
-  fe.fenv = curr.fenv = fegetenv_register ();
+  fe.fenv = curr.fenv = fegetenv_control ();
   result = fenv_reg_to_exceptions (fe.l);
 
   if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID)
     excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID;
 
+  new = fenv_exceptions_to_reg (excepts);
+
+  if (fenv_reg_to_exceptions (new) != excepts)
+    return -1;
+
   /* Sets the new exception mask.  */
-  if (excepts & FE_INEXACT)
-    fe.l &= ~(1 << (31 - FPSCR_XE));
-  if (excepts & FE_DIVBYZERO)
-    fe.l &= ~(1 << (31 - FPSCR_ZE));
-  if (excepts & FE_UNDERFLOW)
-    fe.l &= ~(1 << (31 - FPSCR_UE));
-  if (excepts & FE_OVERFLOW)
-    fe.l &= ~(1 << (31 - FPSCR_OE));
-  if (excepts & FE_INVALID)
-    fe.l &= ~(1 << (31 - FPSCR_VE));
+  fe.l &= ~new;
 
   if (fe.l != curr.l)
-    fesetenv_register (fe.fenv);
+    fesetenv_control (fe.fenv);
 
-  new = __fegetexcept ();
-  if (new == 0 && result != 0)
-    (void)__fe_mask_env ();
+  __TEST_AND_ENTER_NON_STOP (-1ULL, fe.l);
 
-  if ((new & excepts) != 0)
-    result = -1;
   return result;
 }
diff --git a/sysdeps/powerpc/fpu/feenablxcpt.c b/sysdeps/powerpc/fpu/feenablxcpt.c
index dbaffdc05c..8be82a0f58 100644
--- a/sysdeps/powerpc/fpu/feenablxcpt.c
+++ b/sysdeps/powerpc/fpu/feenablxcpt.c
@@ -26,33 +26,24 @@ feenableexcept (int excepts)
   int result, new;
 
   /* Get current exception mask to return.  */
-  fe.fenv = curr.fenv = fegetenv_register ();
+  fe.fenv = curr.fenv = fegetenv_control ();
   result = fenv_reg_to_exceptions (fe.l);
 
   if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID)
     excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID;
 
+  new = fenv_exceptions_to_reg (excepts);
+
+  if (fenv_reg_to_exceptions (new) != excepts)
+    return -1;
+
   /* Sets the new exception mask.  */
-  if (excepts & FE_INEXACT)
-    fe.l |= (1 << (31 - FPSCR_XE));
-  if (excepts & FE_DIVBYZERO)
-    fe.l |= (1 << (31 - FPSCR_ZE));
-  if (excepts & FE_UNDERFLOW)
-    fe.l |= (1 << (31 - FPSCR_UE));
-  if (excepts & FE_OVERFLOW)
-    fe.l |= (1 << (31 - FPSCR_OE));
-  if (excepts & FE_INVALID)
-    fe.l |= (1 << (31 - FPSCR_VE));
+  fe.l |= new;
 
   if (fe.l != curr.l)
-    fesetenv_register (fe.fenv);
-
-  new = __fegetexcept ();
-  if (new != 0 && result == 0)
-    (void) __fe_nomask_env_priv ();
+    fesetenv_control (fe.fenv);
 
-  if ((new & excepts) != excepts)
-    result = -1;
+  __TEST_AND_EXIT_NON_STOP (0ULL, fe.l);
 
   return result;
 }
diff --git a/sysdeps/powerpc/fpu/fegetexcept.c b/sysdeps/powerpc/fpu/fegetexcept.c
index 10a37f0d44..68a67b907e 100644
--- a/sysdeps/powerpc/fpu/fegetexcept.c
+++ b/sysdeps/powerpc/fpu/fegetexcept.c
@@ -24,7 +24,7 @@ __fegetexcept (void)
 {
   fenv_union_t fe;
 
-  fe.fenv = fegetenv_status ();
+  fe.fenv = fegetenv_control ();
 
   return fenv_reg_to_exceptions (fe.l);
 }
diff --git a/sysdeps/powerpc/fpu/fegetmode.c b/sysdeps/powerpc/fpu/fegetmode.c
index 466f5b7098..0483128bfd 100644
--- a/sysdeps/powerpc/fpu/fegetmode.c
+++ b/sysdeps/powerpc/fpu/fegetmode.c
@@ -21,6 +21,6 @@
 int
 fegetmode (femode_t *modep)
 {
-  *modep = fegetenv_status ();
+  *modep = fegetenv_control ();
   return 0;
 }
diff --git a/sysdeps/powerpc/fpu/feholdexcpt.c b/sysdeps/powerpc/fpu/feholdexcpt.c
index b16d480e45..f105c7b8aa 100644
--- a/sysdeps/powerpc/fpu/feholdexcpt.c
+++ b/sysdeps/powerpc/fpu/feholdexcpt.c
@@ -18,7 +18,6 @@
 
 #include <fenv_libc.h>
 #include <fpu_control.h>
-#define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM | _FPU_MASK_XM | _FPU_MASK_IM)
 
 int
 __feholdexcept (fenv_t *envp)
@@ -35,11 +34,7 @@ __feholdexcept (fenv_t *envp)
   if (new.l == old.l)
     return 0;
 
-  /* If the old env had any enabled exceptions, then mask SIGFPE in the
-     MSR FE0/FE1 bits.  This may allow the FPU to run faster because it
-     always takes the default action and can not generate SIGFPE. */
-  if ((old.l & _FPU_MASK_ALL) != 0)
-    (void)__fe_mask_env ();
+  __TEST_AND_ENTER_NON_STOP (old.l, 0ULL);
 
   /* Put the new state in effect.  */
   fesetenv_register (new.fenv);
diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h
index 9861f18efd..df38487a55 100644
--- a/sysdeps/powerpc/fpu/fenv_libc.h
+++ b/sysdeps/powerpc/fpu/fenv_libc.h
@@ -27,6 +27,26 @@ extern const fenv_t *__fe_nomask_env_priv (void);
 
 extern const fenv_t *__fe_mask_env (void) attribute_hidden;
 
+/* If the old env had any enabled exceptions and the new env has no enabled
+   exceptions, then mask SIGFPE in the MSR FE0/FE1 bits.  This may allow the
+   FPU to run faster because it always takes the default action and can not
+   generate SIGFPE.  */
+#define __TEST_AND_ENTER_NON_STOP(old, new) \
+  do { \
+    if (((old) & FPSCR_ENABLES_MASK) != 0 && ((new) & FPSCR_ENABLES_MASK) == 0) \
+      (void) __fe_mask_env (); \
+  } while (0)
+
+/* If the old env has no enabled exceptions and the new env has any enabled
+   exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits.  This will put the
+   hardware into "precise mode" and may cause the FPU to run slower on some
+   hardware.  */
+#define __TEST_AND_EXIT_NON_STOP(old, new) \
+  do { \
+    if (((old) & FPSCR_ENABLES_MASK) == 0 && ((new) & FPSCR_ENABLES_MASK) != 0) \
+      (void) __fe_nomask_env_priv (); \
+  } while (0)
+
 /* The sticky bits in the FPSCR indicating exceptions have occurred.  */
 #define FPSCR_STICKY_BITS ((FE_ALL_EXCEPT | FE_ALL_INVALID) & ~FE_INVALID)
 
@@ -35,9 +55,12 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden;
 #define fegetenv_register() __builtin_mffs()
 
 /* Equivalent to fegetenv_register, but only returns bits for
-   status, exception enables, and mode.  */
-
-#define fegetenv_status_ISA300()					\
+   status, exception enables, and mode.
+   Nicely, it turns out that the 'mffsl' instruction will decode to
+   'mffs' on architectures older than "power9" because the additional
+   bits set for 'mffsl' are "don't care" for 'mffs'.  'mffs' is a superset
+   of 'mffsl'.  */
+#define fegetenv_control()					\
   ({register double __fr;						\
     __asm__ __volatile__ (						\
       ".machine push; .machine \"power9\"; mffsl %0; .machine pop"	\
@@ -45,16 +68,36 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden;
     __fr;								\
   })
 
+#define __fe_mffscrn(rn)						\
+  ({register fenv_union_t __fr;						\
+    if (__builtin_constant_p (rn))					\
+      __asm__ __volatile__ (						\
+        ".machine push; .machine \"power9\"; mffscrni %0,%1; .machine pop" \
+        : "=f" (__fr.fenv) : "i" (rn));					\
+    else								\
+    {									\
+      __fr.l = (rn);							\
+      __asm__ __volatile__ (						\
+        ".machine push; .machine \"power9\"; mffscrn %0,%1; .machine pop" \
+        : "=f" (__fr.fenv) : "f" (__fr.fenv));				\
+    }									\
+    __fr.fenv;								\
+  })
+
+/* Like fegetenv_control, but also sets the rounding mode.  */
 #ifdef _ARCH_PWR9
-# define fegetenv_status() fegetenv_status_ISA300()
-#elif defined __BUILTIN_CPU_SUPPORTS__
-# define fegetenv_status()						\
-  (__glibc_likely (__builtin_cpu_supports ("arch_3_00"))		\
-   ? fegetenv_status_ISA300()						\
-   : fegetenv_register()						\
-  )
+#define fegetenv_and_set_rn(rn) __fe_mffscrn (rn)
 #else
-# define fegetenv_status() fegetenv_register ()
+/* 'mffscrn' will decode to 'mffs' on ARCH < 3_00, which is still necessary
+   but not sufficient, because it does not set the rounding mode.
+   Explicitly set the rounding mode when 'mffscrn' actually doesn't.  */
+#define fegetenv_and_set_rn(rn)						\
+  ({register fenv_union_t __fr;						\
+    __fr.fenv = __fe_mffscrn (rn);					\
+    if (__glibc_unlikely (!(GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00)))	\
+      __fesetround_inline (rn);						\
+    __fr.fenv;								\
+  })
 #endif
 
 /* Equivalent to fesetenv, but takes a fenv_t instead of a pointer.  */
@@ -70,6 +113,11 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden;
 	    __builtin_mtfsf (0xff, d); \
 	} while(0)
 
+/* Set the last 2 nibbles of the FPSCR, which contain the
+   exception enables and the rounding mode.
+   'fegetenv_control' retrieves these bits by reading the FPSCR.  */
+#define fesetenv_control(env) __builtin_mtfsf (0b00000011, (env));
+
 /* This very handy macro:
    - Sets the rounding mode to 'round to nearest';
    - Sets the processor into IEEE mode; and
@@ -100,7 +148,12 @@ typedef union
 static inline int
 __fesetround_inline (int round)
 {
-  if ((unsigned int) round < 2)
+#ifdef _ARCH_PWR9
+  __fe_mffscrn (round);
+#else
+  if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))
+    __fe_mffscrn (round);
+  else if ((unsigned int) round < 2)
     {
        asm volatile ("mtfsb0 30");
        if ((unsigned int) round == 0)
@@ -116,7 +169,7 @@ __fesetround_inline (int round)
        else
          asm volatile ("mtfsb1 31");
     }
-
+#endif
   return 0;
 }
 
@@ -125,63 +178,125 @@ __fesetround_inline (int round)
 static inline void
 __fesetround_inline_nocheck (const int round)
 {
-  asm volatile ("mtfsfi 7,%0" : : "i" (round));
+#ifdef _ARCH_PWR9
+  __fe_mffscrn (round);
+#else
+  if (__glibc_likely (GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))
+    __fe_mffscrn (round);
+  else
+    asm volatile ("mtfsfi 7,%0" : : "i" (round));
+#endif
 }
 
+#define FPSCR_MASK(bit) (1 << (31 - (bit)))
+
 /* Definitions of all the FPSCR bit numbers */
 enum {
   FPSCR_FX = 0,    /* exception summary */
+#define FPSCR_FX_MASK (FPSCR_MASK (FPSCR_FX))
   FPSCR_FEX,       /* enabled exception summary */
+#define FPSCR_FEX_MASK (FPSCR_MASK FPSCR_FEX))
   FPSCR_VX,        /* invalid operation summary */
+#define FPSCR_VX_MASK (FPSCR_MASK (FPSCR_VX))
   FPSCR_OX,        /* overflow */
+#define FPSCR_OX_MASK (FPSCR_MASK (FPSCR_OX))
   FPSCR_UX,        /* underflow */
+#define FPSCR_UX_MASK (FPSCR_MASK (FPSCR_UX))
   FPSCR_ZX,        /* zero divide */
+#define FPSCR_ZX_MASK (FPSCR_MASK (FPSCR_ZX))
   FPSCR_XX,        /* inexact */
+#define FPSCR_XX_MASK (FPSCR_MASK (FPSCR_XX))
   FPSCR_VXSNAN,    /* invalid operation for sNaN */
+#define FPSCR_VXSNAN_MASK (FPSCR_MASK (FPSCR_VXSNAN))
   FPSCR_VXISI,     /* invalid operation for Inf-Inf */
+#define FPSCR_VXISI_MASK (FPSCR_MASK (FPSCR_VXISI))
   FPSCR_VXIDI,     /* invalid operation for Inf/Inf */
+#define FPSCR_VXIDI_MASK (FPSCR_MASK (FPSCR_VXIDI))
   FPSCR_VXZDZ,     /* invalid operation for 0/0 */
+#define FPSCR_VXZDZ_MASK (FPSCR_MASK (FPSCR_VXZDZ))
   FPSCR_VXIMZ,     /* invalid operation for Inf*0 */
+#define FPSCR_VXIMZ_MASK (FPSCR_MASK (FPSCR_VXIMZ))
   FPSCR_VXVC,      /* invalid operation for invalid compare */
+#define FPSCR_VXVC_MASK (FPSCR_MASK (FPSCR_VXVC))
   FPSCR_FR,        /* fraction rounded [fraction was incremented by round] */
+#define FPSCR_FR_MASK (FPSCR_MASK (FPSCR_FR))
   FPSCR_FI,        /* fraction inexact */
+#define FPSCR_FI_MASK (FPSCR_MASK (FPSCR_FI))
   FPSCR_FPRF_C,    /* result class descriptor */
+#define FPSCR_FPRF_C_MASK (FPSCR_MASK (FPSCR_FPRF_C))
   FPSCR_FPRF_FL,   /* result less than (usually, less than 0) */
+#define FPSCR_FPRF_FL_MASK (FPSCR_MASK (FPSCR_FPRF_FL))
   FPSCR_FPRF_FG,   /* result greater than */
+#define FPSCR_FPRF_FG_MASK (FPSCR_MASK (FPSCR_FPRF_FG))
   FPSCR_FPRF_FE,   /* result equal to */
+#define FPSCR_FPRF_FE_MASK (FPSCR_MASK (FPSCR_FPRF_FE))
   FPSCR_FPRF_FU,   /* result unordered */
+#define FPSCR_FPRF_FU_MASK (FPSCR_MASK (FPSCR_FPRF_FU))
   FPSCR_20,        /* reserved */
   FPSCR_VXSOFT,    /* invalid operation set by software */
+#define FPSCR_VXSOFT_MASK (FPSCR_MASK (FPSCR_VXSOFT))
   FPSCR_VXSQRT,    /* invalid operation for square root */
+#define FPSCR_VXSQRT_MASK (FPSCR_MASK (FPSCR_VXSQRT))
   FPSCR_VXCVI,     /* invalid operation for invalid integer convert */
+#define FPSCR_VXCVI_MASK (FPSCR_MASK (FPSCR_VXCVI))
   FPSCR_VE,        /* invalid operation exception enable */
+#define FPSCR_VE_MASK (FPSCR_MASK (FPSCR_VE))
   FPSCR_OE,        /* overflow exception enable */
+#define FPSCR_OE_MASK (FPSCR_MASK (FPSCR_OE))
   FPSCR_UE,        /* underflow exception enable */
+#define FPSCR_UE_MASK (FPSCR_MASK (FPSCR_UE))
   FPSCR_ZE,        /* zero divide exception enable */
+#define FPSCR_ZE_MASK (FPSCR_MASK (FPSCR_ZE))
   FPSCR_XE,        /* inexact exception enable */
+#define FPSCR_XE_MASK (FPSCR_MASK (FPSCR_XE))
 #ifdef _ARCH_PWR6
   FPSCR_29,        /* Reserved in ISA 2.05  */
+#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_29))
 #else
-  FPSCR_NI         /* non-IEEE mode (typically, no denormalised numbers) */
+  FPSCR_NI,        /* non-IEEE mode (typically, no denormalised numbers) */
+#define FPSCR_NI_MASK (FPSCR_MASK (FPSCR_NI))
 #endif /* _ARCH_PWR6 */
   /* the remaining two least-significant bits keep the rounding mode */
+  FPSCR_RN_hi,
+#define FPSCR_RN_hi_MASK (FPSCR_MASK (FPSCR_RN_hi))
+  FPSCR_RN_lo
+#define FPSCR_RN_lo_MASK (FPSCR_MASK (FPSCR_RN_lo))
 };
 
+#define FPSCR_RN_MASK (FPSCR_RN_hi_MASK|FPSCR_RN_lo_MASK)
+#define FPSCR_ENABLES_MASK \
+  (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK)
+#define FPSCR_BASIC_EXCEPTIONS_MASK \
+  (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK)
+#define FPSCR_EXCEPTIONS_MASK (FPSCR_BASIC_EXCEPTIONS_MASK| \
+  FPSCR_VXSNAN_MASK|FPSCR_VXISI_MASK|FPSCR_VXIDI_MASK|FPSCR_VXZDZ_MASK| \
+  FPSCR_VXIMZ_MASK|FPSCR_VXVC_MASK|FPSCR_VXSOFT_MASK|FPSCR_VXSQRT_MASK| \
+  FPSCR_VXCVI_MASK)
+#define FPSCR_FPRF_MASK \
+  (FPSCR_FPRF_C_MASK|FPSCR_FPRF_FL_MASK|FPSCR_FPRF_FG_MASK| \
+   FPSCR_FPRF_FE_MASK|FPSCR_FPRF_FU_MASK)
+#define FPSCR_CONTROL_MASK (FPSCR_ENABLES_MASK|FPSCR_NI_MASK|FPSCR_RN_MASK)
+#define FPSCR_STATUS_MASK (FPSCR_FR_MASK|FPSCR_FI_MASK|FPSCR_FPRF_MASK)
+
+/* The bits in the FENV(1) ABI for exceptions correspond one-to-one with bits
+   in the FPSCR, albeit shifted to different but corresponding locations.
+   Similarly, the exception indicator bits in the FPSCR correspond one-to-one
+   with the exception enable bits. It is thus possible to map the FENV(1)
+   exceptions directly to the FPSCR enables with a simple mask and shift,
+   and vice versa. */
+#define FPSCR_EXCEPT_TO_ENABLE_SHIFT 22
+
 static inline int
 fenv_reg_to_exceptions (unsigned long long l)
 {
-  int result = 0;
-  if (l & (1 << (31 - FPSCR_XE)))
-    result |= FE_INEXACT;
-  if (l & (1 << (31 - FPSCR_ZE)))
-    result |= FE_DIVBYZERO;
-  if (l & (1 << (31 - FPSCR_UE)))
-    result |= FE_UNDERFLOW;
-  if (l & (1 << (31 - FPSCR_OE)))
-    result |= FE_OVERFLOW;
-  if (l & (1 << (31 - FPSCR_VE)))
-    result |= FE_INVALID;
-  return result;
+  return (((int)l) & FPSCR_ENABLES_MASK) << FPSCR_EXCEPT_TO_ENABLE_SHIFT;
+}
+
+static inline unsigned long long
+fenv_exceptions_to_reg (int excepts)
+{
+  return (unsigned long long)
+    (excepts & FE_ALL_EXCEPT) >> FPSCR_EXCEPT_TO_ENABLE_SHIFT;
 }
 
 #ifdef _ARCH_PWR6
diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h
index 8c126f9101..0eb1b08da7 100644
--- a/sysdeps/powerpc/fpu/fenv_private.h
+++ b/sysdeps/powerpc/fpu/fenv_private.h
@@ -23,73 +23,31 @@
 #include <fenv_libc.h>
 #include <fpu_control.h>
 
-/* Mask for the exception enable bits.  */
-#define _FPU_ALL_TRAPS (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM \
-                      | _FPU_MASK_XM | _FPU_MASK_IM)
-
-/* Mask the rounding mode bits.  */
-#define _FPU_MASK_RN 0xfffffffffffffffcLL
-
-/* Mask everything but the rounding modes and non-IEEE arithmetic flags.  */
-#define _FPU_MASK_NOT_RN_NI 0xffffffff00000807LL
-
-/* Mask restore rounding mode and exception enabled.  */
-#define _FPU_MASK_TRAPS_RN 0xffffffffffffff00LL
-
-/* Mask FP result flags, preserve fraction rounded/inexact bits.  */
-#define _FPU_MASK_FRAC_INEX_RET_CC 0xfffffffffff80fffLL
+#ifdef _ARCH_PWR8
+/* There is no performance advantage to non-stop mode.  */
+/* The odd syntax here is to innocuously reference the given variables
+   to prevent warnings about unused variables.  */
+#define __TEST_AND_BEGIN_NON_STOP(old, new) do {} while ((old) * (new) * 0 != 0)
+#define __TEST_AND_END_NON_STOP(old, new) do {} while ((old) * (new) * 0 != 0)
+#else
+#define __TEST_AND_BEGIN_NON_STOP __TEST_AND_ENTER_NON_STOP
+#define __TEST_AND_END_NON_STOP __TEST_AND_EXIT_NON_STOP
+#endif
 
 static __always_inline void
-__libc_feholdbits_ppc (fenv_t *envp, unsigned long long mask,
-	unsigned long long bits)
+libc_feholdexcept_setround_ppc (fenv_t *envp, int r)
 {
   fenv_union_t old, new;
 
   old.fenv = *envp = fegetenv_register ();
 
-  new.l = (old.l & mask) | bits;
-
-  /* If the old env had any enabled exceptions, then mask SIGFPE in the
-     MSR FE0/FE1 bits.  This may allow the FPU to run faster because it
-     always takes the default action and can not generate SIGFPE.  */
-  if ((old.l & _FPU_ALL_TRAPS) != 0)
-    (void) __fe_mask_env ();
+  __TEST_AND_BEGIN_NON_STOP (old.l, 0ULL);
 
+  /* Clear everything and set the rounding mode.  */
+  new.l = r;
   fesetenv_register (new.fenv);
 }
 
-static __always_inline void
-libc_feholdexcept_ppc (fenv_t *envp)
-{
-  __libc_feholdbits_ppc (envp, _FPU_MASK_NOT_RN_NI, 0LL);
-}
-
-static __always_inline void
-libc_feholdexcept_setround_ppc (fenv_t *envp, int r)
-{
-  __libc_feholdbits_ppc (envp, _FPU_MASK_NOT_RN_NI & _FPU_MASK_RN, r);
-}
-
-static __always_inline void
-libc_fesetround_ppc (int r)
-{
-  __fesetround_inline (r);
-}
-
-static __always_inline int
-libc_fetestexcept_ppc (int e)
-{
-  fenv_union_t u;
-  u.fenv = fegetenv_register ();
-  return u.l & e;
-}
-
-static __always_inline void
-libc_feholdsetround_ppc (fenv_t *e, int r)
-{
-  __libc_feholdbits_ppc (e, _FPU_MASK_TRAPS_RN, r);
-}
-
 static __always_inline unsigned long long
 __libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask,
 	unsigned long long new_mask)
@@ -102,22 +60,23 @@ __libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask,
   /* Merge bits while masking unwanted bits from new and old env.  */
   new.l = (old.l & old_mask) | (new.l & new_mask);
 
-  /* If the old env has no enabled exceptions and the new env has any enabled
-     exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits.  This will put the
-     hardware into "precise mode" and may cause the FPU to run slower on some
-     hardware.  */
-  if ((old.l & _FPU_ALL_TRAPS) == 0 && (new.l & _FPU_ALL_TRAPS) != 0)
-    (void) __fe_nomask_env_priv ();
-
-  /* If the old env had any enabled exceptions and the new env has no enabled
-     exceptions, then mask SIGFPE in the MSR FE0/FE1 bits.  This may allow the
-     FPU to run faster because it always takes the default action and can not
-     generate SIGFPE.  */
-  if ((old.l & _FPU_ALL_TRAPS) != 0 && (new.l & _FPU_ALL_TRAPS) == 0)
-    (void) __fe_mask_env ();
-
-  /* Atomically enable and raise (if appropriate) exceptions set in `new'.  */
-  fesetenv_register (new.fenv);
+  __TEST_AND_END_NON_STOP (old.l, new.l);
+  __TEST_AND_BEGIN_NON_STOP (old.l, new.l);
+
+  /* If requesting to keep status, replace control, and merge exceptions,
+     and exceptions haven't changed, we can just set new control instead
+     of the whole FPSCR.  */
+  if ((old_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK))
+      == (FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK) &&
+      (new_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK))
+      == (FPSCR_CONTROL_MASK|FPSCR_EXCEPTIONS_MASK) &&
+      (old.l & FPSCR_EXCEPTIONS_MASK) == (new.l & FPSCR_EXCEPTIONS_MASK))
+  {
+    fesetenv_control (new.fenv);
+  }
+  else
+    /* Atomically enable and raise (if appropriate) exceptions set in `new'.  */
+    fesetenv_register (new.fenv);
 
   return old.l;
 }
@@ -132,14 +91,15 @@ libc_fesetenv_ppc (const fenv_t *envp)
 static __always_inline void
 libc_feresetround_ppc (fenv_t *envp)
 {
-  __libc_femergeenv_ppc (envp, _FPU_MASK_TRAPS_RN, _FPU_MASK_FRAC_INEX_RET_CC);
+  fenv_union_t new = { .fenv = *envp };
+  fegetenv_and_set_rn (new.l & FPSCR_RN_MASK);
 }
 
 static __always_inline int
 libc_feupdateenv_test_ppc (fenv_t *envp, int ex)
 {
-  return __libc_femergeenv_ppc (envp, _FPU_MASK_TRAPS_RN,
-				_FPU_MASK_FRAC_INEX_RET_CC) & ex;
+  return __libc_femergeenv_ppc (envp, ~FPSCR_CONTROL_MASK,
+				~FPSCR_STATUS_MASK) & ex;
 }
 
 static __always_inline void
@@ -174,18 +134,26 @@ libc_feupdateenv_ppc (fenv_t *e)
 static __always_inline void
 libc_feholdsetround_ppc_ctx (struct rm_ctx *ctx, int r)
 {
+  fenv_union_t old;
+
+  ctx->env = old.fenv = fegetenv_and_set_rn (r);
+  ctx->updated_status = (r != (old.l & FPSCR_RN_MASK));
+}
+
+static __always_inline void
+libc_feholdsetround_noex_ppc_ctx (struct rm_ctx *ctx, int r)
+{
   fenv_union_t old, new;
 
   old.fenv = fegetenv_register ();
 
-  new.l = (old.l & _FPU_MASK_TRAPS_RN) | r;
+  new.l = (old.l & ~(FPSCR_ENABLES_MASK|FPSCR_RN_MASK)) | r;
 
   ctx->env = old.fenv;
   if (__glibc_unlikely (new.l != old.l))
     {
-      if ((old.l & _FPU_ALL_TRAPS) != 0)
-	(void) __fe_mask_env ();
-      fesetenv_register (new.fenv);
+      __TEST_AND_BEGIN_NON_STOP (old.l, 0ULL);
+      fesetenv_control (new.fenv);
       ctx->updated_status = true;
     }
   else
@@ -218,6 +186,9 @@ libc_feresetround_ppc_ctx (struct rm_ctx *ctx)
 #define libc_feholdsetround_ctx          libc_feholdsetround_ppc_ctx
 #define libc_feholdsetroundf_ctx         libc_feholdsetround_ppc_ctx
 #define libc_feholdsetroundl_ctx         libc_feholdsetround_ppc_ctx
+#define libc_feholdsetround_noex_ctx     libc_feholdsetround_noex_ppc_ctx
+#define libc_feholdsetround_noexf_ctx    libc_feholdsetround_noex_ppc_ctx
+#define libc_feholdsetround_noexl_ctx    libc_feholdsetround_noex_ppc_ctx
 #define libc_feresetround_ctx            libc_feresetround_ppc_ctx
 #define libc_feresetroundf_ctx           libc_feresetround_ppc_ctx
 #define libc_feresetroundl_ctx           libc_feresetround_ppc_ctx
diff --git a/sysdeps/powerpc/fpu/fesetenv.c b/sysdeps/powerpc/fpu/fesetenv.c
index 009a4f025e..7e0176b65e 100644
--- a/sysdeps/powerpc/fpu/fesetenv.c
+++ b/sysdeps/powerpc/fpu/fesetenv.c
@@ -19,8 +19,6 @@
 #include <fenv_libc.h>
 #include <fpu_control.h>
 
-#define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM | _FPU_MASK_XM | _FPU_MASK_IM)
-
 int
 __fesetenv (const fenv_t *envp)
 {
@@ -28,25 +26,12 @@ __fesetenv (const fenv_t *envp)
 
   /* get the currently set exceptions.  */
   new.fenv = *envp;
-  old.fenv = fegetenv_register ();
-  if (old.l == new.l)
-    return 0;
-
-  /* If the old env has no enabled exceptions and the new env has any enabled
-     exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits.  This will put the
-     hardware into "precise mode" and may cause the FPU to run slower on some
-     hardware.  */
-  if ((old.l & _FPU_MASK_ALL) == 0 && (new.l & _FPU_MASK_ALL) != 0)
-    (void) __fe_nomask_env_priv ();
-
-  /* If the old env had any enabled exceptions and the new env has no enabled
-     exceptions, then mask SIGFPE in the MSR FE0/FE1 bits.  This may allow the
-     FPU to run faster because it always takes the default action and can not
-     generate SIGFPE. */
-  if ((old.l & _FPU_MASK_ALL) != 0 && (new.l & _FPU_MASK_ALL) == 0)
-    (void)__fe_mask_env ();
-
-  fesetenv_register (*envp);
+  old.fenv = fegetenv_control ();
+
+  __TEST_AND_EXIT_NON_STOP (old.l, new.l);
+  __TEST_AND_ENTER_NON_STOP (old.l, new.l);
+
+  fesetenv_register (new.fenv);
 
   /* Success.  */
   return 0;
diff --git a/sysdeps/powerpc/fpu/fesetmode.c b/sysdeps/powerpc/fpu/fesetmode.c
index 4f4f71a3ba..72acdaf5eb 100644
--- a/sysdeps/powerpc/fpu/fesetmode.c
+++ b/sysdeps/powerpc/fpu/fesetmode.c
@@ -19,11 +19,6 @@
 #include <fenv_libc.h>
 #include <fpu_control.h>
 
-#define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM	\
-		       | _FPU_MASK_XM | _FPU_MASK_IM)
-
-#define FPU_STATUS 0xbffff700ULL
-
 int
 fesetmode (const femode_t *modep)
 {
@@ -32,18 +27,15 @@ fesetmode (const femode_t *modep)
   /* Logic regarding enabled exceptions as in fesetenv.  */
 
   new.fenv = *modep;
-  old.fenv = fegetenv_register ();
-  new.l = (new.l & ~FPU_STATUS) | (old.l & FPU_STATUS);
+  old.fenv = fegetenv_control ();
+  new.l = (new.l & ~FPSCR_STATUS_MASK) | (old.l & FPSCR_STATUS_MASK);
 
   if (old.l == new.l)
     return 0;
 
-  if ((old.l & _FPU_MASK_ALL) == 0 && (new.l & _FPU_MASK_ALL) != 0)
-    (void) __fe_nomask_env_priv ();
-
-  if ((old.l & _FPU_MASK_ALL) != 0 && (new.l & _FPU_MASK_ALL) == 0)
-    (void) __fe_mask_env ();
+  __TEST_AND_EXIT_NON_STOP (old.l, new.l);
+  __TEST_AND_ENTER_NON_STOP (old.l, new.l);
 
-  fesetenv_register (new.fenv);
+  fesetenv_control (new.fenv);
   return 0;
 }
diff --git a/sysdeps/powerpc/fpu/feupdateenv.c b/sysdeps/powerpc/fpu/feupdateenv.c
index 39b08e7406..ff4d902038 100644
--- a/sysdeps/powerpc/fpu/feupdateenv.c
+++ b/sysdeps/powerpc/fpu/feupdateenv.c
@@ -20,8 +20,6 @@
 #include <fenv_libc.h>
 #include <fpu_control.h>
 
-#define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM | _FPU_MASK_XM | _FPU_MASK_IM)
-
 int
 __feupdateenv (const fenv_t *envp)
 {
@@ -36,19 +34,8 @@ __feupdateenv (const fenv_t *envp)
      unchanged.  */
   new.l = (old.l & 0xffffffff1fffff00LL) | (new.l & 0x1ff80fff);
 
-  /* If the old env has no enabled exceptions and the new env has any enabled
-     exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits.  This will put
-     the hardware into "precise mode" and may cause the FPU to run slower on
-     some hardware.  */
-  if ((old.l & _FPU_MASK_ALL) == 0 && (new.l & _FPU_MASK_ALL) != 0)
-    (void) __fe_nomask_env_priv ();
-
-  /* If the old env had any enabled exceptions and the new env has no enabled
-     exceptions, then mask SIGFPE in the MSR FE0/FE1 bits.  This may allow the
-     FPU to run faster because it always takes the default action and can not
-     generate SIGFPE. */
-  if ((old.l & _FPU_MASK_ALL) != 0 && (new.l & _FPU_MASK_ALL) == 0)
-    (void)__fe_mask_env ();
+  __TEST_AND_EXIT_NON_STOP (old.l, new.l);
+  __TEST_AND_ENTER_NON_STOP (old.l, new.l);
 
   /* Atomically enable and raise (if appropriate) exceptions set in `new'. */
   fesetenv_register (new.fenv);