超级详细讲解stm32f10x系列的启动文件

        声明:这次讲解真的超级详细,根据标准库的启动文件,一步步介绍的。看的时候可以与启动文件一起查看学习。

1、栈

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem       SPACE   Stack_Size

__initial_sp

【解释EQU】给数字常量取一个名字,相当于C 语言中的define

【解释AREA STACK】 标明汇编一个新的代码段或者数据段  段名字为STACK

【解释NOINIT】 不初始化

【解释READWRITE】 表示这个段内容是可读可写的

【解释ALIGN】编译器对指令或者数据的存放地址进行对齐,这里是8字节对齐(2^3)

【解释SPACE】 这个指令标明分配内容空间

【解释 SPACE   Stack_Size】 分配大小为Stack_Size的空间

【解释__initial_sp】在initial_sp之前分配了1KB字节大小的空间,initial_sp表示栈的结束地址。比如我的此时__initial_sp值为0x20000608,因为大小位0x400,所以栈开始地址是0x2000_0208。有的朋友可能会问没什么不是从0x2000_0000开始,我这里使用了堆。堆的空间范围是0x20000008——0x20000208。

拓展:有的同学可能好奇,0x2000_0000与0x2000_0004呢?

0x20000000       存的是    __microlib_freelist

0x20000004       存的是    __microlib_freelist_initialised

我这里是使用了微库(MicroLIB)(KEIL软件的魔术棒->target)

        总结:开辟一个大小位0x0000_0400(1KB)大小的栈空间,段名字为STACK,内部是8字节对齐,段内空间数据是可读可写的。

        有朋友可能会问,什么东西会存放到栈呢?

        所有的局部变量等等。比如我这里写了 int add (int a, int b)函数,那么当程序执行到这个函数的时候,会把这个函数内部定义的局部变量,存放到栈中。

2、堆

        首先说明:堆空间的真正开辟是在项目中有使用malloc函数申请内存。如果没有使用malloc,那么虽然在.s文件中定义了分配堆空间,实际情况下,堆空间是没有开辟的。

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3

__heap_base

Heap_Mem        SPACE   Heap_Size

__heap_limit

【解释:Heap_Size  EQU  0x00000200】 相当于宏定义 Heap_size   0x0000_0200。

【解释:AREA  HEAP, NOINIT, READWRITE, ALIGN=3】 与STACK一样,只是这个段的名字为HEAP。

【解释:__heap_base】 此时还没有开辟空间,此时表示堆的起始地址。

【解释:Heap_Mem  SPACE  Heap_Size】分配大小为Heap_Size的空间为堆空间。

【解释:__heap_limit】此时__heap_limit这个值表示堆空间的结束地址。

3、 PRESERVE8与THUMB指令

                PRESERVE8
                THUMB

【解释:PRESERVE8】PRESERVE8是ARM汇编指令,确保8字节堆栈对齐。

【解释:THUMB】表明之后指令兼容THUMB指令,其实是ARM指令集的一种,指令长度为16位,需要通过两条指令来访问32位的数据和地址空间。还有THUMB-2指令集,它支持16位和32位的混合指令格式,是THUMB的拓展版。

4、向量表

                AREA  RESET, DATA, READONLY

                EXPORT  __Vectors

                EXPORT  __Vectors_End

                EXPORT  __Vectors_Size

【解释:AREA  RESET】 定义一个段,段名为RESET。

【解释:READONLY】    只读,不能写。

【解释:DATA】         DATA表明这个区域存储的是数据。

【解释:EXPORT】      表明之后的标号是全局的,可以被外部文件使用。

【解释:__Vectors】    代表向量表起始地址

【解释:__Vectors_End】代表向量表的结束地址

【解释:__Vectors_Size】代表向量表大小

5、详细向量表

__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

                DCD     0                          ; Reserved                                                 

【解释:DCD】 其‌是一个指令,用于分配一个或多个以字为单位的内存,以四字节对齐,并会初始化这些内存。DCD在STM32的启动文件中用于指定各种中断处理程序的入口地址。

        我们知道中断向量表是放在代码段的最最前面的,比如当我们程序在flash区域运行时,第一个地址是0x0800_0000,这个其实就是向量表的起始地址,也就是__Vectors。

