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 内联汇编

相关推荐
Aspiresky1 小时前
浅析Linux进程信号处理机制:基本原理及应用
linux·运维·信号处理
全栈工程师修炼指南1 小时前
告别手动构建!Jenkins 与 Gitlab 完美协作,根据参数自动化触发CI/CD流水线实践
运维·ci/cd·自动化·gitlab·jenkins
ajassi20002 小时前
linux C 语言开发 (八) 进程基础
linux·运维·服务器
..过云雨2 小时前
05.【Linux系统编程】进程(冯诺依曼体系结构、进程概念、进程状态(注意僵尸和孤儿)、进程优先级、进程切换和调度)
linux·笔记·学习
matlab的学徒2 小时前
Web与Nginx网站服务(改)
linux·运维·前端·nginx·tomcat
Insist7533 小时前
prometheus安装部署与alertmanager邮箱告警
linux·运维·grafana·prometheus
BAGAE3 小时前
MODBUS 通信协议详细介绍
linux·嵌入式硬件·物联网·硬件架构·iot·嵌入式实时数据库·rtdbs
灿烂阳光g3 小时前
SELinux 策略文件编写
android·linux
xqlily3 小时前
Linux操作系统之Ubuntu
linux·运维·ubuntu
阿部多瑞 ABU3 小时前
《基于国产Linux的机房终端安全重构方案》
linux·安全