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

相关推荐
ChinaRainbowSea1 小时前
1. Linux下 MySQL 的详细安装与使用
linux·数据库·sql·mysql·adb
网络安全(华哥)1 小时前
网络安全服务实施流程管理 网络安全服务体系
运维·服务器·网络
致奋斗的我们1 小时前
Nginx反向代理及负载均衡
linux·运维·mysql·nginx·负载均衡·shell·openeluer
百锦再1 小时前
在Linux上创建一个Docker容器并在其中执行Python脚本
linux·python·docker
Ares-Wang2 小时前
负载均衡 方式
运维·负载均衡
钗头风2 小时前
3.Docker常用命令
运维·docker·容器
忧虑的乌龟蛋2 小时前
嵌入式 Linux:使用设备树驱动GPIO全流程
linux·服务器·嵌入式·imx6ull·gpio·点灯·pinctrl
朝九晚五ฺ2 小时前
【Linux探索学习】第三十弹——线程互斥与同步(上):深入理解线程保证安全的机制
linux·运维·学习
小林熬夜学编程2 小时前
【MySQL】第八弹---全面解析数据库表的增删改查操作:从创建到检索、排序与分页
linux·开发语言·数据库·mysql·算法
不要吃栗子李3 小时前
高级运维:1. 对比 LVS 负载均衡群集的 NAT 模式和 DR 模式,比较其各自的优势 。2. 基于 openEuler 构建 LVS-DR 群集。
运维·负载均衡·lvs