diff options
author | das <das@FreeBSD.org> | 2007-01-06 21:46:23 +0000 |
---|---|---|
committer | das <das@FreeBSD.org> | 2007-01-06 21:46:23 +0000 |
commit | 3d86fb6387a094e2d14a959794b86827ea91d03e (patch) | |
tree | 62665f2c7564e85ebe4ba599d4e200d95e83e8fb /lib | |
parent | 3e2f039e9decb8137f7c77597bd7a8c4481d3e43 (diff) | |
download | FreeBSD-src-3d86fb6387a094e2d14a959794b86827ea91d03e.zip FreeBSD-src-3d86fb6387a094e2d14a959794b86827ea91d03e.tar.gz |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/msun/amd64/fenv.h | 13 | ||||
-rw-r--r-- | 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 cb213c2..b4d7379 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 cbe9a6b..c4eab02 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); |