函数调用实现程序跳转

《C陷阱与缺陷》上讲到一个很有趣的事情,

当计算机启动时,硬件将调用首地址为0位置的子例程,要设计出一个C语句,显示的调用它,

最后得出的语句是如下形式

(*(void(*)())0)();

其思想原理是将0地址当成一个指针,强制转换成一个函数指针,这个函数的输入参数是void返回值也是void,然后解引用调用这个函数指针去执行这个函数,也就是main函数

函数指针并不是什么高深莫测的东西,在工作中经常会用到,特别是回调函数,但是我们使用的时候好像并不会对这个函数指针去解引用然后在调用,而是直接调用函数指针去执行。

于是似乎我们可以如下来表示

typedef void (*main_cb)(void);

(*(main_cb)0)();

//or

//((main_cb)0)();

  在我们的一般项目中这种跳转是几乎不会使用的,除非你对自己的硬件及存储非常了解,否则这都是致命的。

但是在我的项目经历中确实有个程序就是利用这种地址跳转来实现对程序本身的升级更新,这一段stm32上的代码。

 

正常运行的功能代码我们是控制在21k以内,然后烧录在机器的-x08000000上,保证不会超过0x08005400.

然后我们还有一段代码就是专门用来升级功能的,烧录在0x08005400地址上,他的作用将0x08000000地址上的数据擦除,然后从串口接收数据,写到0x0800000地址实现功能代码的更新,更新完了软复位重启。

 

所以以上实现的逻辑就是从本身main函数的循环中跳转到硬件的另一个地址上执行另外一个功能的代码。

 

#ifdef SUPPORT_MCU_IAP
#define IAP_ADDRESS (uint32_t)0x08005400


#define EEP_ADDRESS (uint32_t)0x08007FF0

pFunction Jump_To_Application;

uint32_t JumpAddress;

_UINT8 mcuUpdateEnable;

_UINT8 ARMUpdateEnable;


#endif





#ifdef SUPPORT_MCU_IAP if (((*(__IO uint32_t*)IAP_ADDRESS) & 0x2FFE0000 ) == 0x20000000) { /* Jump to user application */ JumpAddress = *(__IO uint32_t*) (IAP_ADDRESS + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t*) IAP_ADDRESS); /* Jump to application */ Jump_To_Application(); } while(1) { } #endif

  

  

  

posted @ 2019-03-28 16:55  mcdull^0^  阅读(773)  评论(0编辑  收藏  举报