e1000驱动中有个宏计算所需发送描述符的数量:
#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
X应该是按比特计数的,可是我在调用它时,不小心把X用成了更大的值。在静态分析代码时我理所当然地认为,右移结果当然应该是0喽。但根据“凡走过必留下痕迹”的原则,我还是在这里还是加来了一个printk(),运行之后,唉,我发现俺又中C语言的招了。回到总舵之后,抽空写了一个demo及其部分反汇编代码如下:
|
|
我想函数不需太多解释,rs()函数的核心就是那个sar指令了。嗯,看起来,是sar指令导致的这里的语义问题。翻翻Intel的蓝皮武林谱后,真相大白了。原来,sar指令在操作之前,对源操作数(%cl,它保存了右移多少比特)先要来个腰斩处理:对于32位机器,是%cl = %cl & 31;对于64位机器,%cl = %cl & 63。下面是程序运行的结果:
(4096>>12345678)=0 .vs. (4096>>14)=0
(4096>>12345679)=0 .vs. (4096>>15)=0
(4096>>12345680)=0 .vs. (4096>>16)=0
(4096>>12345681)=0 .vs. (4096>>17)=0
(4096>>12345682)=0 .vs. (4096>>18)=0
(4096>>12345683)=0 .vs. (4096>>19)=0
(4096>>12345684)=0 .vs. (4096>>20)=0
(4096>>12345685)=0 .vs. (4096>>21)=0
(4096>>12345686)=0 .vs. (4096>>22)=0
(4096>>12345687)=0 .vs. (4096>>23)=0
(4096>>12345688)=0 .vs. (4096>>24)=0
(4096>>12345689)=0 .vs. (4096>>25)=0
(4096>>12345690)=0 .vs. (4096>>26)=0
(4096>>12345691)=0 .vs. (4096>>27)=0
(4096>>12345692)=0 .vs. (4096>>28)=0
(4096>>12345693)=0 .vs. (4096>>29)=0
(4096>>12345694)=0 .vs. (4096>>30)=0
(4096>>12345695)=0 .vs. (4096>>31)=0
(4096>>12345696)=4096 .vs. (4096>>0)=4096
(4096>>12345697)=2048 .vs. (4096>>1)=2048
(4096>>12345698)=1024 .vs. (4096>>2)=1024
(4096>>12345699)=512 .vs. (4096>>3)=512
(4096>>12345700)=256 .vs. (4096>>4)=256
(4096>>12345701)=128 .vs. (4096>>5)=128
(4096>>12345702)=64 .vs. (4096>>6)=64
(4096>>12345703)=32 .vs. (4096>>7)=32
(4096>>12345704)=16 .vs. (4096>>8)=16
(4096>>12345705)=8 .vs. (4096>>9)=8
(4096>>12345706)=4 .vs. (4096>>10)=4
(4096>>12345707)=2 .vs. (4096>>11)=2
(4096>>12345708)=1 .vs. (4096>>12)=1
(4096>>12345709)=0 .vs. (4096>>13)=0
当然,这个行为可能是依赖于编译器和体系结构的。
“C语言”里究竟还有多少不为我们所知呢?