- 論壇徽章:
- 1
|
最近在看2.4內(nèi)核網(wǎng)絡(luò)協(xié)議棧的代碼時發(fā)現(xiàn)很多地方會根據(jù)test_bit()宏的返回值的不同來進行不同的操作,形如 ...
Anzyfly 發(fā)表于 2011-03-17 18:05 ![]() 忍不住,又看了一下內(nèi)核代碼。順便分析了一下,希望對你更底層的了解有用。- #if 0 /* Fool kernel-doc since it doesn't do macros yet */
- /**
- * test_bit - Determine whether a bit is set
- * @nr: bit number to test
- * @addr: Address to start counting from
- */
- static int test_bit(int nr, const volatile void * addr);
- #endif
- static __always_inline int constant_test_bit(int nr, const volatile unsigned long *addr)
- {
- return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0;
- }
復(fù)制代碼 對于編譯時的常數(shù)使用上面的函數(shù)進行判斷
假設(shè)我們要測試的數(shù)為test = 0x00000008,它的第三位是否為1(位數(shù)是從0數(shù)起),即nr = 3 = 0x00000003,addr就是我們測試的數(shù)的地址
addr = &test; 對于運算addr[nr >> 5] = addr[0] 也就是test的值
對于前面部分 1UL左移3位,其值就是0x00000008,它們&運算后,結(jié)果是0x00000008 != 0,所以return的結(jié)果返回是1
即0x00000008的第3位是1,其結(jié)果也確實是1。其他的情況照樣子可以這樣子驗證。- static inline int variable_test_bit(int nr, const volatile unsigned long * addr)
- {
- int oldbit;
- __asm__ __volatile__(
- "btl %2,%1\n\tsbbl %0,%0"
- :"=r" (oldbit)
- :"m" (ADDR),"Ir" (nr));
- return oldbit;
- }
復(fù)制代碼 對于編譯時的非常數(shù),使用上面的函數(shù)進行判斷。上面使用了gcc的內(nèi)聯(lián)匯編。參數(shù)nr和addr的含義和上面相同,其實就兩句,翻譯成Intel格式如下:
BT nr, (addr) ;測試(addr)的第nr位,如果是1,則CF = 1
SUBB oldbit, oldbit ;帶進位的減法,因為上面置CF = 1,所以結(jié)果是1
然后函數(shù)最后返回oldbit的值,也就是1了。
上面的匯編語言可以參看Intel Architecture Software Developer’s Manual- #define test_bit(nr,addr) \
- (__builtin_constant_p(nr) ? \
- constant_test_bit((nr),(addr)) : \
- variable_test_bit((nr),(addr)))
復(fù)制代碼 最后,test_bit其實是一個宏,看nr的屬性(是否是編譯時常數(shù)調(diào)用不同的函數(shù)),gcc的內(nèi)建函數(shù)__builtin_constant_p(nr),測試nr是否是編譯時的常量,如果是則返回1,然后調(diào)用constant_test_bit函數(shù),否則調(diào)用variable_test_bit函數(shù)。下面是引用gcc手冊的關(guān)于__builtin_constant_p(EXP)內(nèi)建函數(shù)的說明。詳細(xì)內(nèi)容可以參看gcc的info文檔。
You can use the built-in function `__builtin_constant_p' to
determine if a value is known to be constant at compile-time and
hence that GCC can perform constant-folding on expressions
involving that value. The argument of the function is the value
to test. The function returns the integer 1 if the argument is
known to be a compile-time constant and 0 if it is not known to be
a compile-time constant. A return of 0 does not indicate that the
value is _not_ a constant, but merely that GCC cannot prove it is
a constant with the specified value of the `-O' option. |
|