【问题标题】:GCC ignores __attribute__((section("CCMRAM"))). How to fix?GCC 忽略 __attribute__((section("CCMRAM")))。怎么修?
【发布时间】:2021-01-19 23:44:26
【问题描述】:

我正在尝试使用我的 cortex-m4 (STM32F407) 的核心耦合内存 (CCMRAM)。它适用于 Keil MDK-ARM,但 gcc-arm-none-eabi 会忽略 __attribute__((section("CCMRAM")))

 #define configTOTAL_HEAP_SIZE 1000*1024
 #define region1_HEAP_SIZE  (40*1024)
 #define region2_HEAP_SIZE  (configTOTAL_HEAP_SIZE - region1_HEAP_SIZE)

 static uint8_t ucHeap1[ region1_HEAP_SIZE ]  __attribute__((section("CCMRAM")));
 static uint8_t ucHeap2[ region2_HEAP_SIZE ];
 const HeapRegion_t xHeapRegions[] =
 {
     { ucHeap1, sizeof(ucHeap1) },
     { ucHeap2, sizeof(ucHeap2) },
     { NULL, 0 } /* Terminates the array. */
 };

手册https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Common-Variable-Attributes.html#Common-Variable-Attributes

根据手册我也尝试初始化ucHeap1

 static uint8_t ucHeap1[ region1_HEAP_SIZE ]  __attribute__((section("CCMRAM"))) = {0};

但是没有效果。

地图文件不包含任何关于ucHeap1 的内容。 GCC 编译时没有关于属性的警告。但未能链接,原因是:

