大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是在IAR开发环境下RT-Thread工程函数重定向失效分析

  痞子衡旧文 《在IAR下将关键函数重定向到RAM中执行的方法》 里介绍了三种关键函数重定向方法,不过这三种方法只是写法形式不同,本质上没啥区别,都是利用 IAR 链接器特性将函数重定向到工程数据段(RW)所在 RAM 里。

  对于 i.MXRT 这种拥有多块地址非连续的 RAM 的芯片,其实我们也可以单独将这些重定向函数放到一个指定的 RAM 里,不一定非得跟数据段放在同一个 RAM 里。具体实现也很简单,只需要在链接文件里额外加一句 place in 语句处理即可,恩智浦官方 SDK 包里就是这么做的。

  然而痞子衡最近在移植一个 i.MXRT1170 RT-Thread 工程时发现,在 IAR 链接文件里用自定义段来单独指定重定向函数到 ITCM 竟然失效了,这是怎么回事?今天我们一起来看一下:

一、回顾SDK里函数重定向做法

  我们以最经典的 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\hello_world\cm7\iar 例程来看,工程 Build 选择 flexspi_nor_sdram_debug(仅该 build 预编译宏里有 XIP_BOOT_HEADER_DCD_ENABLE=1),即代码段放在 Flash 里(0x30000000 - ),数据段放在 SDRAM 里(0x80000000 - )。

  在时钟初始化函数 BOARD_BootClockRUN() 里会调用如下 UpdateSemcClock() 函数,这个函数需要重定向到 RAM 里执行,在代码里先将它放到自定义 CodeQuickAccess 段里。

  1. #define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
  2. #if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
  3. #if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)
  4. AT_QUICKACCESS_SECTION_CODE(void UpdateSemcClock(void));
  5. void UpdateSemcClock(void)
  6. {
  7. SEMC->IPCMD = 0xA55A000D;
  8. while ((SEMC->INTR & 0x3) == 0);
  9. SEMC->INTR = 0x3;
  10. SEMC->DCCR = 0x0B;
  11. CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;
  12. }
  13. #endif
  14. #endif

  然后在工程链接文件 MIMXRT1176xxxxx_cm7_flexspi_nor_sdram.icf 里(仅摘录部分),再将 CodeQuickAccess 段单独放在 ITCM 里(0x00000000 - ),这就是官方 SDK 里的做法。

  1. define symbol m_data3_start = 0x80000000;
  2. define symbol m_data3_end = 0x82FFFFFF;
  3. define symbol m_qacode_start = 0x00000000;
  4. define symbol m_qacode_end = 0x0003FFFF;
  5. define region DATA3_region = mem:[from m_data3_start to m_data3_end-__size_cstack__];
  6. define region QACODE_region = mem:[from m_qacode_start to m_qacode_end];
  7. define block RW { first readwrite, section m_usb_dma_init_data };
  8. define block QACCESS_CODE { section CodeQuickAccess };
  9. initialize by copy { readwrite, section .textrw, section CodeQuickAccess };
  10. place in DATA3_region { block RW };
  11. place in QACODE_region { block QACCESS_CODE };

  编译链接 hello_world_demo_cm7.ewp 工程,然后查看其映射文件(hello_world_demo_cm7.map)找到跟 UpdateSemcClock() 函数相关的内容如下,显然这是符合预期的。这里特别注意一下,CodeQuickAccess 的类别显示的是 inited,表明其不是常见的 ro code,而是经过重定向的,而且 UpdateSemcClock() 函数所在 clock_config.o 里包含了 60个字节的 rw code。

  1. *******************************************************************************
  2. *** PLACEMENT SUMMARY
  3. ***
  4. define block QACCESS_CODE { section CodeQuickAccess };
  5. "P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
  6. Section Kind Address Size Object
  7. ------- ---- ------- ---- ------
  8. "P7": 0x3c
  9. QACCESS_CODE 0x0 0x3c <Block>
  10. QACCESS_CODE-1 0x0 0x3c <Init block>
  11. CodeQuickAccess inited 0x0 0x3c clock_config.o [1]
  12. - 0x3c 0x3c
  13. *******************************************************************************
  14. *** MODULE SUMMARY
  15. ***
  16. Module ro code rw code ro data rw data
  17. ------ ------- ------- ------- -------
  18. clock_config.o 2'644 60 844
  19. *******************************************************************************
  20. *** ENTRY LIST
  21. ***
  22. Entry Address Size Type Object
  23. ---- ------- ---- ---- ------
  24. UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [1]

