大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是IAR启动函数流程里的段初始化函数__iar_data_init3实现

  本篇是 《IAR启动函数流程及其__low_level_init设计对函数重定向的影响》 一文的后续,在上篇文章里我们在 IAR 软件安装目录下找到了标准启动函数 __iar_program_start() 相关源文件,并且分析了 __iar_program_start() 函数里的全部动作。我们知道了其中负责 .data/.bss/.textrw 段初始化工作的是 __iar_data_init3() 函数,但是这个函数的具体实现并没有详细介绍,今天我们就仔细说说这个 __iar_data_init3() 函数:

  • Note 1: 阅读本文前需要对 《IAR链接文件(.icf)》 有所了解。
  • Note 2: 本文使用的 IAR EWARM 软件版本是 v9.10.2。

一、为什么有些段需要初始化?

  《IAR链接文件(.icf)》 一文第一小节列出了 IAR 工程里定义的全部系统段(Section)名,其中 .data/.bss/.textrw 段是需要初始化的,因为这些段是链接在 RAM 里,而 RAM 上电其内容都是随机值,所以需要一段启动代码将 .data/.bss/.textrw 段所在的 RAM 区填上对应的初值(初值来自于下载了程序镜像文件的 Flash 区),然后应用程序才能正常运行。

  • Note: 除了 .data/.bss/.textrw 之外,还有一些段(.noinit/CSTACK/HEAP等)也链接在 RAM 区,但这些段对初值没有依赖,所以不需要初始化。
.bss                 // 初值为 0 的静态/全局变量(RAM)
.data // 初值为非 0 的全局变量(RAM)
.data_init // .data 段的初值(Flash)
.textrw // __ramfunc 修饰的重定向函数实际执行区(RAM)
.textrw_init // .textrw 段的机器码存储区(Flash)

二、RW/ZI段初始化的一般实现

  应用程序工程在编译链接结束后,.data/.bss/.textrw 段实际链接地址就确定了(这里指默认由 IAR 链接器自由分配具体链接地址,而不是用户在链接文件中指明具体链接地址的情况),我们知道了这些段的链接地址,就可以完成对应初始化工作(说白了,就是初值数据从 Flash 到 RAM 的拷贝工作),实际链接地址可以通过如下 IAR 链接器提供的接口来获取,具体拷贝过程可参看 《IAR下将关键函数重定向到RAM中执行的方法》 一文最后一节里的代码。

  • Note: IAR 链接器为了后续初始化的方便,都是将程序中全部的全局变量紧挨着放到一块连续的 RAM 区域(.data),然后其全部初值也一一对应紧挨着放一起(.data_init,下载到一块连续的 Flash 区);对于 .textrw 的处理也类似。
#pragma section = ".data"
#pragma section = ".data_init"
#pragma section = ".bss"
#pragma section = ".textrw"
#pragma section = ".textrw_init" uint8_t *data_ram = __section_begin(".data");
uint8_t *data_rom = __section_begin(".data_init");
uint8_t *data_rom_end = __section_end(".data_init");
uint8_t *bss_start = __section_begin(".bss");
uint8_t *bss_end = __section_end(".bss");
uint8_t *code_relocate_ram = __section_begin(".textrw");
uint8_t *code_relocate_rom = __section_begin(".textrw_init");
uint8_t *code_relocate_rom_end = __section_end(".textrw_init");

  段初始化的一般实现虽然简单,但有个缺点,就是对于用户自定义 RW/ZI 段或者多个分散的 RW/ZI 段无法自动适应,需要根据实际情况不断调整代码实现。

三、__iar_data_init3() 函数实现细节

  前面铺垫了这么多,终于到了围观 IAR 标准段初始化函数 __iar_data_init3() 实现的时候了,跟这个函数相关的源文件在如下路径下,核心代码在 data_init.c 文件中:

\IAR Systems\Embedded Workbench 9.10.2\arm\src\lib\init\data_init.c
\IAR Systems\Embedded Workbench 9.10.2\arm\src\lib\init\zero_init3.c - 存放 __iar_zero_init3 函数
\IAR Systems\Embedded Workbench 9.10.2\arm\src\lib\init\copy_init3.c - 存放 __iar_copy_init3 函数

  在 data_init.c 文件中有一个叫 IAR_DATA_INIT 的函数,其实它就是 __iar_data_init3,光看这个函数里的代码会让人有点摸不着头脑,因为用了 IAR 链接器里的接口及一些特殊定义,我们结合一个具体应用程序工程来讲解会更清晰。

