From 8185b32b5a8bddbb6cf78f87b848bd042324d6d2 Mon Sep 17 00:00:00 2001 From: David Schultz Date: Sat, 6 Jan 2007 21:46:23 +0000 Subject: [PATCH] Fix a problem relating to fesetenv() clobbering i387 register stack. Details: As a side-effect of restoring a saved FP environment, fesetenv() overwrites the tag word, which indicates which i387 registers are in use. Normally this isn't a problem because the calling convention requires the register stack to be empty on function entry and exit. However, fesetenv() is inlined, so we need to tell gcc explicitly that the i387 registers get clobbered. PR: 85101 --- lib/msun/amd64/fenv.h | 13 ++++++++++++- lib/msun/i387/fenv.h | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/msun/amd64/fenv.h b/lib/msun/amd64/fenv.h index cb213c271c5..b4d7379e8ff 100644 --- a/lib/msun/amd64/fenv.h +++ b/lib/msun/amd64/fenv.h @@ -78,6 +78,9 @@ extern const fenv_t __fe_dfl_env; #define __fldcw(__cw) __asm __volatile("fldcw %0" : : "m" (__cw)) #define __fldenv(__env) __asm __volatile("fldenv %0" : : "m" (__env)) +#define __fldenvx(__env) __asm __volatile("fldenv %0" : : "m" (__env) \ + : "st", "st(1)", "st(2)", "st(3)", "st(4)", \ + "st(5)", "st(6)", "st(7)") #define __fnclex() __asm __volatile("fnclex") #define __fnstenv(__env) __asm __volatile("fnstenv %0" : "=m" (*(__env))) #define __fnstcw(__cw) __asm __volatile("fnstcw %0" : "=m" (*(__cw))) @@ -171,7 +174,15 @@ static __inline int fesetenv(const fenv_t *__envp) { - __fldenv(__envp->__x87); + /* + * XXX Using fldenvx() instead of fldenv() tells the compiler that this + * instruction clobbers the i387 register stack. This happens because + * we restore the tag word from the saved environment. Normally, this + * would happen anyway and we wouldn't care, because the ABI allows + * function calls to clobber the i387 regs. However, fesetenv() is + * inlined, so we need to be more careful. + */ + __fldenvx(__envp->__x87); __ldmxcsr(__envp->__mxcsr); return (0); } diff --git a/lib/msun/i387/fenv.h b/lib/msun/i387/fenv.h index cbe9a6b6de9..c4eab02d9df 100644 --- a/lib/msun/i387/fenv.h +++ b/lib/msun/i387/fenv.h @@ -99,6 +99,9 @@ extern const fenv_t __fe_dfl_env; #define __fldcw(__cw) __asm __volatile("fldcw %0" : : "m" (__cw)) #define __fldenv(__env) __asm __volatile("fldenv %0" : : "m" (__env)) +#define __fldenvx(__env) __asm __volatile("fldenv %0" : : "m" (__env) \ + : "st", "st(1)", "st(2)", "st(3)", "st(4)", \ + "st(5)", "st(6)", "st(7)") #define __fnclex() __asm __volatile("fnclex") #define __fnstenv(__env) __asm __volatile("fnstenv %0" : "=m" (*(__env))) #define __fnstcw(__cw) __asm __volatile("fnstcw %0" : "=m" (*(__cw))) @@ -207,7 +210,15 @@ fesetenv(const fenv_t *__envp) __mxcsr = __get_mxcsr(__env); __set_mxcsr(__env, 0xffffffff); - __fldenv(__env); + /* + * XXX Using fldenvx() instead of fldenv() tells the compiler that this + * instruction clobbers the i387 register stack. This happens because + * we restore the tag word from the saved environment. Normally, this + * would happen anyway and we wouldn't care, because the ABI allows + * function calls to clobber the i387 regs. However, fesetenv() is + * inlined, so we need to be more careful. + */ + __fldenvx(__env); if (__HAS_SSE()) __ldmxcsr(__mxcsr); return (0);