微软strlen函数实现

前阵子看熊力的《WINDOWS用户态程序高效排错》的时候,在他BLOG(blogs.msdn.com/lixiong)里的用户反馈里看到的,据说是系统STRLEN的汇编代码

下面是熊力对这段代码的分析:
“这里对一个DWORD (EAX)的判断方法是: 

1. 对EAX+0x7efefeff 
2. 对EAX取反 
3. 把1和2的结果作XOR,然后跟0x81010100h作test运算 

研究了好久,理解如下: 

问题的关键点在于,当且仅当EAX四个byte都不为0的时候,运算结果会是下面的pattern: 
0??? ???0 ???? ???0 ???? ???0 ???? ???? 

分别解释如下: 

如果第一个byte为0, 考虑第二个byte的最后一个bit。不管这个bit是0还是1,计算公式是: 
(x+0) XOR (!x) =x xor !x=0 
如果第一个byte不为0,肯定产生进位,考虑第二个byte的最后一个bit。不管这个bit是0还是1,计算公式是: 
(x+1)XOR(!x)=!x xor !x=1 

这就是上面0??? ???0 ???? ???0 ???? ???0 ???? ????第二个byte的第一个bit是0的来历 

同理,第二,三,四个byte中的的第一个bit的0也是在前面所有的byte都不为0的时候才会出现,否则就会出现至少一个1 

换句话说,上面的代码无法区分最高一个byte最高bit为0,其他bit为1的情况。这是这种算法的一个死穴。当出现比如0x80112233这样的 DWORD的时候,test    eax,81010100h 计算的结果跟0x00112233一样。当然最后的结果不会有问题,因为 byte_3 -- byte_0里面会再次作判断。所以,如果用一连串的0x80112233作为字符串内容,strcpy的效率会大大下降 

对于一个DWORD,导致这个因素的可能是 
2^24/2^32=1/2^8=1/256 

算是比较罕见了 

从逻辑上说,最高byte是无法区分本身为1,或者是低byte进位的情况。所以单独的DWORD是无法判断出所有情况的,当前的做法已经算很有想法的了 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值