// 在 IAR 目录 \arm\inc\c\DLib_Product.h 中宏定义
#define _DLIB_ELF_INIT_INTERFACE_VERSION 3 // 在 IAR 目录 \arm\src\lib\init\data_init.h 中的宏定义
#define IAR_DATA_INIT _GLUE(__iar_data_init, _DLIB_ELF_INIT_INTERFACE_VERSION) #pragma section = "Region$$Table" const TABLE_MEM
void IAR_DATA_INIT(void)
{
FAddr TABLE_MEM const * pi = __section_begin("Region$$Table");
table_ptr_t pe = __section_end ("Region$$Table");
while (pi != pe)
{
init_fun_t * fun = FAddr_GetPtr(pi);
++pi;
pi = fun(pi);
}
}

  我们现在随便编译一个 SDK 例程(痞子衡选择的是 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\hello_world\cm7\iar,切到 flexspi_nor_debug build,即代码 RO 段链接在 0x30000000 开始的 Flash 区,代码 RW 段链接在 0x20000000 开始的 DTCM 区),查看其对应映射文件(.map),摘出其中跟段初始化相关的一些内容如下,初始化工作包含:利用 __iar_zero_init3 函数清零起始地址为 0x20000040 长度为 0x4c 字节的 ZI 段空间,利用 __iar_copy_init3 函数拷贝 0x40 字节 RW 段数据(从 0x300060fc 到 0x20000000):

*******************************************************************************
*** INIT TABLE
*** Address Size
------- ----
Zero (__iar_zero_init3)
1 destination range, total size 0x4c:
0x2000'0040 0x4c Copy (__iar_copy_init3)
1 source range, total size 0x40:
0x3000'60fc 0x40
1 destination range, total size 0x40:
0x2000'0000 0x40 *******************************************************************************
*** ENTRY LIST
*** Entry Address Size Type Object
---- ------- ---- ---- ------
.iar.init_table$$Base 0x3000'63d4 -- Gb - Linker created -
.iar.init_table$$Limit 0x3000'63f8 -- Gb - Linker created -
Region$$Table$$Base 0x3000'63d4 -- Gb - Linker created -
Region$$Table$$Limit 0x3000'63f8 -- Gb - Linker created -
__iar_copy_init3 0x3000'630d 0x2c Code Gb copy_init3.o [6]
__iar_zero_init3 0x3000'613d 0x3c Code Gb zero_init3.o [6]

  在映射文件里,我们知道了 Region$$Table 区域的起止地址 [0x300063d4 - 0x300063f8),打开镜像文件或者在线调试找到这段区域里的内容,你会发现段初始化工作所需的全部信息(操作函数地址、操作数据长度、操作源地址、操作目标地址)都记录在里面,其中特别注意的是涉及 Flash 区的地址都是以相对地址来存放的:

  • Note:FAddr_GetPtr 函数负责地址转换,0x300063d4 地址处的值是 0xfffffd69,那么 0x300063d4 + 0xfffffd69 = 0x13000613d,保留低 32bit 即是 __iar_zero_init3 函数地址。

  现在我们就很好理解 __iar_data_init3 函数里的代码了,它就是从 Region$$Table 区域里按序取出初始化工作所需的信息,并去一一执行完成段初始化的工作,这种实现方法的优点在于拓展性强,IAR 链接器可根据实际应用程序工程的链接情况自由拓展 Region$$Table 区域里的内容,而 __iar_data_init3 函数本身则不需要做任何修改。

  至此,IAR启动函数流程里的段初始化函数__iar_data_init3实现痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

