右移运算符问题

 
e1000驱动中有个宏计算所需发送描述符的数量:

    #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )

X应该是按比特计数的,可是我在调用它时,不小心把X用成了更大的值。在静态分析代码时我理所当然地认为,右移结果当然应该是0喽。但根据“凡走过必留下痕迹”的原则,我还是在这里还是加来了一个printk(),运行之后,唉,我发现俺又中C语言的招了。回到总舵之后,抽空写了一个demo及其部分反汇编代码如下:

#include <stdio.h>

int rs(int i, int j)
{
        return i>>j;
}

int main()
{
        int j = 12345678;
        int k;

        for (k=0; k<0x20; k++) {
                printf("(4096>>%d)=%d .vs. (4096>>%d)=%d\n",
                                j+k, rs(4096, j+k),
                                (j+k)&0x1f, rs(4096, (j+k)&0x1f)
                                );
        }
}



08048374 <rs>:
 8048374: 55 push %ebp
 8048375: 89 e5 mov %esp,%ebp
 8048377: 8b 4d 0c mov 0xc(%ebp),%ecx
 804837a: 8b 45 08 mov 0x8(%ebp),%eax
 804837d: d3 f8 sar %cl,%eax
 804837f: 5d pop %ebp
 8048380: c3 ret


    我想函数不需太多解释,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语言”里究竟还有多少不为我们所知呢?

转载于:https://www.cnblogs.com/papam/archive/2009/08/27/1555367.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值