2013-09-06

一例C000001D错误的分析

公司客服收到用户反映,说我们的软件使用到某个功能的时候,报了一个错误。错误信息只有“External exception C000001D”这么一段文字。

搜一下C000001D,很容易就能知道对应的含义是STATUS_ILLEGAL_INSTRUCTION,也就是说程序使用了当前CPU所不支持的指令集。我们自己的程序并没有使用太新的指令集,但有一些第三方的接口库可就未必了。由于功能基本上是计算密集型的,所以这些第三方的库如果没注意编译开关,完全有可能造成这种情况。

让客服电话采集了一下用户的硬件信息,果不出所料:AMD Athlon XP 3000+。根据维基百科的资料显示,2003年面市,这是一款可以称得上老旧的CPU。支持的指令集:MMX、SSE、3DNow,并不算多,关键是没有SSE2

为什么会怀疑到SSE2上面呢?因为前不久刚看了一篇博文,说Win8需要CPU支持SSE2才能安装。这说明SSE2所能提供的,已经几乎是现在开发的新软件所必需的基本能力了。另外很多编译器已经默认把SSE2优化给打开了。也难怪——这年头,还有谁在用Pentium III吗?

总之,合理怀疑之后,先来看看是不是这么一回事。这种事情如果要通过正常途径去沟通,不见得效果好。说不定那个当初负责编译出这个库的程序员早换工作了。就算人还在,编译选项和指令集之间的关系搞不清的程序员大有人在。问还不如自己动手看。以下是用dumpbin对其中一个第三方DLL库反汇编出来的某个函数的部分代码:
1001314E: 66 0F 6F 06        movdqa      xmm0,xmmword ptr [esi]
10013152: 66 0F 6F 4E 10     movdqa      xmm1,xmmword ptr [esi+10h]
10013157: 66 0F 6F 56 20     movdqa      xmm2,xmmword ptr [esi+20h]
1001315C: 66 0F 6F 5E 30     movdqa      xmm3,xmmword ptr [esi+30h]
10013161: 66 0F 7F 07        movdqa      xmmword ptr [edi],xmm0
10013165: 66 0F 7F 4F 10     movdqa      xmmword ptr [edi+10h],xmm1
1001316A: 66 0F 7F 57 20     movdqa      xmmword ptr [edi+20h],xmm2
1001316F: 66 0F 7F 5F 30     movdqa      xmmword ptr [edi+30h],xmm3
10013174: 66 0F 6F 66 40     movdqa      xmm4,xmmword ptr [esi+40h]
10013179: 66 0F 6F 6E 50     movdqa      xmm5,xmmword ptr [esi+50h]
1001317E: 66 0F 6F 76 60     movdqa      xmm6,xmmword ptr [esi+60h]
10013183: 66 0F 6F 7E 70     movdqa      xmm7,xmmword ptr [esi+70h]
10013188: 66 0F 7F 67 40     movdqa      xmmword ptr [edi+40h],xmm4
1001318D: 66 0F 7F 6F 50     movdqa      xmmword ptr [edi+50h],xmm5
10013192: 66 0F 7F 77 60     movdqa      xmmword ptr [edi+60h],xmm6
10013197: 66 0F 7F 7F 70     movdqa      xmmword ptr [edi+70h],xmm7
1001319C: 8D B6 80 00 00 00  lea         esi,[esi+00000080h]
100131A2: 8D BF 80 00 00 00  lea         edi,[edi+00000080h]
100131A8: 49                 dec         ecx
100131A9: 75 A3              jne         1001314E
SSE2的指令集可以参见这里。其实看到movdqa就已经很明白了。这个DLL库的确用了SSE2,那么,报错就是很正常的事情。

在分析这个问题的时候,我花了一点时间,希望能找到一个能够列出程序所使用的指令集的静态分析工具,但没有找到答案。当然,就这次的情况而言,我能通过XMM寄存器很容易地找到并筛选出SSE2的指令。但要是能有一个自动化工具,就更好了。也许还是有这种工具的,只是我目前还不知道吧。如果有谁知道,还望不吝告知。

没有评论:

发表评论