痞子衡嵌入式:深扒IAR启动函数流程之段初始化函数__iar_data_init3实现的更多相关文章

  1. 痞子衡嵌入式:深扒IAR启动函数流程之段初始化实现中可用的压缩选项

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR启动函数流程里段初始化实现中可用的压缩选项. 接着 <IAR启动函数流程之段初始化函数__iar_data_init3实现& ...

  2. 痞子衡嵌入式:深扒IAR启动函数流程及其__low_level_init设计对函数重定向的影响

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR启动函数流程及其__low_level_init设计对函数重定向的影响. 上一篇文章 <IAR下RT-Thread工程自定义 ...

  3. 痞子衡嵌入式:在IAR开发环境下将关键函数重定向到RAM中执行的三种方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下将关键函数重定向到RAM中执行的三种方法. 嵌入式项目里应用程序代码正常是放在 Flash 中执行的,但有时候也需要将 ...

  4. 痞子衡嵌入式:在IAR开发环境下RT-Thread工程函数重定向失效分析

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下RT-Thread工程函数重定向失效分析. 痞子衡旧文 <在IAR下将关键函数重定向到RAM中执行的方法> ...

  5. 痞子衡嵌入式:在IAR开发环境下将整个源文件代码重定向到任意RAM中的方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下将整个源文件代码重定向到任意RAM中的方法. 痞子衡旧文 <在IAR下将关键函数重定向到RAM中执行的方法> ...

  6. 痞子衡嵌入式:在IAR开发环境下为工程开启CRC完整性校验功能的方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下为工程开启CRC完整性校验功能的方法. CRC校验在嵌入式领域里的应用非常广,比如在通信领域,CRC检验值可以作为数据 ...

  7. 痞子衡嵌入式:浅析IAR下调试信息输出机制之硬件UART外设

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR下调试信息输出机制之硬件UART外设. 在嵌入式世界里,输出打印信息是一种非常常用的辅助调试手段,借助打印信息,我们可以比较容易地 ...

  8. 痞子衡嵌入式:浅析IAR下调试信息输出机制之半主机(Semihosting)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR下调试信息输出机制之半主机(Semihosting). 在嵌入式世界里,输出打印信息是一种非常常用的辅助调试手段,借助打印信息,我 ...

  9. 痞子衡嵌入式:深扒i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合. 在串行 NOR Flash 热启动过程 ...

随机推荐

  1. python函数参数类型:位置参数、默认参数、动态参数、关键字参数

    1.位置参数:调用函数的时候传的参数,参数默认按顺序赋值,如果是指定那个参数赋值,不关注顺序.指定参数a=1,b=2 就在函数体内a=1,b=2 2.默认参数:在定义函数的时候,给某个参数设置默认值 ...

  2. SpringMVC 数据响应

    页面跳转 返回字符串形式 直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转. @RequestMapping("/quick") public String ...

  3. MySQL复习(一)MySQL架构

    MySQL架构 MySQL采用的是C/S架构,我们在使用MySQL的时候,都是以客户端的身份,发送请求连接到运行服务端的MySQL守护进程,而MySQL服务器端则根据我们的请求进行处理并把处理后的结果 ...

  4. the Agiles Scrum Meeting 5

    会议时间:2020.4.13 20:00 1.每个人的工作 今天已完成的工作 增量组:完成了增量开发的基础工作,初步完成了自动评测机制 issues:增量组:准备评测机制,增加仓库自动创建和管理 完善 ...

  5. eureka服务端和客户端的简单搭建

    本篇博客简单记录一下,eureka 服务端和 客户端的简单搭建. 目标: 1.完成单机 eureka server 和 eureka client 的搭建. 2.完成eureka server 的添加 ...

  6. reactnative实现qq聊天消息气泡拖拽消失效果

    前言(可跳过) 我在开发自己的APP时遇到了一个类似于qq聊天消息气泡拖拽消息的需求,因为在网上没有找到相关的组件,所以自己动手实现了一下 需求:对聊天消息气泡拖拽到一定长度松开时该气泡会消失(可自行 ...

  7. Go并发编程--Mutex/RWMutex

    目录 一.前言 二. Mutex 2.1 案例 三. 实现原理 3.1 锁的实现模式 3.2 Go Mutex 实现原理 3.2.1 加锁 3.2.2 解锁 四. 源码分析 4.1 Mutex基本结构 ...

  8. Pod 生命周期和重启策略

    Pod 在整个生命周期中被系统定义为各种状态,熟悉 Pod 的各种状态对于理解如何设置 Pod 的调度策略.重启策略是很有必要的. Pod 的状态 状态值 描述 Pending API Server ...

  9. Qt 项目管理文件(.pro) 详解

    项目文件目录树 在 Qt Creator 中新建一个 Widget Application 项目 samp2_1,在选择窗口基类的页面选择 QWidget 作为窗体基类,并选中"Genera ...

  10. 远程连接linux | Xshell和Xftp下载安装

    为什么需要远程登录linux 公司开发时候, 具体的情况是这样的: Linux 一般作为服务器使用,而服务器一般放在机房,你不可能在机房操作你的 Linux 服务器.这时我们就需要远程登录到Linux ...