linux内核bitmap之setbit汇编实现

内核版本:kernel 0.12

首先看一段代码,下面这段代码来自内核版本0.12的mm/swap.c中:

c 复制代码
// mm/swap.c
#define bitop(name,op) \
    static inline int name(char * addr,unsigned int nr) \
{ \
    int __res; \
    __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
            :"=g" (__res) \
            :"r" (nr),"m" (*(addr)),"0" (0)); \
    return __res; \
}

bitop(bit,"")
bitop(setbit,"s")
bitop(clrbit,"r")

这段代码通过宏定义了三个位操作函数,分别是 bit() 测试位,setbit() 置位,clrbit() 清除位。

将上述代码进行改造,对setbit()封装后:

c 复制代码
// main.c
#define bitop(name,op) \
    static inline int name(char * addr,unsigned int nr) \
{ \
    int __res; \
    __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \
            :"=g" (__res) \
            :"r" (nr),"m" (*(addr)),"0" (0)); \
    return __res; \
}

bitop(setbit,"s")
    
int do_setbit(char *addr, unsigned int nr)
{
    return setbit(addr, nr);
}

反汇编后:

执行gcc -c -o main.o main.c && objdump -s -d main.o

c 复制代码
0000000000000000 <setbit>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	48 89 7d e8          	mov    %rdi,-0x18(%rbp)
   8:	89 75 e4             	mov    %esi,-0x1c(%rbp)
   b:	8b 55 e4             	mov    -0x1c(%rbp),%edx
   e:	48 8b 4d e8          	mov    -0x18(%rbp),%rcx
  12:	b8 00 00 00 00       	mov    $0x0,%eax       // (1) 清零eax
  17:	b8 00 00 00 00       	mov    $0x0,%eax
  1c:	0f ab 11             	bts    %edx,(%rcx)     // (2) bts 置位
  1f:	83 d0 00             	adc    $0x0,%eax       // (3) adc: eax = eax + 0 + CF
  22:	89 45 fc             	mov    %eax,-0x4(%rbp)
  25:	8b 45 fc             	mov    -0x4(%rbp),%eax
  28:	5d                   	pop    %rbp
  29:	c3                   	retq   

000000000000002a <do_setbit>:
  2a:	55                   	push   %rbp
  2b:	48 89 e5             	mov    %rsp,%rbp
  2e:	48 83 ec 10          	sub    $0x10,%rsp
  32:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)
  36:	89 75 f4             	mov    %esi,-0xc(%rbp)
  39:	8b 55 f4             	mov    -0xc(%rbp),%edx
  3c:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  40:	89 d6                	mov    %edx,%esi
  42:	48 89 c7             	mov    %rax,%rdi
  45:	e8 b6 ff ff ff       	callq  0 <setbit>
  4a:	c9                   	leaveq 
  4b:	c3                   	retq 

bt: 表示 Bit Test,测试并用原值设置进位值
bts : 表示 Bit Test and Set,设置比特位(设为 1)并用原值设置进位值
btr: 表示 Bit Test and Reset,复位比特位(设为 0)并用原值设置进位值

可以看到在setbit()中最重要的几步:

(1) 清零eax: "0" (0)

(2) bts 置位: "bt" op " %1,%2

(3) adc: eax = eax + 0 + 溢出标记CFadcl $0,%0

c语言内联汇编语法含义:

c 复制代码
__asm__("汇编语句"
     :输出寄存器
     :输入寄存器
     :会被修改的寄存器
     )

 "="    操作数在指令中是只写的 (输出操作数)
 "r"    通用寄存器, 也就是eax,ebx,ecx,edx,esi,edi中的一个
 "m"    内存变量
 "g"    通用寄存器, 或者内存变量
 "0-9"  表示用它限制的操作数与某个指定的操作数匹配,
        注意作为限定符字母的 %0-%9 与指令中的 "0"-"9" 的区别,
        前者代表操作数, 后者描述操作数.

  %0, %1, %2 分别代表: __res, nr, *addr
  adcl $0,%0 表示: 将 __res(%0) 加上立即数 0($0) 后, 将结果放入 __res(%0) 中
  "0" (0) : 第一个"0"表示__res, 第二(0)表示常量0, 整个语句意思是将__res初始化为0, 相当于 __res = 0

参考:

bt/bts/btr 指令

AT&T中的bt汇编指令

GCC 内联汇编

相关推荐
xywww1681 小时前
大模型 API 选型实战:GPT、Gemini、Claude 接入时该看哪些指标?
运维·服务器·人工智能·python·gpt·langchain
梦想的颜色4 小时前
【Docker原理】Docker 容器一文打尽:生命周期、环境管控、迁移备份、日志进程排查、垃圾清理
运维·docker·容器·容器生命周期·容器日志排查·容器迁移备份·容器进程管理
donoot6 小时前
Linux系统下图书馆级电子书全自动标准化分类整理完整实施方案
大数据·linux·运维·电子书管理
ITKEY_7 小时前
macOS brew 安装的nginx 文件在哪里?
运维·nginx·macos
Felix-lxd7 小时前
Ubuntu 22.04 配置 Nginx
linux·nginx·ubuntu
Elastic 中国社区官方博客7 小时前
如何比较两个 Elasticsearch 索引并找出缺失的文档
大数据·运维·数据库·elasticsearch·搜索引擎
Tim_Van8 小时前
在 CentOS 7 中安装 Chromium 的完整步骤
linux·运维·chrome·centos
2023自学中8 小时前
C++ 内存追踪器
linux·c++
孫治AllenSun9 小时前
【Nginx】配置参数和使用案例
运维·nginx
啵啵鱼爱吃小猫咪10 小时前
Ubuntu 20.04 + ROS Noetic 源码安装 libfranka 0.8.0 和 franka_ros 0.8.0 完整教程
linux·运维·ubuntu