arm-none-eabi/bin/ld: avds.elf section `.bss' will not fit in region `RAM'
arm-none-eabi/bin/ld: region `RAM' overflowed by 55032 bytes

这些 55032 应该分配在 CCMRAM 中。但它试图使用 RAM。 请帮助我了解如何使其工作。

链接器脚本:

ENTRY(Reset_Handler)
_estack = 0x20000000 + 128K - 1;
_Min_Heap_Size = 0;
_Min_Stack_Size = 0x200;
MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K
  RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
  CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
SECTIONS
{
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector))
    . = ALIGN(4);
  } >FLASH
  .text :
  {
    . = ALIGN(4);
    *(.text)
    *(.text*)
    *(.glue_7)
    *(.glue_7t)
    *(.eh_frame)
    KEEP (*(.init))
    KEEP (*(.fini))
    . = ALIGN(4);
    _etext = .;
  } >FLASH
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)
    *(.rodata*)
    . = ALIGN(4);
  } >FLASH
  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH
  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH
  _sidata = LOADADDR(.data);
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;
    *(.data)
    *(.data*)
    . = ALIGN(4);
    _edata = .;
  } >RAM AT> FLASH
  _siccmram = LOADADDR(.ccmram);
  .ccmram :
  {    . = ALIGN(4);
    _sccmram = .;
    *(.ccmram)
    *(.ccmram*)
    . = ALIGN(4);
    _eccmram = .;
  } >CCMRAM AT> FLASH
  . = ALIGN(4);
  .bss :
  {
    _sbss = .;
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
    . = ALIGN(4);
    _ebss = .;
    __bss_end__ = _ebss;
  } >RAM
  ._user_heap_stack :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }
  .ARM.attributes 0 : { *(.ARM.attributes) }
}

【问题讨论】:

  • 请创建一个minimal reproducible exampleHeapRegion_t 是什么? *(.ccmram).ccram != CCRAM,不是吗?
  • 很难,因为上下文足够大。 stm32 和 cmsis 和 freertos 合二为一看起来是一个足够大的项目

标签: c gcc linker arm ld


【解决方案1】:

.ccmram 部分名称不是 CCMRAM。请注意,带有前导点的部分应该由一个小的忽略约定留给实现。所以更喜欢只使用没有前导点的部分名称。

删除您的 .ccmram : { ... } 并将其替换为:

 .ccmram :   {
    .  = ALIGN(4);
    _sccmram = .;
    KEEP(*(CCMRAM))    # section is named CCMRAM __not__ .ccmram and __not__ .ccmram*
    . = ALIGN(4);  
    _eccmram = .;
 } >CCMRAM AT> FLASH

改变之后:

$ arm-none-eabi-gcc main.c -Wl,-T,./linker.ld --specs=nosys.specs && arm-none-eabi-nm ./a.out  | grep ucHeap
/usr/lib/gcc/arm-none-eabi/10.2.0/../../../../arm-none-eabi/bin/ld: warning: cannot find entry symbol Reset_Handler; defaulting to 0000000008000000
10000000 d ucHeap1
20000434 b ucHeap2

或者,您也可以将 __attribute__((section("CCMRAM"))) 更改为 __attribute__((section(".ccmram")))__attribute__((section(".ccmram*"))) 以匹配链接描述文件中使用的部分名称。

您的.bss 部分仍然可能溢出。在我的测试中,configTOTAL_HEAP_SIZE 宏是未定义的,region2_HEAP_SIZE- 40*1024,它是负数,因此被环绕并导致一个很大的正数。

我测试过:

cat >Makefile <<EOF    
all:
    arm-none-eabi-gcc main.c -Wl,-T,./linker.ld --specs=nosys.specs && arm-none-eabi-nm ./a.out  | grep ucHeap
EOF

cat >linker.ld <<EOF
ENTRY(Reset_Handler)
_estack = 0x20000000 + 128K - 1;
_Min_Heap_Size = 0;
_Min_Stack_Size = 0x200;
MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K
  RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
  CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
SECTIONS
{
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector))
    . = ALIGN(4);
  } >FLASH
  .text :
  {
    . = ALIGN(4);
    *(.text)
    *(.text*)
    *(.glue_7)
    *(.glue_7t)
    *(.eh_frame)
    KEEP (*(.init))
    KEEP (*(.fini))
    . = ALIGN(4);
    _etext = .;
  } >FLASH
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)
    *(.rodata*)
    . = ALIGN(4);
  } >FLASH
  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH
  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH
  _sidata = LOADADDR(.data);
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;
    *(.data)
    *(.data*)
    . = ALIGN(4);
    _edata = .;
  } >RAM AT> FLASH

  .ccmram :
  {
    . = ALIGN(4);
    _sccmram = .;
    KEEP(*(CCMRAM))
    . = ALIGN(4);
    _eccmram = .;
  } >CCMRAM AT> FLASH
  . = ALIGN(4);
  .bss :
  {
    _sbss = .;
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)
    . = ALIGN(4);
    _ebss = .;
    __bss_end__ = _ebss;
  } >RAM
  ._user_heap_stack :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }
  .ARM.attributes 0 : { *(.ARM.attributes) }
}
EOF

cat >main.c <<EOF
#include <stdint.h>
#include <stddef.h>
static uint8_t ucHeap1[ 10 ]  __attribute__((section("CCMRAM")));
static uint8_t ucHeap2[ 20 ];
typedef struct {
    uint8_t *p;
    size_t s;
} HeapRegion_t;
const HeapRegion_t xHeapRegions[] =
{
     { ucHeap1, sizeof(ucHeap1) },
     { ucHeap2, sizeof(ucHeap2) },
     { NULL, 0 } /* Terminates the array. */
};
int main() {
    return xHeapRegions[1].s;
}
EOF

【讨论】:

  • 如何让 gcc 对不存在的部分产生错误/警告?
  • 我不知道。最简单的可能是创建一个允许的部分列表并列出生成的可执行文件的部分,然后查看是否有任何不允许的部分。
【解决方案2】:
__attribute__((section("CCMRAM")));

您没有CCMRAM 部分。你有部分.ccmram

【讨论】:

  • 链接器甚至不是 gcc。他们确实彼此了解,所以这是不可能的。生成地图文件并检查
  • 在地图文件中检查什么?搜索什么?
  • 为你的变量
猜你喜欢
  • 1970-01-01
  • 2020-05-23
  • 2013-08-23
  • 2016-03-31
  • 2016-02-13
  • 1970-01-01
  • 2013-08-31
  • 2011-02-17
  • 1970-01-01
相关资源
最近更新 更多