linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* set_bit() is broken on i386?
@ 2006-01-21  0:53 Chuck Ebbert
  2006-01-21  1:15 ` Trond Myklebust
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Chuck Ebbert @ 2006-01-21  0:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Andi Kleen, Andrew Morton, Ingo Molnar, Linus Torvalds

/* 
 * setbit.c -- test the Linux set_bit() function
 *
 * Compare the output of this program with and without the
 * -finline-functions option to GCC.
 *
 * If they are not the same, set_bit is broken.
 *
 * Result on i386 with gcc 3.3.2 (Fedora Core 2):
 *
 * [me@d2 t]$ gcc -O2 -o setbit.ex setbit.c ; ./setbit.ex
 * 00010001
 * [me@d2 t]$ gcc -O2 -o setbit.ex -finline-functions setbit.c ; ./setbit.ex
 * 00000001
 */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>

#define inline __attribute__((always_inline))

/*
 * From 2.6.15/include/asm-i386/bitops.h -- needs a memory clobber?
 */
#define ADDR (*(volatile long *) addr)
static inline void set_bit(int nr, volatile unsigned long * addr)
{
	__asm__ __volatile__( "lock ; "
		"btsl %1,%0"
		:"=m" (ADDR)
		:"Ir" (nr));
}

unsigned long b[2];

int main(int argc, char * const argv[])
{
	b[1] = 0x1;
	set_bit(12 * sizeof(unsigned long), b);
	printf("%08x\n", b[1]);
	return 0;
}
-- 
Chuck
Currently reading: _Sun Of Suns_ by Karl Schroeder

^ permalink raw reply	[flat|nested] 13+ messages in thread
* Re: set_bit() is broken on i386?
@ 2006-01-21  1:38 Kenny Simpson
  0 siblings, 0 replies; 13+ messages in thread
From: Kenny Simpson @ 2006-01-21  1:38 UTC (permalink / raw)
  To: linux kernel

Would it not be more correct to have "+m" to show that the register is both an input and an
output, and nothing more?
Or is set_bit supposed to be a general barrier or fence?

static inline void set_bit(int nr, volatile unsigned long * addr)
{
	__asm__ __volatile__( "lock ; "
		"btsl %1,%0"
		:"+m" (ADDR)
		:"Ir" (nr));
}

-Kenny


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 

^ permalink raw reply	[flat|nested] 13+ messages in thread
* Re: set_bit() is broken on i386?
@ 2006-01-21  1:46 Kenny Simpson
  0 siblings, 0 replies; 13+ messages in thread
From: Kenny Simpson @ 2006-01-21  1:46 UTC (permalink / raw)
  To: linux kernel

As a follow-up to my previous post... this only works if the ADDR macro is not used:
        "+m" (*addr)

What is the purpose of the ADDR macro? (besides calling upon the wrath of the undefined behavior
gremlins?)

-Kenny


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 

^ permalink raw reply	[flat|nested] 13+ messages in thread
* Re: set_bit() is broken on i386?
@ 2006-01-21  2:07 Kenny Simpson
  0 siblings, 0 replies; 13+ messages in thread
From: Kenny Simpson @ 2006-01-21  2:07 UTC (permalink / raw)
  To: linux kernel

Some day I'll learn to wait a few minutes before posting...

Is the issue here because btsl can touch many different bytes in the array, and there is no easy
way to tell gcc that an array is in-out, so "memory" is the best we can do?

-Kenny


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 

^ permalink raw reply	[flat|nested] 13+ messages in thread
* Re: set_bit() is broken on i386?
@ 2006-01-21  7:43 Chuck Ebbert
  0 siblings, 0 replies; 13+ messages in thread
From: Chuck Ebbert @ 2006-01-21  7:43 UTC (permalink / raw)
  To: Andrew Morton
  Cc: torvalds, mingo, ak, linux-kernel, trond.myklebust, Andreas Schwab

In-Reply-To: <20060120183857.188ef516.akpm@osdl.org>

On Fri, 20 Jan 2006, Andrew Morton wrote:

> We need to somehow tell the compiler "this assembly statement altered
> memory and you can't cache memory contents across it".  That's what
> "memory" (ie: barrier()) does.  I don't think there's a way of telling gcc
> _what_ memory was clobbered - just "all of memory".

I think you can do that by specifying an output operand that you
never use in your assembler code, e.g. changing this:

|       __asm__ __volatile__( "lock ; "
|               "btsl %1,%0"
|               :"=m" (ADDR)
|               :"Ir" (nr));

to this:

| #define LONGBITS (8 * sizeof(unsigned long))
|
|       __asm__ __volatile__( "lock ; "
|               "btsl %2,%1"
|               :"=m"(*(&ADDR + nr/LONGBITS))
|               :"m" (ADDR), "Ir" (nr));

fixes my example program by telling the compiler what memory location
is altered.  (Note that %0 is never used inside the asm code.)
So iff 'nr' is a constant you can clobber specific memory locations.
-- 
Chuck
Currently reading: _Sun Of Suns_ by Karl Schroeder

^ permalink raw reply	[flat|nested] 13+ messages in thread
* Re: set_bit() is broken on i386?
@ 2006-01-21 20:49 Chuck Ebbert
  0 siblings, 0 replies; 13+ messages in thread
From: Chuck Ebbert @ 2006-01-21 20:49 UTC (permalink / raw)
  To: Grzegorz Kulewski
  Cc: Valdis.Kletnieks, Andrew Morton, linux-kernel, Andi Kleen,
	Ingo Molnar, Linus Torvalds

In-Reply-To: <Pine.LNX.4.63.0601210245280.8060@alpha.polcom.net>

(Resent because I forgot the cc: list; Grzegorz, please don't
reply to my original.)

On Sat, 21 Jan 2006, Grzegorz Kulewski wrote:

> > On Fri, 20 Jan 2006 19:53:14 EST, Chuck Ebbert said:
> >> /*
> >>  * setbit.c -- test the Linux set_bit() function
> >>  *
> >>  * Compare the output of this program with and without the
> >>  * -finline-functions option to GCC.
> >>  *
> >>  * If they are not the same, set_bit is broken.

I should have said "If they do not both output '00010001' then
set_bit() is broken."

You got:

> gcc-3.4.5 (GCC) 3.4.5 (Gentoo 3.4.5, ssp-3.4.5-1.0, pie-8.7.9)
> 00000001
> 00000001
> 
> gcc-4.0.2 (GCC) 4.0.2 (Gentoo 4.0.2-r3, pie-8.7.8)
> 00000001
> 00000001
> 
> gcc-4.1.0-beta20060113 (GCC) 4.1.0-beta20060113  (prerelease)
> 00000001
> 00000001
> 
> gcc (GCC) 3.3.5-20050130 (Gentoo 3.3.5.20050130-r1, ssp-3.3.5.20050130-1,

pie-8.7.7.1)
> 00010001
> 00000001

So the macro is broken even without -finline-functions on all but the
last compiler.

I couldn't break this new program, which assumes 'nr' is a constant:

/* 
 * setbit2.c -- test an alternate Linux set_bit() function
 *
 * Compare the output of this program with and without the
 * -finline-functions option to GCC.
 *
 * If they do not both contain two ones, set_bit is broken.
 *
 * Result on i386 with gcc 4.0.2 (Fedora Core 4):
 *
 * [me@d2 t]$ gcc -O2 -o setbit2.ex setbit2.c ; ./setbit2.ex
 * 0x00010001
 * [me@d2 t]$ gcc -O2 -o setbit2.ex -finline-functions setbit2.c ;
./setbit2.ex
 * 0x00010001
 */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>

#define inline __attribute__((always_inline))
#define LONGBITS (8 * sizeof(unsigned long))

/*
 * new set_bit() for testing; assumes nr is a compile-time constant
 */
#define ADDR (*(volatile long *) addr)
static inline void set_bit(int nr, volatile unsigned long * addr)
{
        __asm__ __volatile__( "lock ; "
                "btsl %2,%1"
                :"=m" (*(addr + nr/LONGBITS))
                :"m" (*addr),"Ir" (nr),"m" (*(addr + nr/LONGBITS))
                );
}

unsigned long a = 1;
unsigned long b[3];

#define WORD 2
int main(int argc, char * const argv[])
{
        b[WORD] = a;
        set_bit(WORD * LONGBITS + LONGBITS / 2, b);
        printf("0x%08x\n", b[WORD]);
        return 0;
}

-- 
Chuck

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2006-01-21 20:53 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-21  0:53 set_bit() is broken on i386? Chuck Ebbert
2006-01-21  1:15 ` Trond Myklebust
2006-01-21  1:49   ` Andreas Schwab
2006-01-21  2:38     ` Andrew Morton
2006-01-21 19:26       ` Trond Myklebust
2006-01-21  1:32 ` Valdis.Kletnieks
2006-01-21  2:01   ` Grzegorz Kulewski
2006-01-21  1:48 ` Andrew Morton
2006-01-21  1:38 Kenny Simpson
2006-01-21  1:46 Kenny Simpson
2006-01-21  2:07 Kenny Simpson
2006-01-21  7:43 Chuck Ebbert
2006-01-21 20:49 Chuck Ebbert

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).