在stm32 IAP例程中,跳转到APP区的时候,都会检查栈顶地址是否合法,以及reset地址是否正确等信息,那么这些判断具体依据什么原理???
以stm32H743为例说明↓↓↓↓
检查栈顶是否合法代码如下:
#define STM32_APP_BASE 0x08020000 // APP flash start address
void iap_jumpapp(void)
{
// 检查栈顶是否合法,,确保栈顶落在0x24000000-0x24FFFFFF 之间,刚好在stm32h7的RAM范围内
if (((*(uint32_t*)(STM32_APP_BASE)) & 0xff000000 ) == 0x24000000 ) {
// 检查reset入口是否正确
if (((*(uint32_t*)(STM32_APP_BASE + 4)) & 0x0fff0000 ) == 0x08020000 ) {
JumpToApp = (pfunction)((*(uint32_t*)(STM32_APP_BASE + 4)));
MSR_MSP(*(uint32_t*)STM32_APP_BASE);
JumpToApp();
}
} else {
...
}
}
栈顶地址 和 reset入口地址具体是什么???
从startup_stm32h743xx.s中可以看出,程序第一个地址存放的是__initial_sp,紧接着第二个地址存放的是Reset_Handler;这两个正是所谓的栈顶地址 reset 入口
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
代码 | 说明 | 备注 |
---|---|---|
__initial_sp | 栈顶地址 | 程序占用的最大RAM地址,占用RAM大小=RW-data + ZI-data |
Reset_Handler | reset入口 | 程序上电后,第一个运行的函数地址 |
结合map文件和bin文件进行分析
- 生成map文件中,__initial_sp = 0x2400f2a8
...
HEAP 0x2400c2a8 Section 4096 startup_stm32h743xx.o(HEAP)
Heap_Mem 0x2400c2a8 Data 4096 startup_stm32h743xx.o(HEAP)
STACK 0x2400d2a8 Section 8192 startup_stm32h743xx.o(STACK)
Stack_Mem 0x2400d2a8 Data 8192 startup_stm32h743xx.o(STACK)
__initial_sp 0x2400f2a8 Data 0 startup_stm32h743xx.o(STACK)
Global Symbols
...
另外,从中可以看出
堆栈Stack范围 0x2400d2a8 - 0x2400f2a8 占用8K
Heap范围 0x2400c2a8 - 0x2400d2a8 占用4K
和startup_stm32h743xx.s中的定义对应Stack_Size EQU 0x2000 ;;0x400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp ; <h> Heap Configuration ; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Heap_Size EQU 0x1000 ;;0x200 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit PRESERVE8 THUMB
- map文件中,Reset_Handler = 0x0802038d
Reset_Handler 0x0802038d Thumb Code 8 startup_stm32h743xx.o(.text)
生成bin文件中
第一个数据 a8 f2 00 24 即 0x2400f2a8 (__initial_sp)
第二个数据 8d 03 02 08 即 0x0802038d (Reset_Handler)
a8 f2 00 24 8d 03 02 08 31 60 02 08 f1 59 02 08
15 60 02 08 25 0f 02 08 89 87 02 08 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 09 65 02 08
41 12 02 08 00 00 00 00 c5 61 02 08 5d 65 02 08
a7 03 02 08 a7 03 02 08 a7 03 02 08 a7 03 02 08
a7 03 02 08 a7 03 02 08 a7 03 02 08 a7 03 02 08
a7 03 02 08 a7 03 02 08 a7 03 02 08 61 0f 02 08
6d 0f 02 08 a7 03 02 08 a7 03 02 08 a7 03 02 08
a7 03 02 08 a7 03 02 08 a7 03 02 08 a7 03 02 08
a7 03 02 08 a7 03 02 08 a7 03 02 08 a7 03 02 08
所以跳转的时候,直接跳转到0x0802038d地址即可!
生成bin文件user run命令:
fromelf.exe --bin -o “$L@L.bin” “#L”
所以
(*(uint32_t*)(STM32_APP_BASE) 即 __initial_sp
(*(uint32_t*)(STM32_APP_BASE+4) 即 Reset_Handler