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

相关推荐
热爱嵌入式的小许9 分钟前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
韩楚风4 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学4 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO4 小时前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
Pythonliu74 小时前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器
你疯了抱抱我4 小时前
【RockyLinux 9.4】安装 NVIDIA 驱动,改变分辨率,避坑版本。(CentOS 系列也能用)
linux·运维·centos
追风赶月、4 小时前
【Linux】进程地址空间(初步了解)
linux
栎栎学编程4 小时前
Linux中环境变量
linux
挥剑决浮云 -5 小时前
Linux 之 安装软件、GCC编译器、Linux 操作系统基础
linux·服务器·c语言·c++·经验分享·笔记
小O_好好学6 小时前
CentOS 7文件系统
linux·运维·centos