位操作
- 基本位运算指令
常见的位运算功能及指令类别对应关系如下表所示,具体某一功能类别的衍生指令不在这里详细介绍,同样如果感兴趣可以查阅Armv8指令手册进行了解。
功能
指令/指令族
与
AND
或
ORR
取反
NEG
异或
EOR
逻辑左移
LSL
逻辑右移
LSR
- 对齐判断与处理
我们在第三节已提到,汇编代码中经常会有内存操作。相比起高级语言的习惯,汇编代码尤其是string系列,更加注重内存地址对齐操作。内存寻址的一般原则是只能直接访问部分类型地址,其他地址通过能直接访问的地址加上偏移量进行访问,故而对于内存操作,直接对对齐地址的内存进行操作一般会优于对非对齐地址的内存。
而内存地址对齐的本质是对内存地址进行相关的位操作,其实现并不复杂,使用BIC指令就可以,但是通常对一个地址进行对齐后,还需要对相关参数进行调整以保证逻辑的正确,此时先要通过AND指令计算并保存为使地址对齐需要偏移的字节数。另外这种情况下使用SUB指令对地址进行对齐的效果和BIC指令效果相同,如下所示:
/* Assume the src is the addr to be aligned */ … … and tmp, src, 15 bic src, src, 15 (sub src, src, tmp) add count, count, tmp sub dst, dst, tmp … …
- 魔法数字的妙用
string类函数源码中还存在一些特殊设计的魔法数字实际上是非常高深的位操作用法,利用这些魔法数字及对应的位操作同样可以实现一些更强的功能,例如strcpy在判断每个字节是否为NULL结束符就巧妙的利用了魔法数字。
#define REP8_01 0x0101010101010101 #define REP8_7f 0x7f7f7f7f7f7f7f7f … … ldp data1, data2, [src], #16 sub tmp1, data1, #REP8_01 orr tmp2, data1, #REP8_7f sub tmp3, data2, #REP8_01 orr tmp4, data2, #REP8_7f bic has_nul1, tmp1, tmp2 bics has_nul2, tmp3, tmp4 ccmp has_nul1, #0, #0, eq /* NZCV = 0000 */
在上述strcpy.S中的这段汇编代码,设置魔法数字REP8_01和REP8_7f,并利用位操作表达式((X - 1) & ~(X | 0x7f))实现了判断每个字节是否为NULL结束符(0x00)的功能。在这里我们不再具体解释其如何实现,读者们可以假设一串ASCII值带入该表达式中进行计算,会发现只有当其值为0x00时才会出现不同的计算结果。
另一个更神奇的魔法数字出现在memchr.S的实现中,通过定义魔法数字0x40100401及相关的位计算操作,实现找到相同ASCII值字符的功能。