diff options
author | Constantine Gavrilov <constg@qlusters.com> | 2005-11-17 11:40:43 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-17 08:42:26 -0800 |
commit | b7fd1edd2c0c225afa96af92d4adecb91e7d439d (patch) | |
tree | 5e8d4cbc6d16eb318bc7df102b39a09056981817 | |
parent | 3b26b1100e26811e54770abaa221eae140ba840d (diff) | |
download | op-kernel-dev-b7fd1edd2c0c225afa96af92d4adecb91e7d439d.zip op-kernel-dev-b7fd1edd2c0c225afa96af92d4adecb91e7d439d.tar.gz |
[PATCH] x86: fix sigaddset() inline asm memory constraint
Due to incomplete memory constraints, gcc would miscompile code with
sigaddset on i386 if sig arg was const.
A quote form Jakub to make the issue clear:
"You need either
__asm__("btsl %1,%0" : "+m"(*set) : "Ir"(_sig-1) : "cc");
or
__asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig-1), "m"(*set) : "cc");
because the btsl instruction doesn't just set the memory to some
value, but needs to read its previous content as well. If you don't
tell that fact to GCC, GCC is of course free to optimize as if the asm
was just setting the value and not depended on the previous value."
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | include/asm-i386/signal.h | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/include/asm-i386/signal.h b/include/asm-i386/signal.h index cbb47d3..6ba29f1 100644 --- a/include/asm-i386/signal.h +++ b/include/asm-i386/signal.h @@ -159,14 +159,37 @@ typedef struct sigaltstack { #define __HAVE_ARCH_SIG_BITOPS -static __inline__ void sigaddset(sigset_t *set, int _sig) +#define sigaddset(set,sig) \ + (__builtin_constant_p(sig) ? \ + __const_sigaddset((set),(sig)) : \ + __gen_sigaddset((set),(sig))) + +static __inline__ void __gen_sigaddset(sigset_t *set, int _sig) { - __asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); + __asm__("btsl %1,%0" : "+m"(*set) : "Ir"(_sig - 1) : "cc"); } -static __inline__ void sigdelset(sigset_t *set, int _sig) +static __inline__ void __const_sigaddset(sigset_t *set, int _sig) { - __asm__("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); + unsigned long sig = _sig - 1; + set->sig[sig / _NSIG_BPW] |= 1 << (sig % _NSIG_BPW); +} + +#define sigdelset(set,sig) \ + (__builtin_constant_p(sig) ? \ + __const_sigdelset((set),(sig)) : \ + __gen_sigdelset((set),(sig))) + + +static __inline__ void __gen_sigdelset(sigset_t *set, int _sig) +{ + __asm__("btrl %1,%0" : "+m"(*set) : "Ir"(_sig - 1) : "cc"); +} + +static __inline__ void __const_sigaddset(sigset_t *set, int _sig) +{ + unsigned long sig = _sig - 1; + set->sig[sig / _NSIG_BPW] &= ~(1 << (sig % _NSIG_BPW)); } static __inline__ int __const_sigismember(sigset_t *set, int _sig) |