本跳转程序靠bug运行,请不要优化

描述

 

绝大多数产品开发,软件一般都会设计成 boot + app 的形式,这是方便后续软件更新,否则更新会变成一个很麻烦的事情。

网上随处可见的跳转程序大概如下:

#define APP_START_ADDR          0x08040000 


void jump2app()
{
  typedef void (*func_app_start)(void);
   
  __disable_irq();
  
  func_app_start app_start = (func_app_start) (*(__IO  uint32_t*) (APP_START_ADDR + 4));
  
  __set_MSP(*(__IO  uint32_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 局部变量变成全局变量这样变量就不会受到栈顶位置影响,自然可以避免了。

如:

#define APP_START_ADDR          0x08040000 


void jump2app()
{
  typedef void (*func_app_start)(void);
   
  __disable_irq();
  
  static func_app_start app_start = (func_app_start) (*(__IO  uint32_t*) (APP_START_ADDR + 4));
  
  __set_MSP(*(__IO  uint32_t*) (APP_START_ADDR));// 设置栈顶地址


  app_start();
}

 

如有更好的优化方法,欢迎留言讨论。



 


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分