【STM32】解读启动文件startup_stm32f10x_md.s

栈空间

  • 栈(Stack):栈是一种后进先出(LIFO)的数据结构,用于存储函数调用时的局部变量、返回地址和寄存器的值。启动文件会定义栈的大小,并将栈指针初始化为栈顶地址。在函数调用时,栈指针会自动调整,以分配和释放内存空间。例如,当一个函数被调用时,返回地址和局部变量会被压入栈中;函数返回时,这些数据会从栈中弹出。

Stack_Size EQU 0x00000400

  • EQU 属于汇编伪指令,其功能是定义一个常量。在这里,Stack_Size 被定义为**0x00000400**,换算成十进制就是 1024。这意味着栈的大小为 1024 字节。

AREA STACK, NOINIT, READWRITE, ALIGN=3

  • **AREA**也是汇编伪指令,用于定义一个存储区域。
  • **STACK**是该存储区域的名称,表明这个区域是用来作为栈空间的。
  • **NOINIT**表示此区域无需进行初始化操作,也就是在程序启动时,不会对这个区域的内存赋初值。
  • **READWRITE**说明这个区域是可读写的,程序能够对其进行读写操作。
  • **ALIGN=3**意味着该存储区域的起始地址要按照 2的3次方=8 字节对齐。地址对齐有助于提高内存访问的效率。

Stack_Mem SPACE Stack_Size

  • Stack_Mem 是这个栈空间的起始标签。
  • SPACE 同样是汇编伪指令,其作用是分配一定大小的内存空间。这里分配的空间大小由 Stack_Size 决定,也就是 1024 字节。

__initial_sp

  • __initial_sp 代表栈顶指针的初始值。因为栈是从高地址向低地址增长的,所以 **__initial_sp**指向的是栈空间的末尾地址,也就是栈顶。

代码功能

这段代码的主要功能是定义一个大小为 1024 字节、起始地址按 8 字节对齐、可读写且无需初始化的栈空间,并且确定了栈顶指针的初始位置。在程序启动时,栈指针会被设置为 __initial_sp,后续函数调用、局部变量存储等操作都会使用这个栈空间。

堆空间

堆(Heap) :堆用于动态内存分配,例如使用malloc()free()函数。启动文件会定义堆的大小和起始地址,为动态内存分配提供空间。堆的管理通常由操作系统或运行时库负责。

cs 复制代码
; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

                PRESERVE8
                THUMB

1. Heap_Size EQU 0x00000200

  • EQU 是汇编伪指令,用于定义常量。这里将 Heap_Size 定义为 0x00000200,换算成十进制是 512。这表明堆的大小为 512 字节。

2. AREA HEAP, NOINIT, READWRITE, ALIGN=3

  • **AREA**也是汇编伪指令,用于定义一个存储区域。
  • **HEAP**是该存储区域的名称,意味着这个区域是用来作为堆空间的。
  • **NOINIT**表示此区域无需进行初始化操作,即程序启动时,不会对该区域的内存赋初值。
  • **READWRITE**说明这个区域是可读写的,程序能够对其进行读写操作。
  • **ALIGN=3**表示该存储区域的起始地址要按照 2的3次方=8 字节对齐,地址对齐有助于提高内存访问效率。

3. __heap_base

  • **__heap_base**是一个标签,代表堆空间的起始地址。

4. Heap_Mem SPACE Heap_Size

  • Heap_Mem 同样是一个标签,SPACE 是汇编伪指令,用于分配一定大小的内存空间。这里分配的空间大小由 Heap_Size 决定,即 512 字节。

5. __heap_limit

  • **__heap_limit**是一个标签,代表堆空间的结束地址。

6. PRESERVE8

  • 这是一个汇编指令,其作用是指示编译器保证代码中的数据和栈的对齐方式为 8 字节对齐。在某些架构中,保持 8 字节对齐能够提高内存访问的性能。
  1. THUMB
  • 此指令表明后续的代码会使用 Thumb 指令集进行编译。Thumb 指令集是 ARM 指令集的一种精简版本,它具有更高的代码密度,能够节省存储空间。

