打印

还真是ADS1.2的BUG![build 805]的BUG,还在使ADS1.2的兄弟注意升级

[复制链接]
6030|27
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
bluesky_78|  楼主 | 2007-5-27 17:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
ads1, ui, BUG, ST, TE
编译环境:ADS1.2
调试环境:AXD Armulate

发现问题:同一条语句,不同的编译选项编译,执行结果不同。

语句:
if((d & 0x0fffffff) == 0x05555550)

选用-O1选项编译时生成代码:(armcc –O1 –g+ -S –fs –cpu ARM7TDMI –o outO1.s test.c)
000004  e1a00200          MOV      r0,r0,LSL #4
000008  e1500221          CMP      r0,r1,LSR #4
00000c  1a000001          BNE      |L1.24|
其中
r0为0xA5555550
r1为0x05555550

执行结果为假:
;r0 中为0xA5555550
MOV      r0,r0,LSL #4  
;r0中为0x55555500, r1中为0x05555550, r1,LSR #4 为0x00555555
CMP      r0,r1,LSR #4  ;不相等,为假
BNE      |L1.24|

选用-O0选项编译时生成代码:(armcc –O0 –g+ -S –fs –cpu ARM7TDMI –o outO0.s test.c)
000000  e1a01000          MOV      r1,r0
000004  e1a00201          MOV      r0,r1,LSL #4
000008  e59f202c          LDR      r2,|L1.60|
00000c  e1520220          CMP      r2,r0,LSR #4
其中
r0为0xA5555550

执行结果为真:
;r0 中为0xA5555550
MOV      r1,r0
;r0和r1中都为0xA5555550
MOV      r0,r1,LSL #4
;r0中为0x55555500
LDR      r2,|L1.60|
;r2中为0x05555550
CMP      r2,r0,LSR #4  ;r0,LSR #4为0x05555550, 与r2相等,为真

源程序:
int test(unsigned int d)
{
    if((d & 0x0fffffff) == 0x05555550)
        return 1;
    else
        return 0;
}

int main(void)
{
    int d;
    
    d = test(0xA5555550);
    
    return d;
}
使用-O1选项生成的汇编代码:
(armcc –O1 –g+ -S –fs –cpu ARM7TDMI –o outO1.s test.c)
; generated by ARM C Compiler, ADS1.2 [Build 805]

; commandline [-O1 -S -g+ -fs "-IC:Program FilesARMADSv1_2INCLUDE"]
                          CODE32

                          AREA ||.text||, CODE, READONLY

                  test PROC
;;;1      int test(unsigned int d)
;;;2      {
000000  e59f1020          LDR      r1,|L1.40|
;;;3          //unsigned int bak;
;;;4          
;;;5          if((d & 0x0fffffff) == 0x05555550)
000004  e1a00200          MOV      r0,r0,LSL #4
000008  e1500221          CMP      r0,r1,LSR #4
00000c  1a000001          BNE      |L1.24|
;;;6              return 1;
000010  e3a00001          MOV      r0,#1
;;;7          else
;;;8              return 0;
;;;9      }
                  |L1.20|
000014  e1a0f00e          MOV      pc,lr
                  |L1.24|
000018  e3a00000          MOV      r0,#0                 ;8
00001c  eafffffc          B        |L1.20|               ;8
                          ENDP

                  main PROC
;;;11     int main(void)
;;;12     {
000020  e59f0004          LDR      r0,|L1.44|
;;;13         unsigned int d;
;;;14     
;;;15         d = test(0xA5555550);
000024  eafffffe          B        test
                  |L1.40|
000028  05555550          DCD      0x05555550
                  |L1.44|
00002c  a5555550          DCD      0xa5555550
;;;16         
;;;17         return d;
;;;18     }                          ENDP



        END

使用-O0选项生成的汇编代码:
(armcc –O0 –g+ -S –fs –cpu ARM7TDMI –o outO0.s test.c)
; generated by ARM C Compiler, ADS1.2 [Build 805]

; commandline [-O0 -S -g+ -fs "-IC:Program FilesARMADSv1_2INCLUDE"]
                          CODE32

                          AREA ||.text||, CODE, READONLY

                  test PROC
