2009年6月25日星期四

fls 2.6.4 bug

Do you discover any problem in the following code?

c->space_bits = fls(c->leb_size) - 3;
c->lpt_lnum_bits = fls(c->lpt_lebs);
c->lpt_offs_bits = fls(c->leb_size - 1);
c->lpt_spc_bits = fls(c->leb_size);
n = DIV_ROUND_UP(c->max_leb_cnt, UBIFS_LPT_FANOUT);
c->pcnt_bits = fls(n - 1)

This bug is inside the inline assmeble marco fls, you can not discover it in the C-level.

Let see the fls marco,
2.6.4 include/asm-arm/bitops.h
#define fls(x) \
( __builtin_constant_p(x) ? generic_fls(x) : \
({ int __r; asm("clz%?\t%0, %1" : "=r"(__r) : "r"(x)); 32-__r; }) )

clz, count the number of leading zero,
%0, result register
%1, operand register
"=r", output to C varaible
"r", input from C varaible

Since the clz instruction may alter the code register, so the following divion may be incorrect. There is a fix in 2.6.2x, which put "cc" in the Clobber List, it tell compiler there is a chance the cc will be changed by the inline asemble code.

2.6.2x arm/include/asm/bitops.h
static inline int fls(int x)
{
int ret;
if (__builtin_constant_p(x))
return constant_fls(x);

asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
ret = 32 - ret;
return ret;
}

1 則留言: