关于linux bitops的使用

本文探讨了内核API在不同平台上的实现差异,特别是bitops相关函数的行为区别。介绍了find_first_zero_bit与find_next_zero_bit函数在x86与ARM平台上的返回值差异,并提出了一种通用的判断方法。此外,还展示了如何为内核添加find_first_bit与find_next_bit函数的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内核API没有通用的标准 即使在内核的文档和头文件也没详细给出
一个多平台开发中多处用到bitops   结果碰到许多问题

1
int find_first_zero_bit(void * addr, unsigned size);
int find_next_zero_bit(void * addr, int size, int offset);
找到0bit时,各平台都返回0~size-1
在x86下,没有找到0bit时,返回size
在arm下,没有找到0bit时,则返回size+1
所以通用的判断方法是,检查返回值是否>=size

2
test_bit
test_and_set_bit
test_and_clear_bit

0 bit 返回0是一定的
1 bit各个平台不一样  arm返回1  x86返回 ~0(全FF)
因此通用的检查方法是判断是0或者非0

3
2.6 引入了
find_first_bit
find_next_bit
用来查找1bit
内核头文件确实有了新的特性
但是在fc4的用户头文件中却没看到这个新特性,这个头文件在内核和用户空间不是应该一样么??

arm平台的uclinux中也没有,因此打算自己加上
它的实现在arch/armnommu/lib/findbits.S中

#include <linux/linkage.h>
#include <asm/assembler.h>
                .text

/*
 * Purpose  : Find a 'zero' bit
 * Prototype: int find_first_zero_bit(void *addr, int maxbit);
 */
ENTRY(find_first_zero_bit)
        mov    r2, #0
.bytelp:    ldrb    r3, [r0, r2, lsr #3]
        eors    r3, r3, #0xff        @ invert bits
        bne    .found            @ any now set - found zero bit
        add    r2, r2, #8        @ next bit pointer
        cmp    r2, r1            @ any more?
        bcc    .bytelp
        add    r0, r1, #1        @ no free bits
        RETINSTR(mov,pc,lr)

/*
 * Purpose  : Find next 'zero' bit
 * Prototype: int find_next_zero_bit(void *addr, int maxbit, int offset)
 */
ENTRY(find_next_zero_bit)
        ands    ip, r2, #7
        beq    .bytelp            @ If new byte, goto old routine
        ldrb    r3, [r0, r2, lsr#3]
        eor    r3, r3, #0xff        @ now looking for a 1 bit
        movs    r3, r3, lsr ip        @ shift off unused bits
        orreq    r2, r2, #7        @ if zero, then no bits here
        addeq    r2, r2, #1        @ align bit pointer
        beq    .bytelp            @ loop for next bit

/*
 * One or more bits in the LSB of r3 are assumed to be set.
 */
.found:        tst    r3, #0x0f
        addeq    r2, r2, #4
        movne    r3, r3, lsl #4
        tst    r3, #0x30
        addeq    r2, r2, #2
        movne    r3, r3, lsl #2
        tst    r3, #0x40
        addeq    r2, r2, #1
        mov    r0, r2
        RETINSTR(mov,pc,lr)

可以发现它的操作竟然是先将数字进行反转 即0->1 1->0后对1进行搜索
那简单的修改一下就应该能够搞定了
在代码后面加入下面代码


/*
 * Purpose  : Find a 'one' bit
 * Prototype: int find_first_bit(void *addr, int maxbit);
 */
ENTRY(find_first_bit)
        mov    r2, #0
.bbytelp:    ldrb    r3, [r0, r2, lsr #3]
        movs    r3, r3              // 将xor改成movs  触发标志寄存器 保证下面的bne正确跳转
        bne    .bfound            @ any now set - found zero bit
        add    r2, r2, #8        @ next bit pointer
        cmp    r2, r1            @ any more?
        bcc    .bbytelp
        add    r0, r1, #1        @ no free bits
        RETINSTR(mov,pc,lr)

/*
 * Purpose  : Find next 'one' bit
 * Prototype: int find_next_bit(void *addr, int maxbit, int offset)
 */
ENTRY(find_next_bit)
        ands    ip, r2, #7
        beq    .bbytelp            @ If new byte, goto old routine
        ldrb    r3, [r0, r2, lsr#3]
        movs    r3, r3, lsr ip        @ shift off unused bits
                                              // 去掉了xor
        orreq    r2, r2, #7        @ if zero, then no bits here
        addeq    r2, r2, #1        @ align bit pointer
        beq    .bbytelp            @ loop for next bit
/*
 * One or more bits in the LSB of r3 are assumed to be set.
 */
.bfound:    tst    r3, #0x0f
        addeq    r2, r2, #4
        movne    r3, r3, lsl #4
        tst    r3, #0x30
        addeq    r2, r2, #2
        movne    r3, r3, lsl #2
        tst    r3, #0x40
        addeq    r2, r2, #1
        mov    r0, r2
        RETINSTR(mov,pc,lr)




<think>嗯,用户想在Linux中找到bitmap中最高位的设置位。首先,我需要回忆一下Linux内核中处理位图的相关函数。记得Linux内核提供了一系列的位操作函数,比如find_first_bit和find_next_bit,但是用户需要的是最高位,也就是最后一个被设置的位。 这时候,应该想到是否有find_last_bit这个函数。根据之前的学习,Linux内核确实有find_last_bit函数,它可以在给定的位图中找到最高位的设置位。这个函数的原型可能类似于unsigned long find_last_bit(const unsigned long *addr, unsigned long size),其中addr是位图的指针,size是要搜索的位数。 接下来,我需要确认这个函数的具体使用方法和参数。例如,假设有一个位图bits,大小为1024位,调用find_last_bit(bits, 1024)会返回最高位的索引,如果没有找到则返回size的值。需要注意的是,位图的索引是从0开始的,所以最高位的位置应该是索引值。 另外,用户可能需要了解如何包含相关的头文件。通常,这些位操作函数定义在<linux/bitops.h>头文件中,所以在使用前需要包含这个头文件。 还有一种情况,如果用户是在用户空间编程,而不是内核模块,那么可能需要使用不同的方法。例如,GCC提供的内建函数__builtin_clz或者__builtin_clzl可以用来计算前导零的数量,从而推断出最高位的设置位。例如,对于一个32位的数,最高位的位置是31减去__builtin_clz(num)的结果。不过,用户的问题明确提到了Linux,所以可能更倾向于内核中的方法。 此外,还需要考虑性能问题。find_last_bit函数在内核中已经优化过,处理大位图时效率较高。而用户空间的实现可能需要自己处理,尤其是当位图很大时,逐位检查可能效率低下。所以,如果用户在内核开发,直接使用find_last_bit是最佳选择;如果在用户空间,可能需要根据具体情况选择合适的方法。 最后,确保回答中提到的函数和头文件是正确的,避免误导用户。可能还需要提醒用户注意参数的正确性和边界情况,比如位图为空或全0的情况,这时候函数会返回size的值,需要做适当检查。</think>在Linux内核中查找位图(bitmap)最高位的设置位,可以使用内核提供的专用接口$find\_last\_bit()$函数。该函数定义在$<linux/bitops.h>$头文件中,其函数原型为: ```c unsigned long find_last_bit(const unsigned long *addr, unsigned long size); ``` ### 使用步骤说明 1. **包含头文件**:确保代码中包含$<linux/bitops.h>$ 2. **参数说明**: - `addr`: 位图的起始地址 - `size`: 需要扫描的位数(例如位图总长度) 3. **返回值**:返回最高设置位的索引(从0开始计数),若未找到则返回`size` ### 示例代码 ```c #include <linux/bitops.h> unsigned long bitmap = 0x0F00; // 示例位图:第8-11位为1 unsigned long max_bit = find_last_bit(&bitmap, 64); printk("Highest set bit: %lu\n", max_bit); // 输出: Highest set bit: 11 ``` ### 性能优化 - 对于用户态程序,可使用GCC内置函数$__builtin_clzl()$: ```c unsigned long num = 0x0F00; int highest_bit = (num == 0) ? 0 : (63 - __builtin_clzl(num)); ``` ### 实现原理 内核中的$find\_last\_bit()$通过逆向遍历位图,结合CPU指令级优化(如x86的$BSR$指令)实现高效查找[^3]。该函数的时间复杂度为$O(n)$,但实际执行效率受硬件指令加速影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值