;;;1      int test(unsigned int d)
;;;2      {
000000  e1a01000          MOV      r1,r0
;;;3          //unsigned int bak;
;;;4          
;;;5          if((d & 0x0fffffff) == 0x05555550)
000004  e1a00201          MOV      r0,r1,LSL #4
000008  e59f202c          LDR      r2,|L1.60|
00000c  e1520220          CMP      r2,r0,LSR #4
000010  1a000001          BNE      |L1.28|
;;;6              return 1;
000014  e3a00001          MOV      r0,#1
;;;7          else
;;;8              return 0;
;;;9      }
                  |L1.24|
000018  e1a0f00e          MOV      pc,lr
                  |L1.28|
00001c  e3a00000          MOV      r0,#0                 ;8
000020  eafffffc          B        |L1.24|               ;8
                          ENDP

                  main PROC
;;;11     int main(void)
;;;12     {
000024  e52de004          STR      lr,[sp,#-4]!
;;;13         unsigned int d;
;;;14     
;;;15         d = test(0xA5555550);
000028  e59f0010          LDR      r0,|L1.64|
00002c  ebfffffe          BL       test
000030  e1a03000          MOV      r3,r0
;;;16         
;;;17         return d;
000034  e1a00003          MOV      r0,r3
;;;18     }000038  e49df004          LDR      pc,[sp],#4
                  |L1.60|
00003c  05555550          DCD      0x05555550
                  |L1.64|
000040  a5555550          DCD      0xa5555550
                          ENDP



        END

相关帖子

沙发
mohanwei| | 2007-5-27 18:35 | 只看该作者

所谓“优化”,是要有一些不同的……

不过有一点是肯定的:没问题。

使用特权

评论回复
板凳
bluesky_78|  楼主 | 2007-5-27 19:08 | 只看该作者

疑问

优化前test函数返回1
优化后test函数返回0
执行结果不同。
显然优化前的结果是正确的,而优化后的结果是错误的。而且优化后在调试环境下,用watch观察((d & 0x0fffffff) == 0x05555550),结果为1,执行时却跳到return 0;处。
使用-O1选项优化后,语句:
CMP      r0,r1,LSR #4
如果改为
CMP      r0,r1,LSL #4
就对了。

使用特权

评论回复
地板
djyos| | 2007-5-27 19:50 | 只看该作者

编译器没有错

编译器认为main函数里面的 int d是冗余变量,被优化掉了。定义成
volatile int d;
再试一下就知道了。

编译器忽视
return d;
语句,说明ads的runtime库没有使用main函数的返回值,否则不会这样的。

使用特权

评论回复
5
mohanwei| | 2007-5-27 20:42 | 只看该作者

4楼说得对,优化的时候会使用到覆盖技术,那时候同一个内

单元有可能被N个变量公用了……
有时候你没用到这个变量,那么它的值是什么都无所谓了。你可以做一下测试:用返回值参与运算,看看它是不是一下子又变好了……

使用特权

评论回复
6
bluesky_78|  楼主 | 2007-5-27 22:04 | 只看该作者

还是不对

谢谢4楼、5楼。
我试着把代码改为:
int test(unsigned int d)
{
    if((d & 0x0fffffff) == 0x05555550)
        return 1;
    else
        return 0;
}

int main(void)
{
    volatile int d, c;
    
    d = test(0xA5555550);
    
    c = 2 * d;
    
    return c;
}
问题依旧。
使用-O1选项(ARM C Compiler->Debug/ Opt->Optimization Level->Most),运行结果c = 0;
使用-O0选项(ARM C Compiler->Debug/ Opt->Optimization Level->Minimum),运行结果c = 2;

同样的代码,在VC下运行,结果c=2

使用特权

评论回复
7
djyos| | 2007-5-28 09:07 | 只看该作者

是个问题

我在realview2.2上试了一下,加volatile确实无效,c和d都被优化掉了。
用gcc编译则,不管优化级别是多少,都没有这个问题。
有高手可以出来解释一下吗,有arm的技术支持在吗?
下面是ansi C 标准文档6.7.3节第6款原文:
An object that has volatile-qualified type may be modified in ways unknown to the
implementation or have other unknown side effects. Therefore any expression referring
to such an object shall be evaluated strictly according to the rules of the abstract machine,
as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the
object shall agree with that prescribed by the abstract machine, except as modified by the
unknown factors mentioned previously.103) What constitutes an access to an object that
has volatile-qualified type is implementation-defined.
我的理解是,volatile变量是不应该给优化掉的。