二、引出RT-Thread下函数重定向失效问题

  现在来看 RT-Thread 工程,也是一个简单的 hello world(具体工程略去不表),其中 i.MXRT1170 芯片 BSP 部分直接来自于官方 SDK,链接文件也与 SDK 里一致,但是编译链接工程后查看其映射文件,发现跟 UpdateSemcClock() 函数相关的内容如下,CodeQuickAccess 的类别显示的是 ro code, UpdateSemcClock() 函数所在 clock_config.o 里干脆连 rw code 都没有。显然函数重定向失效了,链接文件里 initialize by copy { section CodeQuickAccess }; 语句没起作用,这显然就是一个分散链接而已。

  1. *******************************************************************************
  2. *** PLACEMENT SUMMARY
  3. ***
  4. define block QACCESS_CODE { section CodeQuickAccess };
  5. "P7": place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
  6. Section Kind Address Size Object
  7. ------- ---- ------- ---- ------
  8. "P7": 0x3c
  9. QACCESS_CODE 0x0 0x3c <Block>
  10. CodeQuickAccess ro code 0x0 0x3c clock_config.o [4]
  11. - 0x3c 0x3c
  12. *******************************************************************************
  13. *** MODULE SUMMARY
  14. ***
  15. Module ro code ro data rw data
  16. ------ ------- ------- -------
  17. clock_config.o 2'768 784
  18. *******************************************************************************
  19. *** ENTRY LIST
  20. ***
  21. Entry Address Size Type Object
  22. ---- ------- ---- ---- ------
  23. UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [4]

三、RT-Thread下函数重定向失效分析

  第一节里 SDK 裸机环境下函数重定向做法不会失效,RT-Thread 环境下同样的做法就失效了,难道 IAR 对 RTOS 支持不友好?但是痞子衡在 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\rtos_examples\freertos_hello 下做了相同实验,FreeRTOS 下这种函数重定向方式也是没有问题的(FreeRTOS 内核启动是在 main() 里),所以这个问题主要跟 RT-Thread 内核代码结构设计有关。

  经过裸机工程、RT-Thread 工程、FreeRTOS 工程三者对比,痞子衡找到了问题所在。RT-Thread 内核启动是在 /src/components.c 文件中的 __low_level_init() 函数里,而这个 __low_level_init() 函数本应是 IAR 入口函数 __iar_program_start() 中的一部分(IAR 系统库里有一个内置 PUBWEAK 版本),但是 RT-Thread 重实现了这个 __low_level_init() 函数,很不幸的是 IAR 链接器对于自定义段的函数重定向认定与原内置 __low_level_init() 函数设计有某种内在关联。

  当痞子衡将内核启动函数 rtthread_startup() 放到 main() 里,而将 components.c 文件里的 __low_level_init() 函数临时删掉时,函数重定向失效问题就解决了,不过这只是验证分析,并不是真正的解决方案。

