绝大多数产品开发,软件一般都会设计成 boot + app 的形式,这是方便后续软件更新,否则更新会变成一个很麻烦的事情。
网上随处可见的跳转程序大概如下:
voidjump2app()
{
typedefvoid(*func_app_start)(void);
__disable_irq();
func_app_start app_start=(func_app_start)(*(__IOuint32_t*)(APP_START_ADDR+4));
__set_MSP(*(__IOuint32_t*)(APP_START_ADDR));//设置栈顶地址
app_start();
}
大多数情况下,该程序跳转正常,但当你改变了编译器优化级别时,可能直接就 hardfault 了。
此时你会莫名其妙,为什么???
从鱼鹰18年接触到 boot 知识以来,都觉得这样的跳转程序理所当然,并且也没出现过问题,直到最近修改了优化级别,发现程序直接hardfault 了,根本没跳转到 app 中,才发现了这里隐藏的 bug。
调试发现,app_start 这个函数指针变成了异常值,但鱼鹰查看0x08040000 处的内存空间值是正常的。那只能是代码问题了。
因此结合汇编和在线调试,终于发现,执行__set_MSP 这条语句前app_start 的值是正常的,执行后,这个值就异常了。
再结合 C 语言关于栈、局部变量的知识,立刻就知道是因为重新设置栈顶地址,但汇编代码不变,但是从新栈位置偏移取函数地址,因此跳转失败。
如:
新栈的位置,变量的值是未知的,用它进行跳转,失败是必然的。
但是为什么大部分情况下程序没有问题呢?
这是因为跳转程序很简单,局部变量少,那么这个app_start 局部变量编译器可能就不会从栈中分配,而直接用一个寄存器存储数据,而寄存器是不受栈顶位置影响的,自然程序能跳转了。
但我们不能让程序运行正常与否由编译器随机决定,因此我们要避免这个 bug,让程序不管在何种优化级别、函数多复杂的情况下,依然可以正常运行,因此还是有必要进行优化的。
最简单的方法,就是把这个app_start 局部变量变成全局变量。这样变量就不会受到栈顶位置影响,自然可以避免了。
如:
voidjump2app()
{
typedefvoid(*func_app_start)(void);
__disable_irq();
static func_app_start app_start=(func_app_start)(*(__IOuint32_t*)(APP_START_ADDR+4));
__set_MSP(*(__IOuint32_t*)(APP_START_ADDR));//设置栈顶地址
app_start();
}
如有更好的优化方法,欢迎留言讨论。
-
寄存器
+关注
关注
31文章
5342浏览量
120280 -
函数
+关注
关注
3文章
4329浏览量
62585 -
变量
+关注
关注
0文章
613浏览量
28364
原文标题:本跳转程序靠bug运行,请不要优化
文章出处:【微信号:emOsprey,微信公众号:鱼鹰谈单片机】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论