回复: libc printf测试崩溃问题

22 views
Skip to first unread message

weety

unread,
Aug 26, 2014, 1:04:14 AM8/26/14
to rt-threa...@googlegroups.com
这个问题大家有没有碰到过?

来自我的荣耀6


-------- 原始邮件 --------
主题:libc printf测试崩溃问题
发件人:weety
收件人:rt-threa...@googlegroups.com
抄送:


Rtt版本:2.0.0 beta

finsh>>libc_printf()

stdout test!!

fprintf test!!

fprintf test!!

puts test!!

 

12

# vim:syntax=off:

 

Execption:

r00:0xa0070e3d r01:0xa0065866 r02:0x00000000r03:0x00000064

r04:0xa0066258 r05:0xa0066258 r06:0xa0063ed0 r07:0xa008c028

r08:0xa008c1aa r09:0xa008c0ba r10:0x00000000

fp :0x00000000 ip :0xfefeff00

sp :0x00000000 lr :0x00000000 pc :0xa0021acc

cpsr:0x60000013

data abort

thread - tshell stack:

thread  pri  status      sp     stack size max used   left tick  error

-------- ---- ------- ---------- ---------- ---------- ---------- ---

tidle    0xff ready   0x00000074 0x00000100 0x000000bc 0x00000002 000

timer    0x08 suspend 0x00000074 0x00000200 0x00000074 0x00000009 000

tshell   0x14 ready   0x000000b4 0x00001000 0x00000640 0x00000006 000

shutdown...



来自我的荣耀6

weety

unread,
Aug 26, 2014, 1:34:59 AM8/26/14
to rt-threa...@googlegroups.com
这个是rtt自带的libc的测试用例,详见examples/libc/printf.c文件

来自我的荣耀6


-------- 原始邮件 --------
主题:Re: libc printf测试崩溃问题
发件人:Grissiom
收件人:rt-threa...@googlegroups.com
抄送:


On Tue, Aug 26, 2014 at 1:02 PM, weety <luohu...@gmail.com> wrote:
Rtt版本:2.0.0 beta

finsh>>libc_printf()


函数里是啥东西?

--
Cheers,
Grissiom

--
You received this message because you are subscribed to the Google Groups "rt-thread用户组" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rt-thread-cnus...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

weety

unread,
Aug 26, 2014, 7:51:33 AM8/26/14
to rt-threa...@googlegroups.com
崩溃位置找到了,在执行strcat函数时崩溃,采用的是newlib库,编译器也更换过了,崩溃位置相同,不知道是哪里出了问题

 

int printf_test()

{

  char buf[256];

  int i;

 

  printf("%s\n\n", "# vim:syntax=off:");

 

  /* integers */

  for(i=0;format[i];i++) {

    strcpy(buf, format[i]);

    strcat(buf, "d");

    intchk(buf);

  }



来自我的荣耀6


-------- 原始邮件 --------
主题:回复: libc printf测试崩溃问题

发件人:weety
收件人:rt-threa...@googlegroups.com
抄送:


weety

unread,
Aug 26, 2014, 7:54:21 AM8/26/14
to rt-threa...@googlegroups.com
buf[256]也够大了,不会溢出,但这个简单操作也有问题

weety

unread,
Aug 26, 2014, 8:19:33 AM8/26/14
to rt-threa...@googlegroups.com
将优化等级O2修改为Os,就不再崩溃了,应该是优化导致的问题,这么看来newlib c库不赖优化,使用需要注意。

Grissiom

unread,
Aug 26, 2014, 8:54:12 AM8/26/14
to rt-threa...@googlegroups.com
2014-08-26 20:19 GMT+08:00 weety <luohu...@gmail.com>:
将优化等级O2修改为Os,就不再崩溃了,应该是优化导致的问题,这么看来newlib c库不赖优化,使用需要注意。


按说也不会啊,链接库的话函数都是编译好的,难道这个函数是内联的?

--
Cheers,
Grissiom

weety

unread,
Aug 26, 2014, 9:06:33 AM8/26/14
to rt-threa...@googlegroups.com
之前finsh中也崩溃了,崩溃的位置还是strcat,由于找不到原因,我将DFS_USING_WORKDIR选项去掉后屏蔽了这个问题,后来执行libc的测试用例,发现这个问题又出来了,现在确认修改优化等级后,这两处的崩溃问题都解决了。这块我也想不通原因是什么。

 

const char* finsh_get_prompt()

{

    #define _MSH_PROMPT "msh "

    #define _PROMPT "finsh "

    static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {0};

 

#ifdef FINSH_USING_MSH

    if (msh_is_used()) strcpy(finsh_prompt, _MSH_PROMPT);

    else

#endif

    strcpy(finsh_prompt, _PROMPT);

 

#ifdef DFS_USING_WORKDIR

    /* get current working directory */

    getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - rt_strlen(finsh_prompt));

#endif

    strcat(finsh_prompt, ">");

 

    return finsh_prompt;

}