使用特权

评论回复
8
kent_gwk| | 2007-5-28 11:06 | 只看该作者

换一种写法

换一种写法 if((d<<4) == 0x55555500)这样试一下

使用特权

评论回复
9
bluesky_78|  楼主 | 2007-5-28 12:29 | 只看该作者

望指教!

换成if((d<<4) == 0x55555500)就没有问题了。
我感觉不是把变量优化掉的问题。这个问题是我在写一个解码程序时发现的,我先是在VC下把算法验证通过,然后移植到ARM下运行,不通,然后查到是这里的问题,写了上述小程序验证,并排除硬件问题的可能(在Armulate下运行,并生成汇编代码验证),都不对。
在选用-O0选项和-O2选项时,运行结果正确,而选用-O1时运行结果错误。
看选用-O1时的汇编代码:
000004  e1a00200          MOV      r0,r0,LSL #4
000008  e1500221          CMP      r0,r1,LSR #4
00000c  1a000001          BNE      |L1.24|
将r0(0xA5555550)的左移4位与r1(0x05555550)的右移4位相比较,是不相同的。与r1的左移4位就对了。
我看了网上的贴子,大家对ADS1.2的编译器大多很有信心,也不敢冒然认为是编译器出问题。
在实际问题中我把代码改为:
unsigned int bak;
if((bak = d & 0x0fffffff) == 0x05555550)
无论用什么优化选项就都没有问题了。
望指教!

使用特权

评论回复
10
bluesky_78|  楼主 | 2007-5-28 12:38 | 只看该作者

改成
unsigned int bak;
if((bak = d & 0x0fffffff) == 0x05555550)
后使用-O1选项生成的代码为:
BIC r0,r0, #0xf0000000
CMP r0,r1
BNE ...
这时生成的代码就对了,也没有给bak变量分配空间。

不知怎样帖图。抓了几张调试时的图片,想帖一下。点下面的“上传图片/文件”没有反映。

使用特权

评论回复
11
bluesky_78|  楼主 | 2007-5-28 12:42 | 只看该作者

使用-O0选项时生成的代码是:
000004  e1a00201          MOV      r0,r1,LSL #4
000008  e59f202c          LDR      r2,|L1.60|
00000c  e1520220          CMP      r2,r0,LSR #4
000010  1a000001          BNE      |L1.28|
是将r1(0xA5555550)左移4位存入r0,再将r0右移4位(相当于清除r0高4位)与r2(0x05555550)比较,生成的代码和运行结果都是可以理解的。

使用特权

评论回复
12
mohanwei| | 2007-5-28 17:45 | 只看该作者

6楼的代码改成如下,再试试看:

int test(unsigned int d)
{
    if((d & 0x0fffffff) == 0x05555550)
        return 1;
    else
        return 0;
}

int main(void)
{
    volatile int d, c;
    //如果编译器足够聪明,在这里d的值在编译阶段已经可以算出来了,c也是。
    //d = test(0xA5555550);
    //改为如下代码(要让编译器知道,传给test的参数的确是一个“变量”,而不是已知值)
    scanf("%d",&d);
    d = test(d);
    
    c = 2 * d;
    
    printf(" d=%d  c=%d ",d,c);//告诉编译器,你的确需要用到这个返回值。
    return c;
}

优化的时候肯定是要去掉一些无关的东西的,不然程序怎么变小变快……^_^

使用特权

评论回复
13
bluesky_78|  楼主 | 2007-5-28 20:38 | 只看该作者

试了一下,结果还是一样。

非常感谢12楼的回复。我按照所述将程序改为如下:

#include <stdio.h>

int test(unsigned int d)
{
    if((d & 0x0fffffff) == 0x05555550)
        return 1;
    else
        return 0;
}

int main(void)
{
    volatile int d, c;
    
    scanf("%d",&d);
    d = test(d);
    
    c = 2 * d;
    printf(" d=%d  c=%d ",d,c);

    return c;
}

