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

相关推荐
zhd15306915625ff6 分钟前
化工厂主要涉及的自动化备件有哪些?
运维·自动化·化工厂
Jason-河山6 分钟前
利用API返回值实现商品信息自动化更新:技术与实践
运维·自动化
wowocpp1 小时前
查看 linux ubuntu 分区 和 挂载 情况 lsblk
linux·运维·ubuntu
wowocpp1 小时前
查看 磁盘文件系统格式 linux ubuntu blkid ext4
linux·数据库·ubuntu
龙鸣丿2 小时前
Linux基础学习笔记
linux·笔记·学习
耶啵奶膘4 小时前
uniapp-是否删除
linux·前端·uni-app
_.Switch4 小时前
高级Python自动化运维:容器安全与网络策略的深度解析
运维·网络·python·安全·自动化·devops
2401_850410835 小时前
文件系统和日志管理
linux·运维·服务器
JokerSZ.5 小时前
【基于LSM的ELF文件安全模块设计】参考
运维·网络·安全
XMYX-05 小时前
使用 SSH 蜜罐提升安全性和记录攻击活动
linux·ssh