来自我的荣耀6


-------- 原始邮件 --------
主题:Re: libc printf测试崩溃问题
发件人:Grissiom
收件人:rt-threa...@googlegroups.com
抄送:


--

bernard

unread,
Aug 26, 2014, 10:34:03 AM8/26/14
to rt-thread用户组
weety,
你自己实现个strcat把库内置的strcat给冲掉看看。

另外一个,你的GNU GCC是什么版本?是否也可能调试内置newlib的strcat函数。

weety

unread,
Aug 26, 2014, 10:14:59 PM8/26/14
to rt-threa...@googlegroups.com
我确认了,自己实现strcat函数替换掉c库的就不再崩溃了,编译器arm-none-eabi 2013.11 ,2012.09也一样



-------- 原始邮件 --------
主题:Re: libc printf测试崩溃问题
发件人:bernard
收件人:rt-thread用户组
抄送:

weety

unread,
Aug 27, 2014, 1:13:17 AM8/27/14
to rt-threa...@googlegroups.com
现在基本上有了些眉目,我这边测试了O0,O1,O2,O3,Os优化等级,只有Os优化等级编译的代码能够正确运行,其他优化等级都出现崩溃打印信息。

通过反汇编分析,发现不同优化等级优化后二进制代码相差较大,但只有Os优化的代码调用了strcat函数,其他的优化等级(O0,O1,O2,O3)都没有调用strcat函数,被优化掉了。

下面附上c代码和Os、O1优化后的反汇编代码

原始c代码:


const char* finsh_get_prompt()
{
#define _MSH_PROMPT "msh "
#define _PROMPT "finsh "
static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {0};

#ifdef FINSH_USING_MSH
if (msh_is_used()) strcpy(finsh_prompt, _MSH_PROMPT);
else
#endif
strcpy(finsh_prompt, _PROMPT);

#ifdef DFS_USING_WORKDIR
/* get current working directory */
getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - rt_strlen(finsh_prompt));
#endif
strcat(finsh_prompt, ">");

return finsh_prompt;
}


O1优化后的反汇编代码:

