STM32启动过程详解
初始化栈顶指针sp
将0x08000000 - 0x08000003中的值赋值给sp,由硬件自动完成。
执行复位程序Reset_Handler
Reset_Handler中先调用SystemInit进行系统初始化,然后调用__main函数。在__main函数中会初始化RW和ZI段,最后跳转到main函数。
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
初始化RW、ZI段
在生成的map文件中有两个符号Region $ $Table $ $Base,Region $ $Table $ $ Limit。这两个符号会在初始化RW和ZI的库函数中使用。
map文件:
Global Symbols
Symbol Name Value Ov Type Size Object(Section)
... ... ... ... ...
Region$$Table$$Base 0x080008dc Number 0 anon$$obj.o(Region$$Table)
Region$$Table$$Limit 0x080008fc Number 0 anon$$obj.o(Region$$Table)
... ... ... ... ...
bin文件:
00000820h: 0C 94 0D 94 00 21 0A A8 0E 94 FF F7 53 FD 10 B0 ;
00000830h: 10 BD 00 00 0D 48 01 68 41 F0 01 01 01 60 41 68 ;
00000840h: 0B 4A 11 40 41 60 01 68 0A 4A 11 40 01 60 01 68 ;
00000850h: 21 F4 80 21 01 60 41 68 21 F4 FE 01 41 60 4F F4 ;
00000860h: 1F 01 81 60 04 49 C0 03 08 60 70 47 00 10 02 40 ;
00000870h: 00 00 FF F8 FF FF F6 FE 08 ED 00 E0 FE E7 09 07 ;
00000880h: 09 0E 00 28 04 DB 00 F1 E0 20 80 F8 00 14 70 47 ;
00000890h: 00 F0 0F 00 00 F1 E0 20 80 F8 14 1D 70 47 02 E0 ;
000008a0h: 08 C8 12 1F 08 C1 00 2A FA D1 70 47 70 47 00 20 ;
000008b0h: 01 E0 01 C1 12 1F 00 2A FB D1 70 47 FF F7 88 FC ;
000008c0h: FF F7 96 FF FF F7 78 FF FE E7 00 00 00 00 00 00 ;
000008d0h: 00 00 01 02 03 04 06 07 08 09 00 00 FC 08 00 08 ;
000008e0h: 00 00 00 20 10 00 00 00 9E 08 00 08 0C 09 00 08 ;
000008f0h: 10 00 00 20 00 04 00 00 AE 08 00 08 01 00 00 00 ;
00000900h: 10 00 00 00 00 00 00 00 00 24 F4 00 ; …$?
Region$$ Table $ $ Base对应表的起始地址,Region $ $ Table $ $ Limit对应终止地址,链接的时候确定这两个值。由于bin文件起始地址是0,所以地址0x080008dc对应0x8dc。表内容:
内容 | 值 |
---|---|
rw数据在flash中的起始地址 | 080008FC |
rw数据在ram中的起始地址 | 20000000 |
rw数据长度(byte) | 00000010 |
拷贝函数起始地址 | 0800089E |
rw数据在flash中的终止地址 | 0800090C |
ZI段在ram中的起始地址 | 20000010 |
ZI段长度,包含heap(byte) | 00000400 |
ZI段初始化函数起始地址 | 080008AE |
初始化RW数据:
初始化ZI和heap数据:
__rt_entry
调用以下函数
__user_initial_stackheap()
startup_stm32xxx.s文件中
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
__rt_stackheap_init()
__rt_lib_init()
rt_misc.h
/*
* This is the library init function itself, provided just in case
* a user needs to call it directly. It is called just after
* __rt_stackheap_init(), and passed an initial chunk of memory to
* use as a heap. It returns argc and argv ready to be passed to
* main(). (The __argc_argv structure contains four words rather
* than just two, in case you need to pass anything else to main()
* such as the Unix envp. For AArch64 struct __argc_argv is 8 words
* (4 registers) and explicit padding is used to ensure argc is in w0.)
*/
struct __argc_argv {
#if (defined(__ARM_64BIT_STATE) || defined(__TARGET_ARCH_AARCH64)) && \
(defined(__ARM_BIG_ENDIAN) || defined(__BIG_ENDIAN))
int padding;
#endif
int argc;
#if (defined(__ARM_64BIT_STATE) || defined(__TARGET_ARCH_AARCH64)) && \
!(defined(__ARM_BIG_ENDIAN) || defined(__BIG_ENDIAN))
int padding;
#endif
char **argv;
void *r2;
void *r3;
};
extern __value_in_regs struct __argc_argv
__rt_lib_init(unsigned /*heapbase*/, unsigned /*heaptop*/);
main()
用户主函数
exit()
_regs struct __argc_argv
__rt_lib_init(unsigned /heapbase/, unsigned /heaptop/);
#### main()
用户主函数
#### exit()