【解释:__Vectors  DCD   __initial_sp】分配第一个以字为单位的内存,以四字节对齐,该地址处初始化内容为__initial_sp,__initial_sp是栈的结束地址。也就是0x0800_0000地址处存放的内容为0x20000608。

【解释:DCD     Reset_Handler】分配第二个以字为单位的内存,以四字节对齐,该地址处初始化内容为Reset_Handler,我们知道函数名称表示的其实就是地址,所以,此时该内存的内容为Reset_Handler的地址。也就是0x0800_0004 存放的是Reset_Handler函数地址,我的地址为0x08000145,0x08000145说明Reset_Handler函数的地址起始地址了,对吧??

【解释:DCD     XXX_Handler】经过前面的介绍你们应该已经懂了,之后的内容其实就是0x0800_0004 + 0x4 *  i   存放的是各个中断函数的地址。

6、向量表的大小

__Vectors_Size  EQU  __Vectors_End - __Vectors

        上面这段的意思就是相当于 __Vectors_SIze = __Vectors_End    -  __Vectors,计算出了向量表的大小。

7、.text段

                AREA    |.text|, CODE, READONLY

        看到AREA,我们就应该知道它是一个定义段名字的指令,定义了一个.text的段。这个段的类型为代码段,是只读的。

        注意:在计算机程序中,“.text”段通常用于存放程序的执行代码,也就是机器指令。这是程序执行的核心部分,通常存储在只读内存中,以防止程序运行过程中被修改。|符号在这里用作分隔符,用于区分段名和段的属性。

8、复位中断

Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP

【解释:PROC  ENDP】PROC与ENDP成对使用,相当于规定了一个范围。PROC表示子程序的开始,ENDP表示子程序的结束。

【解释:EXPORT Reset_Handler】 定义Reset_Handler有全局属性,可被外部文件使用。

【解释:WEAK】弱定义,如果你在其他文件中又定义了带有WEAK的函数,那么程序就会执行你自己定义的函数了。注意;weak定义的名字是不能改变的。

【解释:IMPORT】 声明之后的标号来自外部文件,就好像C语言的extern一样。这里的__main可以先简单理解为我们写的main入口函数。

【解释:IMPORT SystemInit】 声明这个SystemInit函数是外部文件的。

【解释:LDR R0, =SystemInit  BLX   R0】将SystemInit函数的地址给R0寄存器,CPU跳转到R0寄存器中的地址去执行。执行完之后,返回接着执行之后程序。

【解释:LDR  R0, =__main    BX   R0】将main函数地址给R0寄存器,之后CPU执行R0寄存器的地址。并且不会返回了。这样到这就进入到了我们的主程序了。

        注意:到此为止,程序就从汇编文件,完成各种初始化配置,进入到我们写的主程序了。

9、Systick函数中断

SysTick_Handler PROC
                EXPORT  SysTick_Handler            [WEAK]
                B       .
                ENDP

        经过介绍上方的复位中断,其他之后的其实都差不多。这里我仅仅介绍一点:

【解释:B    .】    B指令跳转到一个标号,这里的标号是‘.’,表示不限循环。

        那么这段到底什么意思呢??上面说过WEAK是一个弱定义,如果你在其他函数中定义了Systick_Handler函数,那么程序会执行你定义的Systick_Handle函数。如果说你没有在其他文件定义Systick_Handle函数,那么当Systick中断来临的时候,就会执行启动文件中的Systick_Handle函数,并且不干其他事,只是无限循环。

        说明:之后的弱中断,我就不介绍了,其实都一样的。

10、堆栈初始化

                ALIGN

        在启动文件的初始化栈和堆之前有一个单独的ALIGN,ALIGN表示对地址进行对齐,一般后面是跟数字的,比如上方的ALIGN = 3,表示2^3=8字节对齐,默认情况下是4,所以这里是4字节对齐。

;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
                 IF      :DEF:__MICROLIB
                
                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
                
                 ELSE
                
                 IMPORT  __use_two_region_memory
                 EXPORT  __user_initial_stackheap
                 
__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

                 ALIGN

                 ENDIF

                 END

;******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****
 

        这里其实就是在正在进入main函数之前,完成栈和堆空间的初始化。就不详细介绍了。

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值