a00249b4 :
a00249b4: e92d4818 push {r3, r4, fp, lr}
a00249b8: e28db00c add fp, sp, #12
a00249bc: e59f307c ldr r3, [pc, #124] ; a0024a40
a00249c0: e59f207c ldr r2, [pc, #124] ; a0024a44
a00249c4: e8920003 ldm r2, {r0, r1}
a00249c8: e5830000 str r0, [r3]
a00249cc: e2833004 add r3, r3, #4
a00249d0: e1c310b0 strh r1, [r3]
a00249d4: e2833002 add r3, r3, #2
a00249d8: e1a02821 lsr r2, r1, #16
a00249dc: e5c32000 strb r2, [r3]
a00249e0: e59f0058 ldr r0, [pc, #88] ; a0024a40
a00249e4: ebff878f bl a0006828
a00249e8: e1a02000 mov r2, r0
a00249ec: e59f304c ldr r3, [pc, #76] ; a0024a40
a00249f0: e0824003 add r4, r2, r3
a00249f4: e59f0044 ldr r0, [pc, #68] ; a0024a40
a00249f8: ebff878a bl a0006828
a00249fc: e1a03000 mov r3, r0
a0024a00: e2633080 rsb r3, r3, #128 ; 0x80
a0024a04: e1a00004 mov r0, r4
a0024a08: e1a01003 mov r1, r3
a0024a0c: ebffc13e bl a0014f0c
a0024a10: e59f0028 ldr r0, [pc, #40] ; a0024a40
a0024a14: eb0047e5 bl a00369b0
a0024a18: e1a03000 mov r3, r0
a0024a1c: e1a02003 mov r2, r3
a0024a20: e59f3018 ldr r3, [pc, #24] ; a0024a40
a0024a24: e0823003 add r3, r2, r3
a0024a28: e59f2018 ldr r2, [pc, #24] ; a0024a48
a0024a2c: e1d220b0 ldrh r2, [r2]
a0024a30: e1c320b0 strh r2, [r3]
a0024a34: e59f3004 ldr r3, [pc, #4] ; a0024a40
a0024a38: e1a00003 mov r0, r3
a0024a3c: e8bd8818 pop {r3, r4, fp, pc}
a0024a40: a007922c andge r9, r7, ip, lsr #4
a0024a44: a0068ea4 andge r8, r6, r4, lsr #29
a0024a48: a0068eac andge r8, r6, ip, lsr #29


Os优化后的反汇编代码:

a0013cac :
a0013cac: e92d4038 push {r3, r4, r5, lr}
a0013cb0: e59f403c ldr r4, [pc, #60] ; a0013cf4
a0013cb4: e59f103c ldr r1, [pc, #60] ; a0013cf8
a0013cb8: e1a00004 mov r0, r4
a0013cbc: eb00285d bl a001de38
a0013cc0: e1a00004 mov r0, r4
a0013cc4: ebffc073 bl a0003e98
a0013cc8: e1a05000 mov r5, r0
a0013ccc: e1a00004 mov r0, r4
a0013cd0: ebffc070 bl a0003e98
a0013cd4: e2601080 rsb r1, r0, #128 ; 0x80
a0013cd8: e0840005 add r0, r4, r5
a0013cdc: ebffdfe6 bl a000bc7c
a0013ce0: e1a00004 mov r0, r4
a0013ce4: e59f1010 ldr r1, [pc, #16] ; a0013cfc
a0013ce8: eb00272e bl a001d9a8
a0013cec: e1a00004 mov r0, r4
a0013cf0: e8bd8038 pop {r3, r4, r5, pc}
a0013cf4: a005c170 andge ip, r5, r0, ror r1
a0013cf8: a0050c1c andge r0, r5, ip, lsl ip
a0013cfc: a005086b andge r0, r5, fp, ror #16

通过上面的反汇编代码可以发现只有Os优化时,所有的newlib库函数都会被调用,其他的优化等级可能导致部分函数优化掉了。

我这边使用的编译器版本

gcc version 4.7.2 (Sourcery CodeBench Lite 2012.09-63)
gcc version 4.8.1 (Sourcery CodeBench Lite 2013.11-24)

难道是编译器本身的问题?

附崩溃信息:

\ | /
- RT - Thread Operating System
/ | \ 2.0.0 build Aug 27 2014
2006 - 2013 Copyright by rt-thread team
Execption:
r00:0x00000007 r01:0xa0079234 r02:0x0000003e r03:0xa0079233
r04:0xa0079232 r05:0x00000000 r06:0x00000000 r07:0x00000000
r08:0x00000000 r09:0x00000000 r10:0x00000000
fp :0xa0079200 ip :0x01010101
sp :0x00000000 lr :0x00000000 pc :0xa0024a38
cpsr:0x00000013

data abort
thread - tshell stack:
thread pri status sp stack size max used left tick error
-------- ---- ------- ---------- ---------- ---------- ---------- ---
tidle 0xff ready 0x00000044 0x00000100 0x00000044 0x00000020 000
timer 0x08 suspend 0x0000007c 0x00000200 0x0000007c 0x00000009 000
tshell 0x14 ready 0x00000044 0x00001000 0x00000084 0x0000000a 000
init 0x50 ready 0x00000044 0x00000800 0x00000044 0x00000014 000
shutdown...

这个崩溃信息是上面O1优化等级对应的代码产生的。



-------- 原始邮件 --------
主题:回复: libc printf测试崩溃问题
发件人:weety
收件人:rt-threa...@googlegroups.com
抄送:


Grissiom

unread,
Aug 27, 2014, 1:51:04 AM8/27/14
to rt-threa...@googlegroups.com
从寄存器信息和反汇编来看,是 SP 为 0 导致 pop 失败了…… O1 的时候也有很多 bl 啊……

可以在所有优化等级里加入 -g,然后 objdump 会解析出调试信息出来~

--
Cheers,
Grissiom

weety

unread,
Aug 27, 2014, 4:49:51 AM8/27/14
to rt-threa...@googlegroups.com
确实是sp指针有问题,我这边修改了代码,打印当前sp指针地址
const char* finsh_get_prompt()
{
register rt_uint32_t value;

#define _MSH_PROMPT "msh "
#define _PROMPT "finsh "
static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {0};
asm ("mov %0, sp"::"r"(value));
rt_kprintf("sp -- 0x%08x\n", value);


#ifdef FINSH_USING_MSH
if (msh_is_used()) strcpy(finsh_prompt, _MSH_PROMPT);
else
#endif
strcpy(finsh_prompt, _PROMPT);

#ifdef DFS_USING_WORKDIR
/* get current working directory */
getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - rt_strlen(finsh_prompt));
#endif
asm ("mov %0, sp"::"r"(value));
rt_kprintf("sp1 -- 0x%08x\n", value);
strcat(finsh_prompt, ">");
asm ("mov %0, sp"::"r"(value));
rt_kprintf("sp2 -- 0x%08x\n", value);

return finsh_prompt;

}

\ | /
- RT - Thread Operating System
/ | \ 2.0.0 build Aug 27 2014
2006 - 2013 Copyright by rt-thread team
sp -- 0xa0061278
sp1 -- 0xa0061278
Execption:
r00:0x00000007 r01:0xa0060178 r02:0x80000000 r03:0x0000003e
r04:0xa0061278 r05:0xa0060170 r06:0x00000006 r07:0x00000000

r08:0x00000000 r09:0x00000000 r10:0x00000000
fp :0x00000000 ip :0x01010101
sp :0x00000000 lr :0x00000000 pc :0xa0015de4

cpsr:0x00000013
data abort
thread - tshell stack:
thread pri status sp stack size max used left tick error
-------- ---- ------- ---------- ---------- ---------- ---------- ---
tidle 0xff ready 0x00000044 0x00000100 0x00000044 0x00000020 000
timer 0x08 suspend 0x00000074 0x00000200 0x00000074 0x00000009 000
tshell 0x14 ready 0x00000044 0x00001000 0x000000cc 0x0000000a 000

init 0x50 ready 0x00000044 0x00000800 0x00000044 0x00000014 000
shutdown...

可以看到在strcat函数前面两次的sp指针打印正确,最后一个还没有打印出来,已经开启了O2优化和-g选项,

a0015d68 :
a0015d68: e92d4070 push {r4, r5, r6, lr}
a0015d6c: e3a04000 mov r4, #0
a0015d70: e1a0400d mov r4, sp
a0015d74: e59f007c ldr r0, [pc, #124] ; a0015df8
a0015d78: e1a01004 mov r1, r4
a0015d7c: ebffbd1b bl a00051f0
a0015d80: e59f5074 ldr r5, [pc, #116] ; a0015dfc
a0015d84: e59f3074 ldr r3, [pc, #116] ; a0015e00
a0015d88: e8930003 ldm r3, {r0, r1}
a0015d8c: e1a03821 lsr r3, r1, #16
a0015d90: e5850000 str r0, [r5]
a0015d94: e1a00005 mov r0, r5
a0015d98: e1c510b4 strh r1, [r5, #4]
a0015d9c: e5c53006 strb r3, [r5, #6]
a0015da0: ebffbab0 bl a0004868
a0015da4: e1a06000 mov r6, r0
a0015da8: e1a00005 mov r0, r5
a0015dac: ebffbaad bl a0004868
a0015db0: e2601080 rsb r1, r0, #128 ; 0x80
a0015db4: e0850006 add r0, r5, r6
a0015db8: ebffdd05 bl a000d1d4
a0015dbc: e1a0400d mov r4, sp
a0015dc0: e59f003c ldr r0, [pc, #60] ; a0015e04
a0015dc4: e1a01004 mov r1, r4
a0015dc8: ebffbd08 bl a00051f0
a0015dcc: e1a00005 mov r0, r5
a0015dd0: eb002d47 bl a00212f4
a0015dd4: e59f302c ldr r3, [pc, #44] ; a0015e08
a0015dd8: e1d330b0 ldrh r3, [r3]
a0015ddc: e18530b0 strh r3, [r5, r0]
a0015de0: e1a0400d mov r4, sp
a0015de4: e59f0020 ldr r0, [pc, #32] ; a0015e0c
a0015de8: e1a01004 mov r1, r4
a0015dec: ebffbcff bl a00051f0
a0015df0: e1a00005 mov r0, r5
a0015df4: e8bd8070 pop {r4, r5, r6, pc}
a0015df8: a0054488 andge r4, r5, r8, lsl #9
a0015dfc: a0060170 andge r0, r6, r0, ror r1
a0015e00: a0054498 mulge r5, r8, r4
a0015e04: a00544a0 andge r4, r5, r0, lsr #9
a0015e08: a0054054 andge r4, r5, r4, asr r0
a0015e0c: a00544b0 ; instruction: 0xa00544b0

sp指针为0的确有点奇怪。



-------- 原始邮件 --------
主题:Re: libc printf测试崩溃问题
发件人:Grissiom
收件人:rt-threa...@googlegroups.com
抄送:


--

weety

unread,
Aug 27, 2014, 5:55:27 AM8/27/14
to rt-threa...@googlegroups.com
之前的问题分析有点问题,这里的分析更靠近问题本质

之前讨论到sp指针可能有问题,这里基本可以排除,sp值不正确应该是异常中断中打印有点问题,分析崩溃信息,


\ | /
- RT - Thread Operating System
/ | \ 2.0.0 build Aug 27 2014
2006 - 2013 Copyright by rt-thread team
sp -- 0xa0061278
sp1 -- 0xa0061278
Execption:
r00:0x00000007 r01:0xa0060178 r02:0x80000000 r03:0x0000003e
r04:0xa0061278 r05:0xa0060170 r06:0x00000006 r07:0x00000000
r08:0x00000000 r09:0x00000000 r10:0x00000000
fp :0x00000000 ip :0x01010101
sp :0x00000000 lr :0x00000000 pc :0xa0015de4
cpsr:0x00000013
data abort
thread - tshell stack:
thread pri status sp stack size max used left tick error
-------- ---- ------- ---------- ---------- ---------- ---------- ---
tidle 0xff ready 0x00000044 0x00000100 0x00000044 0x00000020 000
timer 0x08 suspend 0x00000074 0x00000200 0x00000074 0x00000009 000
tshell 0x14 ready 0x00000044 0x00001000 0x000000cc 0x0000000a 000
init 0x50 ready 0x00000044 0x00000800 0x00000044 0x00000014 000
shutdown...

可以得知程序崩溃点的pc值为0xa0015de4,而当前执行的代码是pc-8,即0xa0015ddc,对应的指令为


a0015ddc: e18530b0 strh r3, [r5, r0]

通过上面的寄存器信息,r5=0xa0060170, r0=0x00000007,即要访问的地址是0xa0060177,而strh是半字存储指令,地址低2bit必须为0,那么这调指令执行后就会出现data about异常。

通过分析c代码,可以得知这个操作就是在执行strcat功能,将">"字符串拼接到finsh_prompt后面,由于之前的finsh_prompt中已经存放了“finsh /”,刚好是7个字符,因此需要将“>”拼接到finsh_prompt之后形成完整的“finsh />”命令提示符。

将代码中
#define _PROMPT "finsh "
定义修改为
#define _PROMPT "finsh "
即多增加一个空格,可以满足对齐访问,这样处理后,程序运行正常

\ | /
- RT - Thread Operating System
/ | \ 2.0.0 build Aug 27 2014
2006 - 2013 Copyright by rt-thread team
sp -- 0xa0061278
sp1 -- 0xa0061278
sp2 -- 0xa0061278
finsh />Device File System initialized!


sp -- 0xa0061278
sp1 -- 0xa0061278
sp2 -- 0xa0061278
finsh />

sp -- 0xa0061278
sp1 -- 0xa0061278
sp2 -- 0xa0061278
finsh />

通过上面的分析,是不对齐访问导致的异常,不知道大家有没有什么想法。


附c代码和反汇编代码:


const char* finsh_get_prompt()
{
register rt_uint32_t value;
#define _MSH_PROMPT "msh "
#define _PROMPT "finsh "
static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {0};
asm ("mov %0, sp"::"r"(value));
rt_kprintf("sp -- 0x%08x\n", value);

#ifdef FINSH_USING_MSH
if (msh_is_used()) strcpy(finsh_prompt, _MSH_PROMPT);
else
#endif
strcpy(finsh_prompt, _PROMPT);

#ifdef DFS_USING_WORKDIR
/* get current working directory */
getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - rt_strlen(finsh_prompt));
#endif
asm ("mov %0, sp"::"r"(value));
rt_kprintf("sp1 -- 0x%08x\n", value);
strcat(finsh_prompt, ">");
asm ("mov %0, sp"::"r"(value));
rt_kprintf("sp2 -- 0x%08x\n", value);

return finsh_prompt;
}

来自我的荣耀6


-------- 原始邮件 --------

主题:回复: libc printf测试崩溃问题
发件人:weety
收件人:rt-threa...@googlegroups.com
抄送:


weety

unread,
Aug 27, 2014, 8:47:51 AM8/27/14
to rt-threa...@googlegroups.com
本来是要操作字符串,反汇编后竟然出现了ldrh,strh这样的半字操作指令,这个算不算是编译器的问题?

Peng Fan

unread,
Aug 27, 2014, 10:08:17 AM8/27/14
to rt-threa...@googlegroups.com
arm是支持非对齐访问的,前提是需要设置协处理器中相应的非对齐访问引起异常的bit位。
1. 清除相应的bit位:
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #2
mcr p15, 0, r0, c1, c0, 0
2. 或者尝试给编译器传参

Regards,
Peng.

weety

unread,
Aug 27, 2014, 10:59:20 AM8/27/14
to rt-threa...@googlegroups.com
这些方法是可以解决问题,不过只是规避了问题,编译器在操作字符串时使用了半字操作指令,这应该是优化出来的问题,也就是编译器可能存在问题。



于 2014/8/27 22:08, Peng Fan 写道:
arm是支持非对齐访问的,前提是需要设置协处理器中相应的非对齐访问引起异常的bit位。
1. 清除相应的bit位:
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #2
mcr p15, 0, r0, c1, c0, 0
2. 或者尝试给编译器传参

Regards,
Peng.

在 2014年8月27日 下午8:47,weety <luohu...@gmail.com>写 道:
本 来是要操作字符串,反汇编后竟然出现了ldrh,strh这样的半字操作指令,这个算不算是编译器的问题?




-------- 原始邮件 --------
主题:回复: libc printf测试崩溃问题
发件人:weety
收件人:rt-threa...@googlegroups.com
抄送:


之 前的问题分析有点问题,这里的分析更靠近问题本质

之前讨论到sp指针可能有问题,这里基本可以排除,sp值不正确应该是异常中断中打印有点 问题,分析崩溃信息,


\ | /
- RT - Thread Operating System
/ | \ 2.0.0 build Aug 27 2014
2006 - 2013 Copyright by rt-thread team
sp -- 0xa0061278
sp1 -- 0xa0061278
Execption:
r00:0x00000007 r01:0xa0060178 r02:0x80000000 r03:0x0000003e
r04:0xa0061278 r05:0xa0060170 r06:0x00000006 r07:0x00000000
r08:0x00000000 r09:0x00000000 r10:0x00000000
fp :0x00000000 ip :0x01010101
sp :0x00000000 lr :0x00000000 pc :0xa0015de4
cpsr:0x00000013
data abort
thread - tshell stack:
thread pri status sp stack size max used left tick error
-------- ---- ------- ---------- ---------- ---------- ---------- ---
tidle 0xff ready 0x00000044 0x00000100 0x00000044 0x00000020 000
timer 0x08 suspend 0x00000074 0x00000200 0x00000074 0x00000009 000
tshell 0x14 ready 0x00000044 0x00001000 0x000000cc 0x0000000a 000
init 0x50 ready 0x00000044 0x00000800 0x00000044 0x00000014 000
shutdown...

可以得知程序崩溃点的pc值为0xa0015de4,而当前执行的代码是pc-8,即 0xa0015ddc,对应的指令为


a0015ddc: e18530b0 strh r3, [r5, r0]

通过上面的寄存器信息,r5=0xa0060170, r0=0x00000007,即要访问的地址是0xa0060177,而strh是半字存储指令,地址低2bit必须为0,那么这调指令执行后就会出现 data about异常。

通过分析c代码,可以得知这个操作就是在执行strcat功能,将">"字符串拼接 到finsh_prompt后面,由于之前的finsh_prompt中已经存放了 “finsh /”,刚好是7个字符,因此需要将“>”拼接到finsh_prompt之后形成完整的“finsh />”命令提示符。
确 实是sp指针有问题,我这边修改了代码,打印当前sp指针地址
可以看到在strcat函数前面两次的sp指针打印正确,最后一个还没有打印出 来,已经开启了O2优化和-g选项,
通过反汇编分析,发现不同优化等级优化后二进制代码相差 较大,但只有Os优化的代码调用了strcat函数,其 他的优化等级(O0,O1,O2,O3)都没有调用 strcat函数,被优化掉了。

--
Cheers,
Grissiom

Grissiom

unread,
Aug 27, 2014, 11:21:51 AM8/27/14
to rt-threa...@googlegroups.com
2014-08-27 22:59 GMT+08:00 weety <luohu...@gmail.com>:
这些方法是可以解决问题,不过只是规避了问题,编译器在操作字符串时使用了半字操作指令,这应该是优化出来的问题,也就是编译器可能存在问题。



在操作字符串的时候出现半字操作也是很正常的,在 strcpy 的时候,如果条件符合,将指针转换成 uint32_t* 也是很正常的做法。当然,前提是不引起功能上的异常。

--
Cheers,
Grissiom

Grissiom

unread,
Aug 27, 2014, 11:37:48 AM8/27/14
to rt-threa...@googlegroups.com
好吧,这个是我搞错了…… T_T

--
Cheers,
Grissiom

Ming Bai

unread,
Aug 27, 2014, 12:41:31 PM8/27/14
to rt-thread用户组
这种优化是很危险的,因为严重的平台相关。题主的这个问题感觉就像是在不支持非对齐的arch上打开了类似的优化,inline了不属于这个arch的代码。gcc不同的arch也有不同的配置,就像
https://github.com/gcc-mirror/gcc/blob/master/gcc/config/arm/arm.h
这里面很多alignment的设置可能就会对最后产生的代码有影响(猜测,没试过)。
我感觉这可能不是个‘bug',更可能是配置不当吧(比如gcc不是给某个arch专属的)。


--

bernard

unread,
Aug 28, 2014, 2:41:11 AM8/28/14
to rt-thread用户组
这个坑很深很深呐~~

编译的命令行是什么样的呢?

weety

unread,
Aug 28, 2014, 3:46:24 AM8/28/14
to rt-threa...@googlegroups.com
编译器配置如下:

if PLATFORM == 'gcc':
# toolchains
PREFIX = 'arm-none-eabi-'
#PREFIX = 'arm-none-linux-gnueabi-'
CC = PREFIX + 'gcc'
AS = PREFIX + 'gcc'
AR = PREFIX + 'ar'
LINK = PREFIX + 'gcc'
TARGET_EXT = 'axf'
SIZE = PREFIX + 'size'
OBJDUMP = PREFIX + 'objdump'
OBJCPY = PREFIX + 'objcopy'

DEVICE = ' -mcpu=arm1176jzf-s'
CFLAGS = DEVICE
AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp' + ' -DTEXT_BASE=' + TextBase
LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread_arm11.map,-cref,-u,_start -T arm11_dram.ld' + ' -Ttext ' + TextBase

CPATH = ''
LPATH = ''

CFLAGS += ' –O2'

POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n'


-------- 原始邮件 --------
主题:Re: libc printf测试崩溃问题
发件人:bernard
收件人:rt-thread用户组
抄送:

Peng Fan

unread,
Aug 28, 2014, 6:46:06 AM8/28/14
to rt-threa...@googlegroups.com
如果是非对齐访问的话,为什么不设置cp15里面的允许非对齐访问呢?
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf   table3-39
[1] A bit Banked Enables strict alignment of data to detect alignment faults in data accesses. The A bit 
setting takes priority over the U bit.
0 = Strict alignment fault checking disabled, reset value.
1 = Strict alignment fault checking enabled

gcc会生成非对齐访问指令的,如果指定的架构参数支持非对齐访问的话。

weety

unread,
Aug 28, 2014, 9:30:01 AM8/28/14
to rt-threa...@googlegroups.com
这个问题基本上算解决了。

需要增加-mno-unaligned-access编译选项

下面是查阅gcc文档得到这个选项的解释:
-munaligned-access
-mno-unaligned-access
Enables (or disables) reading and writing of 16- and 32- bit values from ad-
dresses that are not 16- or 32- bit aligned. By default unaligned access is
disabled for all pre-ARMv6 and all ARMv6-M architectures, and enabled for
all other architectures. If unaligned access is not enabled then words in packed
data structures will be accessed a byte at a time.
The ARM attribute Tag_CPU_unaligned_access will be set in the generated
object fil et oeithe rtru eo rfalse ,dependin gupo nth esettin go fthi soption.
If unaligned access is enabled then the preprocessor symbol __ARM_FEATURE_
UNALIGNED will also be defined.

也就是armv6之前的版本都是默认禁止不对齐访问的,armv6及之后的版本是默认使能了不对齐访问,这样就可以解释编译出来的代码会遇到不对齐访问的问题。

增加-mno-unaligned-access编译选项的反汇编代码
a0015d68 :
a0015d68: e92d4038 push {r3, r4, r5, lr}
a0015d6c: e59f4054 ldr r4, [pc, #84] ; a0015dc8
a0015d70: e59f3054 ldr r3, [pc, #84] ; a0015dcc
a0015d74: e8930003 ldm r3, {r0, r1}
a0015d78: e1a03821 lsr r3, r1, #16
a0015d7c: e5840000 str r0, [r4]
a0015d80: e1a00004 mov r0, r4
a0015d84: e5c43006 strb r3, [r4, #6]
a0015d88: e1c410b4 strh r1, [r4, #4]
a0015d8c: ebffbab5 bl a0004868
a0015d90: e1a05000 mov r5, r0
a0015d94: e1a00004 mov r0, r4
a0015d98: ebffbab2 bl a0004868
a0015d9c: e2601080 rsb r1, r0, #128 ; 0x80
a0015da0: e0840005 add r0, r4, r5
a0015da4: ebffdd0a bl a000d1d4
a0015da8: e1a00004 mov r0, r4
a0015dac: eb002d40 bl a00212b4
a0015db0: e59f1018 ldr r1, [pc, #24] ; a0015dd0
a0015db4: e0840000 add r0, r4, r0
a0015db8: e3a02002 mov r2, #2
a0015dbc: eb0026e6 bl a001f95c
a0015dc0: e1a00004 mov r0, r4
a0015dc4: e8bd8038 pop {r3, r4, r5, pc}
a0015dc8: a0060170 andge r0, r6, r0, ror r1
a0015dcc: a0054448 andge r4, r5, r8, asr #8
a0015dd0: a0054014 andge r4, r5, r4, lsl r0

可以看到strcat函数被memcpy函数替换掉了,并没有生成ldrh, strh等半字操作指令,因此也就不存在访问对齐问题了。

我这边也反汇编了at91sam9260平台的代码,
20021c48 :
20021c48: e92d4038 push {r3, r4, r5, lr}
20021c4c: e59f3054 ldr r3, [pc, #84] ; 20021ca8
20021c50: e59f4054 ldr r4, [pc, #84] ; 20021cac
20021c54: e8930003 ldm r3, {r0, r1}
20021c58: e1a03821 lsr r3, r1, #16
20021c5c: e5840000 str r0, [r4]
20021c60: e1a00004 mov r0, r4
20021c64: e5c43006 strb r3, [r4, #6]
20021c68: e1c410b4 strh r1, [r4, #4]
20021c6c: ebff9256 bl 200065cc
20021c70: e1a05000 mov r5, r0
20021c74: e1a00004 mov r0, r4
20021c78: ebff9253 bl 200065cc
20021c7c: e2601080 rsb r1, r0, #128 ; 0x80
20021c80: e0840005 add r0, r4, r5
20021c84: ebffb2ae bl 2000e744
20021c88: e1a00004 mov r0, r4
20021c8c: eb008bca bl 20044bbc
20021c90: e59f1018 ldr r1, [pc, #24] ; 20021cb0
20021c94: e3a02002 mov r2, #2
20021c98: e0840000 add r0, r4, r0
20021c9c: eb007f59 bl 20041a08
20021ca0: e1a00004 mov r0, r4
20021ca4: e8bd8038 pop {r3, r4, r5, pc}
20021ca8: 200870b8 strhcs r7, [r8], -r8
20021cac: 20308730 eorscs r8, r0, r0, lsr r7
20021cb0: 200863fc strdcs r6, [r8], -ip

也是采用了memcpy函数来替换strcat,由于at91sam9260是armv5架构,默认是禁止不对齐访问的,因此也不存在这个问题。


由于编译器默认选项是使能了不对齐访问,可以通过设置cp15寄存器来使能不对齐数据访问,这样也可以解决问题,但不对齐总线访问效率会下降。另外,如果cp15使能了不对齐访问,对软件系统中的一些异常问题将不能够发现,特别是地址错误时可能不会触发data abort异常。

因此,通过编译器选项禁止不对齐访问解决问题是最好的方法,这样编译器也不会生成不对齐的指令。
Reply all
Reply to author
Forward
0 new messages