四、RT-Thread下函数重定向失效解决方案

  经过痞子衡的一番尝试,在 RT-Thread 重写 __low_level_init() 函数的情况下,IAR 仅仅是无法正常处理自定义段的重定向函数代码体,而如果将那些需要重定向的函数用 __ramfunc 修饰,统一放到 IAR 内置默认的 .textrw 段里,IAR 是可以正常处理的(感觉更像是 IAR 的一个缺陷)。

  分析到这里,解决方案清晰了,首先是弃用 AT_QUICKACCESS_SECTION_CODE 宏,而改用 __ramfunc 来修饰 UpdateSemcClock() 函数:

  1. #if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
  2. #if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)
  3. __ramfunc void UpdateSemcClock(void)
  4. {
  5. SEMC->IPCMD = 0xA55A000D;
  6. while ((SEMC->INTR & 0x3) == 0);
  7. SEMC->INTR = 0x3;
  8. SEMC->DCCR = 0x0B;
  9. CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;
  10. }
  11. #endif
  12. #endif

  然后在工程链接文件 MIMXRT1176xxxxx_cm7_flexspi_nor_sdram.icf 里直接将 section .textrw 放到 ITCM 里:


  1. define symbol m_qacode_start = 0x00000000;
  2. define symbol m_qacode_end = 0x0003FFFF;
  3. define region QACODE_region = mem:[from m_qacode_start to m_qacode_end];
  4. initialize by copy { readwrite, section .textrw };
  5. place in QACODE_region { section .textrw };

  这时候再编译链接工程查看映射文件,函数重定向结果就符合预期了。

  1. *******************************************************************************
  2. *** PLACEMENT SUMMARY
  3. ***
  4. "P7": place in [from 0x0 to 0x3'ffff] { section .textrw };
  5. Section Kind Address Size Object
  6. ------- ---- ------- ---- ------
  7. "P7": 0x3c
  8. P7 0x0 0x3c <Init block>
  9. .textrw inited 0x0 0x3c clock_config.o [4]
  10. - 0x3c 0x3c
  11. *******************************************************************************
  12. *** MODULE SUMMARY
  13. ***
  14. Module ro code rw code ro data rw data
  15. ------ ------- ------- ------- -------
  16. clock_config.o 2'708 60 846
  17. *******************************************************************************
  18. *** ENTRY LIST
  19. ***
  20. Entry Address Size Type Object
  21. ---- ------- ---- ---- ------
  22. UpdateSemcClock 0x1 0x3c Code Gb clock_config.o [4]

  至此,在IAR开发环境下RT-Thread工程函数重定向失效分析痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

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

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

痞子衡嵌入式:在IAR开发环境下RT-Thread工程函数重定向失效分析的更多相关文章

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

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

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

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

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

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

  4. 痞子衡嵌入式:IAR内部C-SPY调试组件配套宏文件(.mac)用法介绍

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR内部C-SPY调试组件配套宏文件(.mac)用法. 痞子衡之前写过一篇 <JLink Script文件基础及其在IAR下调用 ...

  5. 痞子衡嵌入式:IAR在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致(J-Link / CMSIS-DAP)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR在线调试时设不同复位类型可能会导致i.MXRT下调试现象不一致. 做Cortex-M内核MCU嵌入式软件开发,可用的集成开发环境( ...

  6. 痞子衡嵌入式:其实i.MXRT下改造FlexSPI driver同样支持AHB方式去写入NOR Flash

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT下改造FlexSPI driver以AHB方式去写入NOR Flash. 痞子衡前段时间写过一篇 <串行NAND Fl ...

  7. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU特性介绍(2)- RT1052DVL6性能实测

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RT系列MCU的性能. 在前面的文章 i.MXRT微控制器概览 里,痞子衡给大家简介过恩智浦半导体在2017年推出的新 ...

  8. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU启动那些事(3)- Serial Downloader模式(sdphost/MfgTool)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RT系列MCU的Serial Downloader模式. 在上一篇文章 Boot配置(BOOT Pin, eFUSE) ...

  9. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU启动那些事(6)- Bootable image格式与加载(elftosb/.bd)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RT系列MCU的Bootable image格式与加载过程. 在i.MXRT启动系列第三篇文章 Serial Down ...

随机推荐

  1. Google Chrome打开权限设置开关(摄像头,录音等)

    在搜索框输入以下字符 chrome://flags/#unsafely-treat-insecure-origin-as-secure

  2. 如何做好 NodeJS 框架选型?

    作为一个有一定工作经验的工程师,工作中经常会遇到技术选型的问题.比如当我们在工作中需要使用到 NodeJS 时,第一个要解决的问题就是如何选择一个合适的框架. 不同的框架有不同的特点,如果我们仅仅从框 ...

  3. Vulnhub实战-FALL靶机👻

    Vulnhub实战-FULL靶机 下载地址:http://www.vulnhub.com/entry/digitalworldlocal-fall,726/ 1.描述 通过描述我们可以知道这个靶机枚举 ...

  4. vue.$set实现原理

    上源码: export function set (target: Array<any> | Object, key: any, val: any): any { if (process. ...

  5. javascript-原生-结构

    1.获取用户输入内容的方法 window.prompt("提示信息","默认值"); 获取用户输入内容(字符串类型),返回用户输入内容. 2.顺序结构:所有语句 ...

  6. 网络通信IO的演变过程(一)(一个门外汉的理解)

    以前从来不懂IO的底层,只知道一个大概,就是输入输出的管道怼到一起,然后就可以传输数据了. 最近看了周志垒老师的公开课后,醍醐灌顶. 所以做一个简单的记录. 0 计算机组成原理相关 0.1. 计算机的 ...

  7. 正则表达式: NFA引擎匹配原理

    NFA引擎匹配原理 1       为什么要了解引擎匹配原理 一个个音符杂乱无章的组合在一起,弹奏出的或许就是噪音,同样的音符经过作曲家的手,就可以谱出非常动听的乐曲,一个演奏者同样可以照着乐谱奏出动 ...

  8. BUAA_2019_OO_第一单元总结

    一.基于度量来分析自己的程序结构 1.第一次作业 1.1类图: 第一次作业由于比较简单,我采用了面向过程的编程方式.在Polynomail类的构造函数中将项直接求导输出.这样的弊端显而易见,不能进行优 ...

  9. Less3

    继续第三关的学习 1.根据第一关的记录,我们判断出是什么注入 id=1' and '1'='1 id=1' and '1'='2 返回不同,所以存在字符型的注入 2. 这时候我们再用正常的报错猜解准备 ...

  10. 连续子序列的最大和 牛客网 剑指Offer

    连续子序列的最大和 牛客网 剑指Offer 题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量 ...