zoukankan      html  css  js  c++  java
  • 痞子衡嵌入式:在IAR开发环境下RTThread工程自定义函数段重定向失效分析


      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是在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 段里。

    #define AT_QUICKACCESS_SECTION_CODE(func) func @"CodeQuickAccess"
    
    #if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
    #if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)
    AT_QUICKACCESS_SECTION_CODE(void UpdateSemcClock(void));
    void UpdateSemcClock(void)
    {
        SEMC->IPCMD = 0xA55A000D;
        while ((SEMC->INTR & 0x3) == 0);
        SEMC->INTR                                = 0x3;
        SEMC->DCCR                                = 0x0B;
        CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;
    }
    #endif
    #endif
    

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

    define symbol m_data3_start            = 0x80000000;
    define symbol m_data3_end              = 0x82FFFFFF;
    define symbol m_qacode_start           = 0x00000000;
    define symbol m_qacode_end             = 0x0003FFFF;
    define region DATA3_region  = mem:[from m_data3_start to m_data3_end-__size_cstack__];
    define region QACODE_region = mem:[from m_qacode_start to m_qacode_end];
    define block RW            { first readwrite, section m_usb_dma_init_data };
    define block QACCESS_CODE  { section CodeQuickAccess };
    initialize by copy         { readwrite, section .textrw, section CodeQuickAccess };
    place in DATA3_region                  { block RW };
    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。

    *******************************************************************************
    *** PLACEMENT SUMMARY
    ***
    define block QACCESS_CODE { section CodeQuickAccess };
    "P7":  place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
    
      Section              Kind         Address      Size  Object
      -------              ----         -------      ----  ------
    "P7":                                            0x3c
      QACCESS_CODE                          0x0      0x3c  <Block>
        QACCESS_CODE-1                      0x0      0x3c  <Init block>
          CodeQuickAccess  inited           0x0      0x3c  clock_config.o [1]
                                         - 0x3c      0x3c
    
    *******************************************************************************
    *** MODULE SUMMARY
    ***
        Module                              ro code  rw code  ro data  rw data
        ------                              -------  -------  -------  -------
        clock_config.o                        2'644       60      844
    
    *******************************************************************************
    *** ENTRY LIST
    ***
        Entry                       Address   Size  Type      Object
        ----                       -------   ----  ----      ------
        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 }; 语句没起作用,这显然就是一个分散链接而已。

    *******************************************************************************
    *** PLACEMENT SUMMARY
    ***
    define block QACCESS_CODE { section CodeQuickAccess };
    "P7":  place in [from 0x0 to 0x3'ffff] { block QACCESS_CODE };
    
      Section              Kind         Address    Size  Object
      -------              ----         -------    ----  ------
    "P7":                                          0x3c
      QACCESS_CODE                          0x0    0x3c  <Block>
        CodeQuickAccess    ro code          0x0    0x3c  clock_config.o [4]
                                         - 0x3c    0x3c
    
    *******************************************************************************
    *** MODULE SUMMARY
    ***
        Module                              ro code  ro data  rw data
        ------                              -------  -------  -------
        clock_config.o                        2'768      784
    
    *******************************************************************************
    *** ENTRY LIST
    ***
        Entry                       Address   Size  Type      Object
        ----                       -------   ----  ----      ------
        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 的一个缺陷)。

    源文件处理 链接文件处理 IAR 最终链接结果
    放入自定义程序段 CodeQuickAccess 仅 initialize by copy { section CodeQuickAccess }; 函数直接链在代码段所在 Flash 区,无效重定向
    放入自定义程序段 CodeQuickAccess initialize by copy { section CodeQuickAccess };
    place in ITCM_region { section CodeQuickAccess };
    函数直接链在 ITCM 里,无效重定向
    __ramfunc 修饰放入默认段 .textrw 仅 initialize by copy { section .textrw }; 函数体保存在代码段所在区,但链接在数据段所在 RAM 区,有效重定向
    __ramfunc 修饰放入默认段 .textrw initialize by copy { section .textrw };
    place in ITCM_region { section .textrw };
    函数体保存在代码段所在区,但链接在 ITCM 里,有效重定向

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

    #if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
    #if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)
    __ramfunc void UpdateSemcClock(void)
    {
        SEMC->IPCMD = 0xA55A000D;
        while ((SEMC->INTR & 0x3) == 0);
        SEMC->INTR                                = 0x3;
        SEMC->DCCR                                = 0x0B;
        CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;
    }
    #endif
    #endif
    

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

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

      这时候再编译链接工程查看映射文件,函数重定向结果就符合预期了。.textrw 的类别显示的是 inited,而且 UpdateSemcClock() 函数所在 clock_config.o 里也包含了 60个字节的 rw code。

    *******************************************************************************
    *** PLACEMENT SUMMARY
    ***
    "P7":  place in [from 0x0 to 0x3'ffff] { section .textrw };
    
      Section              Kind         Address    Size  Object
      -------              ----         -------    ----  ------
    "P7":                                          0x3c
      P7                                    0x0    0x3c  <Init block>
        .textrw            inited           0x0    0x3c  clock_config.o [4]
                                         - 0x3c    0x3c
    
    *******************************************************************************
    *** MODULE SUMMARY
    ***
        Module                              ro code  rw code  ro data  rw data
        ------                              -------  -------  -------  -------
        clock_config.o                        2'708       60      846
    
    *******************************************************************************
    *** ENTRY LIST
    ***
        Entry                       Address   Size  Type      Object
        ----                       -------   ----  ----      ------
        UpdateSemcClock                 0x1    0x3c  Code  Gb  clock_config.o [4]
    

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

    欢迎订阅

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

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

      最后欢迎关注痞子衡个人微信公众号【痞子衡嵌入式】,一个专注嵌入式技术的公众号,跟着痞子衡一起玩转嵌入式。

    痞子衡嵌入式-微信二维码 痞子衡嵌入式-微信收款二维码 痞子衡嵌入式-支付宝收款二维码

      衡杰(痞子衡),目前就职于恩智浦MCU系统部门,担任嵌入式系统应用工程师。

      专栏内所有文章的转载请注明出处:http://www.cnblogs.com/henjay724/

      与痞子衡进一步交流或咨询业务合作请发邮件至 hengjie1989@foxmail.com

      可以关注痞子衡的Github主页 https://github.com/JayHeng,有很多好玩的嵌入式项目。

      关于专栏文章有任何疑问请直接在博客下面留言,痞子衡会及时回复免费(划重点)答疑。

      痞子衡邮箱已被私信挤爆,技术问题不推荐私信,坚持私信请先扫码付款(5元起步)再发。


  • 相关阅读:
    花匠
    积木
    Hello world
    老鼠走迷宫全部路径
    今天下午选做题目
    整数高精度运算——加法
    博客启航
    解线性不定方程
    关于完全背包问题
    关于最小代价子母树
  • 原文地址:https://www.cnblogs.com/henjay724/p/15553843.html
Copyright © 2011-2022 走看看