代码整体功能

这段代码的主要功能是定义一个大小为 512 字节、起始地址按 8 字节对齐、可读写且无需初始化的堆空间,同时标记出堆空间的起始地址和结束地址。在程序运行过程中,动态内存分配函数(如 malloccalloc 等)会使用这个堆空间来分配内存。

初始化向量表

  • 向量表的作用:向量表是一个固定地址的数组,存储着各个异常和中断处理函数的入口地址。当异常或中断发生时,处理器会根据异常或中断号从向量表中获取相应的处理函数地址,并跳转到该地址执行。
  • 异常和中断处理:启动文件会将向量表初始化为默认的异常和中断处理函数地址。这些处理函数包括复位处理函数、非屏蔽中断(NMI)处理函数、硬故障处理函数等。用户可以根据需要修改这些处理函数的地址,以实现自定义的异常和中断处理逻辑。
cs 复制代码
; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                ; 其他中断向量...

  • 复位处理函数 :**Reset_Handler**是复位后执行的第一个函数,它会完成一些必要的初始化工作,然后跳转到主程序。

中断向量表结束标记

cs 复制代码
__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors
  • 向量表结束标记 :**__Vectors_End**表示向量表的结束地址。
  • 向量表大小 :**__Vectors_Size**计算向量表的大小,用于后续的一些初始化操作。

复位处理函数

cs 复制代码
; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
     IMPORT  __main
     IMPORT  SystemInit
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

系统初始化

  • 硬件初始化 :启动文件通常会调用一个系统初始化函数,如**SystemInit()**,该函数会对芯片的硬件资源进行初始化,包括时钟系统、总线配置、外设等。例如,配置系统时钟源、设置时钟频率、使能外设时钟等。这些初始化操作确保芯片以正确的时钟频率和工作模式运行。
  • 全局变量初始化:启动文件会将全局变量和静态变量初始化为其初始值。对于已初始化的全局变量,启动文件会将其从只读存储器(ROM)复制到随机存取存储器(RAM)中;对于未初始化的全局变量,启动文件会将其所在的 RAM 区域清零。
  • 跳转到主程序 :调用**__main** 函数,__main 是 C/C++ 程序的入口点,它会完成全局变量的初始化、调用**main()**函数等操作。程序的主要逻辑通常从这里开始执行。

中断处理函数

cs 复制代码
; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP
; 其他中断处理函数...

默认处理函数 :这些是默认的中断处理函数,当相应的异常或中断发生时,如果用户没有提供自定义的处理函数,就会执行这些默认函数。默认函数通常是一个无限循环B .,表示程序会一直停在这里,等待用户进一步处理。

相关推荐
笨鸟先飞的橘猫28 分钟前
skynet——sharetable学习
学习·skynet
liuyicenysabel1 小时前
大模型学习笔记 · 第八篇 · 进阶:偏好对齐与多卡训练
人工智能·笔记·学习
大卡片1 小时前
linux内核驱动开发
linux·运维·驱动开发
心心喵3 小时前
[linux] nohup和pm2的区别 进程保活
linux·运维·服务器
Funing74 小时前
FreeRTOS学习day1:Keil 工程配置与 FreeRTOS 链表机制理解
数据结构·学习·链表
醉熏的石头4 小时前
Ubuntu 中的编程语言(中)
linux·ubuntu·scala
心中有国也有家4 小时前
使用 DevEco Studio 配置 Flutter 鸿蒙签名
学习·flutter·华为·harmonyos
灯澜忆梦4 小时前
MySQL 完整学习路线
学习·mysql
番茄育学园4 小时前
我的三款主流云存储音乐库实测笔记
笔记·分类·媒体
森林古猿15 小时前
再论斜率优化
c++·学习·算法