从STM32F103进入ARM世界(2)-startup_stm32f10x_xx.s探究

本文深入解析STM32F103的启动文件startup_stm32f10x_xx.s,包括栈空间和堆空间设置,中断向量表,以及代码段的详细解释。通过了解汇编语言,揭示了栈向下生长、堆未分配、中断向量表布局以及C语言程序启动流程。
摘要由CSDN通过智能技术生成

对于小编来说,我以前对STM32F103的学习是通过正点原子的资料及视频学习,我也看过野火的资料,发现他们的视频都集中在C语言的基础上,不会跟你说启动文件是干什么的,直接就让你拿来用。现在我们要进入ARM世界了,就一定要开始了解汇编语言,了解启动文件里都做了些什么,它的作用是什么。
我们来一段一段解析startup文件。

1. 栈空间设置

;堆栈大小设置,如果局部变量过多,这里应该相应改大.默认是1024字节.
Stack_Size      EQU     0x00000400
                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp

这里 Stack_Size EQU 0x00000400 什么意思呢,EQU在会汇编里相当于c语言的const关键词,用于定义一个常量。这里有一个需要知道的知识点,在ARM世界里栈是向下生长的。在这里也介绍一下堆和栈的区别,:一般用于存放函数的临时变量,即局部变量。在C语言中函数返回时你return的参数,实际上就是将函数内的局部变量压入栈中,等跳出函数时再将数据出栈的过程。栈最重要的作用还是在于线程切换时用来保护现场。:一般由程序员自行分配和释放,分配类似数据结构中的链表。在单片机里,没有内存管理堆存在将没有意义。所以对于我们之前学习的STM32F103的知识而言,在没用操作系统,纯裸机开发是只需要用到栈的。那可能就有疑问了,那我们的全局变量现在在哪?我们的全局变量其实存在于芯片内部的静态存储区里。
下一句 AREA STACK, NOINIT, READWRITE, ALIGN=3 ,伪指令AREA,表示开辟一段内存空间,段名是STACKNOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0。READWRITE表示可读可写, ALIGN=3——2 的3次方表示以8字节对齐。SPACE用于申请一片内存空间,所以Stack_Mem SPACE Stack_Size的意思就是申请Stack_Size(1024字节)大小的内存空间,这个内存空间叫做Stack_Mem。
__initial_sp只是一个标号,相当于一个指向当前位置的一个指针,前面从内存地址当前位置0x20000000开始开辟了一个1024字节的栈,所以这里__initial_sp指向0x20000400。注意一下,我上面推出的这个地址是基于你c语言代码主函数里什么也没写且堆为空的时候的情况,毕竟不要忘了,栈前面还有静态存储区和堆区。
这个如果你对C语言有一定了解,肯定也了解过C语言goto的用法,它也要用到标号。

2. 堆空间设置

;未用到编译器自带的内存管理(malloc,free等),设置Heap_Szie为0
Heap_Size       EQU     0x00000000

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

根据上面对栈的解释,相信你已经能够看懂这段代码了。
这里设置了堆的空间大小为0,也就是实际上必不会给堆分配空间,到这里我们就可以判定现在内存中会存在一个静态存储区(如果C语言中存在变量的话)和一个1024字节的栈。在不使用堆的情况下,要注意了,你的栈的大小一定要比你定义的变量要大,不然你在使用大数组的时候就会直接从栈里溢出到静态存储区,整个程序直接跑飞。在ARM里规定堆默认是向上生长的,所以__heap_base是堆的起始位置,__heap_limit是堆的结束位置。

                PRESERVE8
                THUMB

PRESERVE8: 指定当前文件的堆栈按照 8 字节对齐。
THUMB: 表示后面指令兼容 THUMB 指令。 THUBM 是 ARM 以前的指令集, 16bit,现在 Cortex-M 系列的都使用 THUMB-2 指令集, THUMB-2 是 32 位的,兼容 16 位和 32 位的指令,是 THUMB 的超集。

3. 中断向量表

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

首先定义了一个数据段RESET,只读。因为我们的中断向量表定好了以后肯定不希望有人可以修改它的。这里我们有接触到了一个伪指令EXPORT,它用来声明__Vectors、 __Vectors_End 和__Vectors_Size 这三个标号具有全局属性。使用EXPORT可以让该变量被其他文件引用,意味着这三个标号可以被c语言代码引用。类似c语言里的extern关键词。

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值