前言
这篇博客是MCU的内部架构与程序的运行原理的关于.ld链接器脚本和.s启动文件部分的笔记,对于理解startup_stm32f407xx.s和STM32F407x_FLASH.ld文件还是十分有帮助的!
存储映射,编译与链接
2.编译与链接
编译与链接的过程
——编译器根据Makefile或CMake将程序进行编译和优化得到目标文件
——链接器根据LD链接器脚本对目标文件进行链接
——可执行文件被进一步转换格式变为MCU上可执行的程序
编译与链接涉及到的文件
——高级语言源文件.c或.cpp,汇编源文件.s:包含程序源代码
——目标文件.o:包含所有源代码对应的机器码以及重定位信息等
——可执行文件.elf:包含了完整程序的信息
——十六进制文件.hex或二进制文件.bin:在MCU上运行的程序,由可执行文件.elf转换得到
——存储映射文件.map:包含了存储映射的信息,如函数入口地址、函数大小、程序使用大小、程序占用空间情况
——完整汇编程序代码.lst:源代码与汇编代码的对照表,完整程序的汇编代码
Makefile脚本与LD链接器脚本
Makefile脚本:配置编译的相关环境包括选择编译器、指定要使用的库、配置各种环境变量等,同时指定要参与编译的源文件和头文件。
LD链接器脚本:用于链接.o文件中的各个部分到存储器的指定地址,指定Reset_Handler等。
STM32常见的SDK编译工具
——Keil uvision:一般无需编辑任何脚本,只需在Options中简单配置如存储器的起始地址,IDE会自动配置SDK的编译环境
——STM32CUBEIDES/STM32CUBEMX:需要用到Makefile和LD链接器脚本,可以由软件自动配置脚本
——linux环境arm-gcc:用户需要手动配置编译环境,需要Makefile或者CMake进行编译,链接需要LD链接器脚本
程序的段及其存储方式
1.程序的段
程序的段的分类
——按照程序文件分段:Code段、RO_data段、RW_data段、ZI_data段
Code段:代码段,包含了用户的程序代码
RO_data段:只读数据段,包含了用户程序中的常量
RW_data段:读写数据段,包含了用户程序中已初始化且非零的全局变量
ZI_data段:零初始化段,包含了用户程序中已初始化为零或者没有初始化的全局变量
——按照程序进程分段:TEXT段、DATA段、BSS段、堆栈段
TEXT段:包含了用户的程序代码,若常量不单独分段,则TEXT段也包含常量
DATA段:包含了用户程序中的已初始化全局变量
BSS段:包含了用户程序中的未初始化全局变量
HEAP堆:用于存放进程运行中被动态分配的内存的变量。当程序中调用malloc等函数给变量分配内存时,这些内存就是位于堆中;使用free等函数释放变量占用的内存
STACK栈:用于存放用户程序的部分局部变量。在函数被调用时,其参数也可能会被压入栈中;中断发生时,中断打断的程序相关变量也会被压入栈中。
栈的地址生长方向是从高到低,与其他段相反。
关于压入堆栈的变量的说明
——编译器存在优化功能,优化功能是在不改变用户程序逻辑的前提下,尽可能的对程序代码进行整合优化,减小代码逻辑复杂度和占用的存储空间资源大小(减少使用堆栈)
——一般CPU执行代码时主要用到的内部通用寄存器是R0、R1、R2、R3
程序的段
——编译器编译时,把每个源文件的内容分成若干段
——链接器链接时,把这些段进行链接
2.程序的段的存储
程序文件中的段的存储方式
ROM区域:Code段、RO_data段、RW_data段
RAM段:RW_data段、ZI_data段
程序运行时RW_data段的所有数据会被加载到RAM区域
程序运行时也可以把Code段、RO_data段、RW_data段都加载到RAM区域执行(启动方式的选择)
存储区域的大小要求
需要的ROM大小等于Code段、RO_data段和RW_data段之和
需要的RAM大小等于RW_data段和ZI_data段之和。由于堆栈的存在,RAM区域需要的空间要比这个数更大
LD链接器脚本的概念与功能
1.LD链接器脚本的概念
——LD链接器脚本在完整程序编译流程的链接过程中使用
——LD链接器脚本定义了程序中的各个程序段的存储分布,描述链接器如何将这些目标文件.o文件链接成一个输出可执行文件
——LD链接器脚本与MCU的种类、MCU的内部存储器分布有关
2.LD链接器脚本的功能
——定义RAM区域和ROM区域的地址信息,包括首地址和长度
——定义各个程序段在MCU内部存储器的分布情况
——定义程序运行的入口
.s启动文件的概念与功能
1. .s启动文件的概念
——.s启动文件在编译时被处理,由汇编语言编写
——.s启动文件描述了MCU的CPU从上电启动到跳转到用户main程序之间的CPU系统行为
——.s启动文件的内容与MCU的种类、CPU的种类、使用的汇编器都有关系
2. .s启动文件的功能
——定义了Reset_Handler复位异常向量处理函数
——定义了中断向量表的具体内容
——定义了一个死循环Default_Handler函数
——配置了汇编环境
——定义了所有异常和外部中断的默认中断处理函数,这些函数都是弱函数