FreeRTOS源码分析与应用开发11(完):编译、链接与部署

目录

1. 存储设备布局

2. 链接器脚本

2.1 链接器脚本生成

2.2 链接器脚本分析

2.2.1 分散加载文件

2.2.2 加载区 & 运行区

2.2.3 ER_IROM1运行区分析

2.2.4 RW_IRAM1运行区分析

3. 启动文件分析

3.1 MSP初始值

3.2 链接器内存堆

3.3 异常向量表

3.4 Reset_Handler


说明:本文以正点原子的μVision FreeRTOS工程作为实例

1. 存储设备布局

STM32F407的存储设备布局如下图所示,此处使用了MCU内部的iROM & iRAM

2. 链接器脚本

2.1 链接器脚本生成

① 使用μVision IDE时,链接器脚本由IDE根据所选MCU型号自动生成

② 自动生成的链接器脚本在工程的Objects目录,文件名后缀为.sct

说明:MCU型号对链接器脚本最大的影响就体现在所用存储介质的地址与范围

2.2 链接器脚本分析

2.2.1 分散加载文件

① 分散加载文件(scatter file)用来指定ARM链接器在生成镜像时如何分配RO / RW / ZI等数据的存放地址

② 分散加载文件的描述需要与实际运行设备匹配

2.2.2 加载区 & 运行区

加载区:包含应用程序复位和加载时的代码和数据

运行区:包含应用程序运行时的代码和数据,应用程序启动过程中,从每个加载区可创建一个或多个运行区

说明1:镜像中的所有代码和数据必须准确地指定到一个加载区和一个运行区

示例中的LR_IROM1是1个加载区,其中包含2个运行区(ER_IROM1和RW_IRAM1)

说明2:加载区 & 运行区关系

2.2.3 ER_IROM1运行区分析

① *.o (RESET, +First)

部署在IROM最前端的为RO数据中的RESET section,这个section包含了MSP的初始值以及Reset_Handler(在异常向量表中),是Cortex-M3 MCU启动的起点

② *(InRoot$$Sections)

库函数__main中有InRoot$$Sections段,主要作用是将RW区复制到IRAM中,并且在RW区之后创建ZI区

③ .ANY (+RO)

所有文件中的RO区

2.2.4 RW_IRAM1运行区分析

① .ANY (+RW +ZI)

所有文件中的RW区和ZI区

附件:μVision链接器脚本示例

3. 启动文件分析

3.1 MSP初始值

① __initial_sp为异常向量表的第1个成员,内容为MSP的初始值

② __initial_sp被链接在RW区,大小为1KB(0x00000400)

说明1:满减栈的定义方式

AREA STACK段的起始地址是栈的低地址端,__initial_sp是栈的高地址端。由于Cortex-M3默认使用满减栈,所以MSP初始值为__inital_sp,也就是高地址端

说明2:MSP初始值上机调试

我们在Reset_Handler中添加LDR R0, =__initial_sp语句,查看MSP初始值,可见结果与预期相同

3.2 链接器内存堆

如之前的笔记分析,此处的内存堆是供编译器提供的malloc & free使用的,通过__heap_base & __heap_limit标号,可标识内存堆范围

3.3 异常向量表

说明:启动文件中提供了WEAK定义的中断Handler,用户可自定义Handler进行覆盖

3.4 Reset_Handler

Reset_Handler为Cortex-M3/4系列MCU启动的起点

Reset_Handler的主体先后调用SystemInit和__main函数,从而进入用户定义的main函数

说明1:SystemInit函数

SystemInit函数会设置内置Flash、PLL以及外置DDR(如果有的话),需要注意下该函数对异常向量表地址的重置,即将SCB->VTOR寄存器值设置为FLASH_BASE(0x08000000) | VECT_TAB_OFFSET(0x00000000),也就是IROM1的起始地址

说明2:__main函数

__main函数由C/C++标准库提供,执行代码和数据复制、加压缩以及ZI数据的零初始化


版权声明:本文为chenchengwudi原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。