目录
介绍
一、Stack-栈(使用的是RAM的内存)
二、Heap-推(使用的是RAM的内存)
三、中断向量表(使用的是flash)
四、复位函数
五、中断服务函数地址
六、堆和栈的初始化
介绍
启动文件是以.s后缀的汇编编写的,启动文件的作用:
1.初始化推栈指针SP
2.初初始化PC指针,指向复位程序
3.初始化中断向量表
4.配置系统时钟
5.调用C库函数_main,最终进入c语言编写的代码
一、Stack-栈(使用的是RAM的内存)
作用:用于局部变量、函数调用、函数形参的开销
汇编指令讲解:
EQU:宏定义的伪指令,相当于等于,类似于C语言中的宏定义define
AREA: 告诉汇编器汇编一个新的代码段或者数据段
SPACE:用于分配一定大小的内存空间,单位字节
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
Stack_Size EQU 0x00000400
Stack_Size 等于 0x00000400(1kb)的空间
AREA STACK, NOINIT, READWRITE, ALIGN=3
定义栈空间 命名为STACK,NOINIT表示不初始化,READWRITE表示可读可写,ALIGN=3表示2的3次方(8个字节)对齐开辟。
Stack_Mem SPACE Stack_Size
分配内存为Stack_Size大小的空间单位字节
__initial_sp
初始化栈指针就是指向栈顶地址(栈使用的时候栈顶先出依次到栈底,先进后出)
标号__initial_sp紧挨着SPACE语句放置,表示栈的结束地址,即栈顶地址,栈是由高向低生长的。
二、Heap-推(使用的是RAM的内存)
作用:用于动态内存的分配,malloc函数
EQU:宏定义的伪指令,相当于等于,类似于C语言中的宏定义define
AREA: 告诉汇编器汇编一个新的代码段或者数据段
SPACE:用于分配一定大小的内存空间,单位字节
Heap_Size EQU 0x00000400
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
Heap_Size EQU 0x00000400
Heap_Size 等于 0x00000400(1kb)的空间
AREA STACK, NOINIT, READWRITE, ALIGN=3
定义栈空间 命名为HEAP,NOINIT表示不初始化,READWRITE表示可读可写,ALIGN=3表示2的3次方(8个字节)对齐开辟。
__heap_base
表示堆的起始地址
Heap_Mem SPACE Heap_Size
分配内存为Heap_Size大小的空间单位字节
__heap_limit
初始化推指针
标号__initial_sp紧挨着SPACE语句放置,表示推的结束地址,堆是由低向高生长的(于栈相反)。
PRESERVE8
THUMB
PRESERVE8表示指定当前文件的推栈按照8字节对齐
THUMB表示后面指令位THUMB指令
三、中断向量表(使用的是flash)
AREA: 告诉汇编器汇编一个新的代码段或者数据段
EXPORT:声明一个标号具有全局属性,类似于C中的extem功能
DCD:分配一个或者多个以字节为单位的内存,以四字节对齐,并要求初始化这些内存。在向量表中,DCD分配了一推内存,并且以ESR的入口地址初始化它们。
AREA: 告诉汇编器汇编一个新的代码段或者数据段
1.向量表实际上是一个32位的整形数组,一个元素对应一个异常(ESR:中断程序服务地址),数组元素存的就是ESR的入口地址。
2.向量表在复位后从FLASH的0地址开始,具体的初始化值查询参考手册的中断章节。
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
AREA RESET, DATA, READONLY
定义一个数据段 命名为RESET,DATA表示数据, READONLY表示可读
EXPORT __Vectors
表示向量表的开始地址(全局属性)
EXPORT __Vectors_End
表示向量表的结束地址(全局属性)
EXPORT __Vectors_Size
表示向量表的大小(全局属性)
__Vectors DCD __initial_sp
DCD Reset_Handler
等等很多
DCD SysTick_Handler
DCD WWDGT_IRQHandler
等等很多
DCD USBFS_IRQHandler
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
__Vectors DCD __initial_sp
中断向量表的第一个字节存放的是__initial_sp栈顶的指针
DCD Reset_Handler
中断向量表的第二个字节存放的是Reset_Handler函数入口地址
DCD SysTick_Handler
SysTick_Handler以上是内核使用的
DCD WWDGT_IRQHandler
从 WWDGT_IRQHandler到USBFS_IRQHandler,都是用户使用的。
__Vectors_End
表示向量表结束
__Vectors_Size EQU __Vectors_End - __Vectors
表示量表的大小 __Vectors_Size=Vectors结束地址-Vectors开始地址
AREA |.text|, CODE, READONLY
定义一个代码段 命名text, CODE表示代码段,READONLY只读
四、复位函数
PROC:表示子程序的开始
EXPORT:声明一个标号具有全局属性,类似于C中的extem功能
WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。这里表示复位子程序可以有程序用户在其他文件重新实现,这里并不是唯一的。
IMPORT:表示该标号来自外部文件,跟C语言中的extern关键字类似。
LDR:从存储器中加载字到一个寄存器中
BLX:跳转到有寄存器给出的地址,并根据寄存器的LES确定处理器的状态,还要吧跳转钱的下一条指令地址保存到LR
BX:跳转到有寄存器/标号给出的地址,不用返回
ENDP:表示子程序的结束
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
Reset_Handler PROC
表示复位子程序开始
EXPORT Reset_Handler [WEAK]
表示用户可在其他地方定义全局函数
IMPORT SystemInit
外部的一个函数SystemInit:主要初始化系统时钟
IMPORT __main
外部的一个函数
LDR R0, =SystemInit
把SystemInit函数入口地址加载到R0寄存器中
BLX R0
跳转到R0寄存器去执行里面的函数,执行完返回。
LDR R0, =__main
把__main函数入口地址加载到R0寄存器中。
(注意这里的_main不是我们写程序的main,这里的_main是外部导入进来的,是C库里面的,执行这个_main后最后会道我们写程序的main里面)
_main的作用:1.初始化程序里面的局部变量全局变量由C库完成2.调用我们写程序的mai函数
BX R0
执行完不用返回
ENDP
子程序结束
五、中断服务函数地址
PROC:表示子程序的开始
EXPORT:声明一个标号具有全局属性,类似于C中的extem功能
WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。这里表示复位子程序可以有程序用户在其他文件重新实现,这里并不是唯一的。
B .:表示无限循环
用汇编全写好了,在三章中断向量表初化函数__initial_sp用到
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
NMI_Handler PROC
表示子程序的开始
EXPORT NMI_Handler [WEAK]
表示用户可在其他地方定义全局函数
B .
表示无限循环
ENDP
子程序结束
六、堆和栈的初始化
上面我们只是开辟了空间没有初始化
EXPORT:声明一个标号具有全局属性,类似于C中的extem功能
IMPORT:表示该标号来自外部文件,跟C语言中的extern关键字类似。
IF、ELSE:和C语言的if、else一样
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 PROC
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDP
ALIGN
ENDIF
END
如果DEF:__MICROLIB成立就把__heap_limit、__heap_base、__initial_sp声明为全局文件
如果没定义会执行__user_initial_stackheap PROC这段代码来初始化(我们都是会定义DEF:__MICROLIB这个的所以不会跑去执行下面这段代码区执行)