內核版本:kernel 0.12
首先看一段代碼,下面這段代碼來自內核版本0.12的mm/swap.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()
封裝后:
// 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
0000000000000000 <setbit>:0: 55 push %rbp1: 48 89 e5 mov %rsp,%rbp4: 48 89 7d e8 mov %rdi,-0x18(%rbp)8: 89 75 e4 mov %esi,-0x1c(%rbp)b: 8b 55 e4 mov -0x1c(%rbp),%edxe: 48 8b 4d e8 mov -0x18(%rbp),%rcx12: b8 00 00 00 00 mov $0x0,%eax // (1) 清零eax17: b8 00 00 00 00 mov $0x0,%eax1c: 0f ab 11 bts %edx,(%rcx) // (2) bts 置位1f: 83 d0 00 adc $0x0,%eax // (3) adc: eax = eax + 0 + CF22: 89 45 fc mov %eax,-0x4(%rbp)25: 8b 45 fc mov -0x4(%rbp),%eax28: 5d pop %rbp29: c3 retq 000000000000002a <do_setbit>:2a: 55 push %rbp2b: 48 89 e5 mov %rsp,%rbp2e: 48 83 ec 10 sub $0x10,%rsp32: 48 89 7d f8 mov %rdi,-0x8(%rbp)36: 89 75 f4 mov %esi,-0xc(%rbp)39: 8b 55 f4 mov -0xc(%rbp),%edx3c: 48 8b 45 f8 mov -0x8(%rbp),%rax40: 89 d6 mov %edx,%esi42: 48 89 c7 mov %rax,%rdi45: 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 + 溢出標記CF:adcl $0,%0
c語言內聯匯編語法含義:
__asm__("匯編語句":輸出寄存器:輸入寄存器:會被修改的寄存器)"=" 操作數在指令中是只寫的 (輸出操作數)"r" 通用寄存器, 也就是eax,ebx,ecx,edx,esi,edi中的一個"m" 內存變量"g" 通用寄存器, 或者內存變量"0-9" 表示用它限制的操作數與某個指定的操作數匹配,注意作為限定符字母的 %0-%9 與指令中的 "0"-"9" 的區別,前者代表操作數, 后者描述操作數.%0, %1, %2 分別代表: __res, nr, *addradcl $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 內聯匯編