AXD 下用Armulate调试:
/*****************************************************************/
使用-O1选项,在Console下输入
2773833040(即0xA5555550)
输出为
d=0 
c=0
test函数生成的代码为
[0xe59f1050]   ldr      r1,0x00008100 ; = #0x05555550
[0xe1a00200]   mov      r0,r0,lsl #4
[0xe1500221]   cmp      r0,r1,lsr #4
[0x1a000001]   bne      0x80c0  ; (test + 0x18)
[0xe3a00001]   mov      r0,#1
[0xe1a0f00e]   mov      pc,r14

/*****************************************************************/
使用-O0选项,在Console下输入
2773833040(即0xA5555550)
输出为
d=1 
c=2
test函数生成的代码为
[0xe1a01000]   mov      r1,r0
[0xe1a00201]   mov      r0,r1,lsl #4
[0xe59f2050]   ldr      r2,0x00008108 ; = #0x05555550
[0xe1520220]   cmp      r2,r0,lsr #4
[0x1a000001]   bne      0x80c4  ; (test + 0x1c)
[0xe3a00001]   mov      r0,#1
[0xe1a0f00e]   mov      pc,r14

/*****************************************************************/
使用-O2选项,在Console下输入
2773833040(即0xA5555550)
输出为
d=0
c=0
test函数生成的代码为
[0xe59f1048]   ldr      r1,0x000080f8 ; = #0x05555550
[0xe1a00200]   mov      r0,r0,lsl #4
[0xe1500221]   cmp      r0,r1,lsr #4
[0x13a00000]   movne    r0,#0
[0x03a00001]   moveq    r0,#1
[0xe1a0f00e]   mov      pc,r14

使用特权

评论回复
14
djyos| | 2007-5-28 21:03 | 只看该作者

lz为什么不把样本寄给arm公司呢

    An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects.
    ansi c 标准明确指出,volatile修饰的变量可能被未知方式修改,或者产生未知的副作用,那编译器既然不知道程序员需要产生什么副作用,就应该如实产生代码,不能自作主张。
    问问ARM公司吧,也许只有他们知道答案。

使用特权

评论回复
15
平常人| | 2007-5-28 21:17 | 只看该作者

把样本寄给ARM公司也没用,ARM公司早就不支持ADS了

就像你今天找出上百个Win98的BUG,Microsoft也不会理你的。你发现了8080的bug,Intel也不会管你。

使用特权

评论回复
16
bluesky_78|  楼主 | 2007-5-28 21:18 | 只看该作者

好的

明天我问问ARM公司吧。
使的是盗版软件,不知是否能给支持。

使用特权

评论回复
17
djyos| | 2007-5-28 21:21 | 只看该作者

我试了一下,realview2.2也是这样

难道realview2.2也不支持了吗?谁有3.0的,也试一下怎样?
我真的很想知道结果,可以学习长经验。
别告诉ARM你用盗版,说是评估版就可以了。

使用特权

评论回复
18
bluesky_78|  楼主 | 2007-5-28 21:23 | 只看该作者

有谁用正版ADS1.2的,帮忙试试?

有谁用正版ADS1.2的,帮忙试试?

使用特权

评论回复
19
high| | 2007-5-28 22:58 | 只看该作者

lz仔细,我很早就碰到过debug好好的,release有时候会出错。

我给别人代码时候都是告诉他用debug -o0的,如果要用release的,自己要仔细测试。但是具体原因我也一直给不出。

使用特权

评论回复
20
wowow| | 2007-5-29 04:32 | 只看该作者

volatile貌似只能用于全局变量

volatile用得比较多的场合:
1.定义映射到RAM寄存器寄存器
2.可能在多个并行模块被修改的变量(比如主程序和中断中都要用的变量)

而局部变量在初始化在堆栈里的,不可能被硬件或其它模块更改,也许编译器认为给局部变量加上volatile毫无意义而忽略掉.

RVCT 2.2中有关volatile的描叙:
The standard ISO qualifier volatile informs the compiler that the
qualified type contains data that can be changed from outside the
program. Such variables must be placed in RW or ZI data (not in
.constdata) so that they can be changed. This includes const volatile
variables.
The compiler does not attempt to optimize accesses to volatile types. For
example, volatile structures can be mapped onto memory-mapped
peripheral registers:
/* define a memory-mapped port register */
volatile unsigned *port = (unsigned int *) 0x40000000;

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

16

帖子

0

粉丝