+diff -pruN glibc-2.12-2-gc4ccff1/math/math_private.h glibc-2.12-2-gc4ccff1.new/math/math_private.h
+--- glibc-2.12-2-gc4ccff1/math/math_private.h 2013-06-07 08:35:52.785442441 -0400
++++ glibc-2.12-2-gc4ccff1.new/math/math_private.h 2013-06-07 08:29:35.621042340 -0400
+@@ -394,4 +394,31 @@ extern void __docos (double __x, double
+ #define libc_feupdateenvf(e) (void) feupdateenv (e)
+ #define libc_feupdateenvl(e) (void) feupdateenv (e)
+
++/* Save and set the rounding mode. The use of fenv_t to store the old mode
++ allows a target-specific version of this function to avoid converting the
++ rounding mode from the fpu format. By default we have no choice but to
++ manipulate the entire env. */
++
++#ifndef libc_feholdsetround
++# define libc_feholdsetround(e, r, c) libc_feholdexcept_setround(e, r)
++#endif
++#ifndef libc_feholdsetroundf
++# define libc_feholdsetroundf(e, r, c) libc_feholdexcept_setroundf(e, r)
++#endif
++#ifndef libc_feholdsetroundl
++# define libc_feholdsetroundl(e, r, c) libc_feholdexcept_setroundl(e, r)
++#endif
++
++/* ... and the reverse. */
++
++#ifndef libc_feresetround
++# define libc_feresetround(e, c) libc_feupdateenv(e)
++#endif
++#ifndef libc_feresetroundf
++# define libc_feresetroundf(e, c) libc_feupdateenvf(e)
++#endif
++#ifndef libc_feresetroundl
++# define libc_feresetroundl(e, c) libc_feupdateenvl(e)
++#endif
++
+ #endif /* _MATH_PRIVATE_H_ */
+diff -pruN glibc-2.12-2-gc4ccff1/sysdeps/ieee754/dbl-64/e_exp.c glibc-2.12-2-gc4ccff1.new/sysdeps/ieee754/dbl-64/e_exp.c
+--- glibc-2.12-2-gc4ccff1/sysdeps/ieee754/dbl-64/e_exp.c 2013-06-07 08:35:52.785442441 -0400
++++ glibc-2.12-2-gc4ccff1.new/sysdeps/ieee754/dbl-64/e_exp.c 2013-06-07 08:30:21.976222459 -0400
+@@ -57,7 +57,8 @@ double __ieee754_exp(double x) {
+ fenv_t env;
+ double retval;
+
+- libc_feholdexcept_setround (&env, FE_TONEAREST);
++ int changed;
++ libc_feholdsetround (&env, FE_TONEAREST, changed);
+
+ junk1.x = x;
+ m = junk1.i[HIGH_HALF];
+@@ -152,7 +153,7 @@ double __ieee754_exp(double x) {
+ else { retval = __slowexp(x); goto ret; }
+ }
+ ret:
+- libc_feupdateenv (&env);
++ libc_feresetround (&env, changed);
+ return retval;
+ }
+
+diff -pruN glibc-2.12-2-gc4ccff1/sysdeps/ieee754/dbl-64/e_pow.c glibc-2.12-2-gc4ccff1.new/sysdeps/ieee754/dbl-64/e_pow.c
+--- glibc-2.12-2-gc4ccff1/sysdeps/ieee754/dbl-64/e_pow.c 2013-06-07 08:35:52.785442441 -0400
++++ glibc-2.12-2-gc4ccff1.new/sysdeps/ieee754/dbl-64/e_pow.c 2013-06-07 08:31:00.294939087 -0400
+@@ -83,7 +83,8 @@ double __ieee754_pow(double x, double y)
+ fenv_t env;
+ double retval;
+
+- libc_feholdexcept_setround (&env, FE_TONEAREST);
++ int changed;
++ libc_feholdsetround (&env, FE_TONEAREST, changed);
+
+ z = log1(x,&aa,&error); /* x^y =e^(y log (X)) */
+ t = y*134217729.0;
+@@ -100,7 +101,7 @@ double __ieee754_pow(double x, double y)
+ t = __exp1(a1,a2,1.9e16*error); /* return -10 or 0 if wasn't computed exactly */
+ retval = (t>0)?t:power1(x,y);
+
+- libc_feupdateenv (&env);
++ libc_feresetround (&env, changed);
+ return retval;
+ }
+
+diff -pruN glibc-2.12-2-gc4ccff1/sysdeps/ieee754/dbl-64/s_sin.c glibc-2.12-2-gc4ccff1.new/sysdeps/ieee754/dbl-64/s_sin.c
+--- glibc-2.12-2-gc4ccff1/sysdeps/ieee754/dbl-64/s_sin.c 2013-06-07 08:35:52.786442462 -0400
++++ glibc-2.12-2-gc4ccff1.new/sysdeps/ieee754/dbl-64/s_sin.c 2013-06-07 08:32:08.254822633 -0400
+@@ -101,7 +101,8 @@ double __sin(double x){
+ fenv_t env;
+ double retval = 0;
+
+- libc_feholdexcept_setround (&env, FE_TONEAREST);
++ int changed;
++ libc_feholdsetround (&env, FE_TONEAREST, changed);
+
+ u.x = x;
+ m = u.i[HIGH_HALF];
+@@ -355,7 +356,7 @@ double __sin(double x){
+ }
+
+ ret:
+- libc_feupdateenv (&env);
++ libc_feresetround (&env, changed);
+ return retval;
+ }
+
+@@ -374,7 +375,8 @@ double __cos(double x)
+ fenv_t env;
+ double retval = 0;
+
+- libc_feholdexcept_setround (&env, FE_TONEAREST);
++ int changed;
++ libc_feholdsetround (&env, FE_TONEAREST, changed);
+
+ u.x = x;
+ m = u.i[HIGH_HALF];
+@@ -623,7 +625,7 @@ double __cos(double x)
+ }
+
+ ret:
+- libc_feupdateenv (&env);
++ libc_feresetround (&env, changed);
+ return retval;
+ }
+
+diff -pruN glibc-2.12-2-gc4ccff1/sysdeps/ieee754/dbl-64/s_tan.c glibc-2.12-2-gc4ccff1.new/sysdeps/ieee754/dbl-64/s_tan.c
+--- glibc-2.12-2-gc4ccff1/sysdeps/ieee754/dbl-64/s_tan.c 2013-06-07 08:35:52.786442462 -0400
++++ glibc-2.12-2-gc4ccff1.new/sysdeps/ieee754/dbl-64/s_tan.c 2013-06-07 08:32:39.736162619 -0400
+@@ -66,7 +66,8 @@ double tan(double x) {
+ int __branred(double, double *, double *);
+ int __mpranred(double, mp_no *, int);
+
+- libc_feholdexcept_setround (&env, FE_TONEAREST);
++ int changed;
++ libc_feholdsetround (&env, FE_TONEAREST, changed);
+
+ /* x=+-INF, x=NaN */
+ num.d = x; ux = num.i[HIGH_HALF];
+@@ -495,7 +496,7 @@ double tan(double x) {
+ goto ret;
+
+ ret:
+- libc_feupdateenv (&env);
++ libc_feresetround (&env, changed);
+ return retval;
+ }
+
+diff -pruN glibc-2.12-2-gc4ccff1/sysdeps/x86_64/fpu/math_private.h glibc-2.12-2-gc4ccff1.new/sysdeps/x86_64/fpu/math_private.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/x86_64/fpu/math_private.h 2013-06-07 08:35:52.787442488 -0400
++++ glibc-2.12-2-gc4ccff1.new/sysdeps/x86_64/fpu/math_private.h 2013-06-07 08:34:35.370109759 -0400
+@@ -139,3 +139,31 @@ do { \
+ #undef libc_feupdateenvf
+ #define libc_feupdateenvf(e) libc_feupdateenv (e)
+ // #define libc_feupdateenvl(e) (void) feupdateenv (e)
++
++#undef libc_feholdsetround
++#define libc_feholdsetround(e, r, c) \
++({ \
++ unsigned int mxcsr, new_mxcsr; \
++ asm ("stmxcsr %0" : "=m" (*&mxcsr)); \
++ new_mxcsr = (mxcsr & ~0x6000) | ((r) << 3); \
++ if (__builtin_expect (new_mxcsr != mxcsr, 0)) \
++ { \
++ (e)->__mxcsr = mxcsr; \
++ asm volatile ("ldmxcsr %0" : : "m" (*&new_mxcsr)); \
++ c = 1; \
++ } \
++ else \
++ c = 0; \
++})
++
++#undef libc_feresetround
++#define libc_feresetround(e, c) \
++({ \
++ if (__builtin_expect (c, 0)) \
++ { \
++ unsigned int mxcsr; \
++ asm ("stmxcsr %0" : "=m" (*&mxcsr)); \
++ mxcsr = (mxcsr & ~0x6000) | ((e)->__mxcsr & 0x6000); \
++ asm volatile ("ldmxcsr %0" : : "m" (*&mxcsr)); \
++ } \
++})