编译器编译后,生成的是一个xx.bin文件,如下图:
左边的是编译器生成的目标文件,存放在外存中,其中Text_start等标识符,编译器会自动给出,汇编里面直接引用是可以的。
启动的过程:(启动文件要做的,也是CPU上电后就运行的程序)
- CPU把Data段和Bss段分别搬运到内存RAM中即可,Text段不用搬,因为是代码段,只需要读取即可。
- 跳转到外部出口函数,一般就是main函数了,就进入了用户世界了。
我们打开stm32官方的启动文件,发现如下:(是跳转到了__main函数,并没有搬运Data段和Bss段啊,也没有跳转到我们用户的main函数啊,这是怎么回事呢?)
这是因为,__main函数是libc库文件标准定义了,里面就是搬运Data段和Bss段到指定的RAM区域中。里面会再次跳转到我们的main函数的,就进入了用户的世界。如下所示:
当然我们也可以不用libc库中的__main函数,我们自己写一个搬运Data段和Bss段的代码,然后跳转到我们指定的main函数去。示意代码如下,自己对着理解理解就可以了,不难。
.cpu cortex-m3
.fpu softvfp
.syntax unified
.thumb
.text
.global RESET_HANDLER
.global __ENTRY
.extern myMain
.type RESET_HANDLER,function
.type FAULT_HANDLER,function
.word Msp_stack
.word RESET_HANDLER
.word FAULT_HANDLER
.word FAULT_HANDLER
__ENTRY:
RESET_HANDLER:
ldr r0,=Psp_stack
msr psp,r0 @初始化线程栈指针,主栈指针是自动初始化的
CPSID I @PRIMASK=1,关中断
@CPSID F @FAULTMASK=1,关异常
mov r0,#0
msr control,r0 @初始化代码在特权级,栈指针选择msp
movs r1, #0
bl LoopCopyDataInit
CopyDataInit:
ldr r3, =text_end
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =data_start
ldr r3, =data_end
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =bss_start
ldr r3, =bss_end
b LoopFillZerobss
FillZerobss:
movs r1, #0
str r1, [r2], #4
LoopFillZerobss:
cmp r2, r3
bcc FillZerobss
mov r0,r0
bl myMain
b .
FAULT_HANDLER:
bx lr