oss可以做视频网站吗,c 网站开发 书,科技 网站 推荐,wordpress文件权限设置笔者接着来介绍一下Bootloader的跳转代码以及优化 1、跳转代码理解
跳转代码可能要涉及到芯片架构的知识,要跳转到对应的位置#xff0c;还要设置相关的SP 堆栈指针#xff0c;具体可以参考笔者这篇文章BootLoader的理解与实现。 STM32的跳转代码如下所示#xff1a;
u32 … 笔者接着来介绍一下Bootloader的跳转代码以及优化 1、跳转代码理解
跳转代码可能要涉及到芯片架构的知识,要跳转到对应的位置还要设置相关的SP 堆栈指针具体可以参考笔者这篇文章BootLoader的理解与实现。 STM32的跳转代码如下所示
u32 ApplicationAddress 0x08008000; //app 地址
typedef void (*pFunction)(void); //函数指针
void Jump_Used_Main(void)
{printf(\r\nboot2-------- Jump APP --------- \r\n);/* 判断栈顶 是否位于 0x20000000 128K */if ( ((*(__IO uint32_t*)ApplicationAddress) 0x20000000) ((*(__IO uint32_t*)ApplicationAddress) 0x20010000)){ JumpAddress *(__IO uint32_t*) (ApplicationAddress 4);Jump_To_Application (pFunction) JumpAddress;/*close the interrupt*/_disable_interrupr();__set_MSP(*(__IO uint32_t*) ApplicationAddress);Jump_To_Application();}else{ while(1){printf(\r\nboot2 error\r\n);}}
}可以看到__set_MSP(* (__IO uint32_t *) ApplicationAddress);这行代码中在取地址里面的内容时增加了__IO的选项
#define __IO volatile保证是从内存里面读出来的SP栈指针的数据然后设置到MSP否则可能导致SP设置错误程序跑飞。
2、跳转代码编译优化
笔者在实际开发的过程中遇到了一个跳转过去就崩掉的情况单步调试发现到Set_MSP就崩掉了很是奇怪通过汇编一查看就很明显了。
NXP LPC的单片机arm-noen-eabi-gcc的编译器。
typedef struct addr_manager_struct
{xxxxxxx;u32 image_load_addr;u32 image_exec_addr;
}addr_manager_t;
u8 main_jump(addr_manager_t* info)
{u32 *image_addr (u32*)info-image_load_addr;u32 *sp (u32*) image_addr [0];u32 *jump (u32*) image_addr [1];disable_interrupt();set_msp((u32)sp);(*jump)();return 0;
}上述在设置完SP之后放到r2寄存器里面然后获取jump地址放到r3里面之后禁止中断修改了r2然后禁止中断然后就把r2传到SP里面造成跑飞可能是一个不存在的地址
有人说sp设置的时候需要加volatile即使改成下面的函数也没用效果
void jump_main(addr_manager_t* info)
{u32 *image_addr (u32*)info-image_load_addr;u32 *sp (u32*) image_addr [0];u32 *jump (u32*) image_addr [1];disable_interrupt();set_msp((volatile u32)sp);(*jump)();
}接着再继续改直
接通过Image指针取内容然后去获取到SP值然后就可以了看来是禁止中断的这个函数所影响禁止中断如果不报存返回值则不会对SP的值产生影响
void jump_main(addr_manager_t* info)
{u32 *image_addr (u32*)info-image_load_addr;u32 *sp (u32*) image_addr [0];u32 *jump (u32*) image_addr [1];disable_interrupt();set_msp(*((volatile u32*)image_addr));(*jump)();
}接着我们再尝试一种方法就是将禁止中断函数移动位置看一下情况发现也是可以的。
void jump_main(addr_manager_t* info)
{disable_interrupt();u32 *image_addr (u32*)info-image_load_addr;u32 *sp (u32*) image_addr [0];u32 *jump (u32*) image_addr [1];set_msp((u32)sp);(*jump)();
}然后我们看一下set sp的汇编函数也并没有指明操作的寄存器很可能是GCC编译器优化的bug。
inline void set_sp(u32 sp_value)
{asm volatile (msr msp, %0 : r(sp_value))
}然后我们再看看armcc编译器的结果没有任何问题。
armcc对于禁止中断的返回值没有处理而GCC处理了然后导致了问题将其中断保存值填到r2里面然后r2的sp值被覆盖其实应用层如果没有对返回值进行处理即使函数有返回值编译器优化会将其处理掉。显然GCC的编译器优化做的还是差一点。