c - GCC 忽略 __attribute__((section ("CCMRAM")))。怎么修?

标签 c gcc linker arm ld

我正在尝试使用我的 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};

但没有效果。

map 文件不包含任何关于 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) }
}

最佳答案

.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

关于c - GCC 忽略 __attribute__((section ("CCMRAM")))。怎么修?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64203031/

相关文章:

c - 如何使用 FFmpeg API 将多张图片合二为一?

c++ - 替代 C、C++?

c++ - 由于库的包含语句,无法通过 GCC 编译使用库 (FFmpeg) 的 C 程序

c++ - makefile 为不同的体系结构设置不同的链接器标志

gcc - 如何防止 GCC 在链接时优化期间插入 memset?

C-编号检查功能给出无限循环

linux - 在 Ubuntu 上使用 makefile 编译时出现问题

c++ - 将 GCC/ATT 风格的汇编程序转换为 visual studio 汇编程序?

ios - Apple Mach-O 链接器错误(当我选择 iOS 设备时无法构建我的应用程序)

c - 当递增 16 时,unsigned char 从 f0 变为 00