IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    cmake 构建环境下自定义 section 失效的问题

    Hacper\'s Blog发表于 2023-12-17 17:04:49
    love 0

    由于项目需要,前几天在调整 NXP RW612 MCU wifi SDK 的构建系统,由原来的 cmake+mingw+a+make+armgcc 调整为 cmake+kcongfig+ninja+mingw+armcc。构建系统调整完成之后,发现烧录固件设备无法启动,而未调整之前编译出来的固件是正常的。

    查找原因

    对比二者编译生成的固件镜像文件,旧构建系统生成的固件比新构建系统生成的固件文件大小大一点。首先怀疑的是否是一些宏定义没启用,部分代码被屏蔽了而未编译进去,经过一些测试和检查之后发现不是这个问题。接下来从map文件着手,对比发现map文件有差异。

    旧构建系统的map信息:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    .flash_config   0x08000000     0x1000
                    0x08000000                . = ALIGN (0x4)
     FILL mask 0xff
                    0x00000400                . = 0x400
     *fill*         0x08000000      0x400 ff
                    0x08000400                __FLASH_BASE = .
     *(.flash_conf)
     .flash_conf    0x08000400      0xc00 out/libs/libmcux_sdk_module_lib.a(flash_config.c.obj)
                    0x08000400                flexspi_config
                    0x00001000                . = 0x1000
    
    .interrupts     0x00001000      0x280 load address 0x08001000
                    0x00001000                . = ALIGN (0x4)
                    0x00001000                __VECTOR_TABLE = .
                    0x00001000                __Vectors = .
    

    新构建系统的map信息:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    .flash_config   0x08000000     0x1000
                    0x08000000                . = ALIGN (0x4)
     FILL mask 0xff
                    0x00000400                . = 0x400
     *fill*         0x08000000      0x400 ff
                    0x08000400                __FLASH_BASE = .
     *(.flash_conf)
                    0x00001000                . = 0x1000
     *fill*         0x08000400      0xc00 ff
    
    .interrupts     0x00001000      0x280 load address 0x08001000
                    0x00001000                . = ALIGN (0x4)
                    0x00001000                __VECTOR_TABLE = .
                    0x00001000                __Vectors = .
    

    旧的构建系统有将 flash_config.c.obj 的代码 flexspi_config 存储在 .flash_config 这个 section,而新的固件却没有,整个map文件都查不到 flexspi_config 的信息。根据 flash_config.c 的代码在这篇文章痞子衡嵌入式:深扒i.MXRTxxx系列ROM中集成的串行NOR Flash启动SW Reset功能及其应用场合中找到 flexspi_config 的作用:flexspi_config 是固件镜像的启动头 FDCB,bootrom 用来给 FlexSPI 外设初始化 flash 用的。对比两个镜像文件也能看到差异,一个有 FDCB,一个没有。

    那么 FDCB 是怎么生成的呢?

    查看 RW612 的 ld 文件:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    
    /* Entry Point */
    ENTRY(Reset_Handler)
    
    HEAP_SIZE  = DEFINED(__heap_size__)  ? __heap_size__  : 0x400;
    STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x400;
    
    /* Specify the memory areas */
    MEMORY
    {
      m_flash               (RX)  : ORIGIN = 0x08000000, LENGTH = 0x00200000
      m_interrupts          (RX)  : ORIGIN = 0x00001000, LENGTH = 0x00000280
      m_text                (RX)  : ORIGIN = 0x00001280, LENGTH = 0x000B9080
    }
    /* 0x2012_3000 - 0x2012_FFFF is reserved for BootROM usage */
    
    /* Define output sections */
    SECTIONS
    {
      .flash_config :
      {
        . = ALIGN(4);
        FILL(0xFF)
        . = 0x400;
        __FLASH_BASE = .;
        KEEP(* (.flash_conf))     /* flash config section */
        . = 0x1000;
      } > m_flash
    
      /* The startup code goes first into internal ram */
    
      /*....*/
    }
    

    在flash的起始地址定义了一个 4K大小的 .flash_config section,前面填充 1K 0xFF, 后面开始存储 flash_conf 的代码。 在 boards\rdrw612bga\flash_config\flash_config.c 也指定了将代码放到 flash_conf section: attribute((section(".flash_conf"), used))

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    
    #if defined(BOOT_HEADER_ENABLE) && (BOOT_HEADER_ENABLE == 1)
    
    #if defined(__ARMCC_VERSION) || defined(__GNUC__)
    
    __attribute__((section(".flash_conf"), used))
    
    #elif defined(__ICCARM__)
    
    #pragma location = ".flash_conf"
    
    #endif
    
    const fc_flexspi_nor_config_t flexspi_config = {
        .memConfig =
            {
                .tag                 = FC_BLOCK_TAG,
                .version             = FC_BLOCK_VERSION,
                .readSampleClkSrc    = 1,
                .csHoldTime          = 3,
                .lookupTable =
                    {
                        /* Read */
                        [0] = FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0xEC, FC_RADDR_SDR, FC_FLEXSPI_4PAD, 0x20),
                        [1] = FC_FLEXSPI_LUT_SEQ(FC_DUMMY_SDR, FC_FLEXSPI_4PAD, 0x0A, FC_READ_SDR, FC_FLEXSPI_4PAD, 0x04),
                        /* chip erase */
                        [4 * 11 + 0] =
                            FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0x60, FC_STOP_EXE, FC_FLEXSPI_1PAD, 0x00),
                    },
            },
        .pageSize           = 0x100,
        .sectorSize         = 0x1000,
        .ipcmdSerialClkFreq = 0,
        .blockSize          = 0x8000,
        .fcb_fill[0]        = 0xFFFFFFFF,
    };
    
    #endif /* BOOT_HEADER_ENABLE */
    

    那么为什么 FDCB 在新的构建系统下没有生成呢?

    我发现二者的差异在于旧构建系统是将flash_config.c放到了构建可执行文件目标的源码里面 add_executable。而新的构建系统是将 flash_config.c 放到构建静态库的源码里面 add_library,然后在构建可执行目标文件的时候通过添加依赖的lib target_link_libraries 加入,在最终链接的时候由于 flash_config.c 的代码未使用而被删除了,即使配置了 attribute((section(".flash_conf"), used)) 也会删除,这个应该是 cmake 的问题。

    解决办法有两个:

    1. 将 flash_config.c 放到构建可执行目标的源码里面。
    2. 找个地方调用一下 flash_config.c 里的变量或者函数,避免未使用而被优化。

    使用 cmake 构建系统时需要留意这个坑,如果需要自定义 section 指定变量或者函数的存储位置,要留意代码有没有被使用和是否是在构建可执行的目标的源码中,不然即便设置了 attribute((section(".xx"), used)) 也还是会被优化删除。

    资料

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


沪ICP备19023445号-2号
友情链接