I'm having trouble in setting the section attribute of gcc to define that a variable should reside in a specific memory section instead of the default.
I'm using the arm cortex m3 LPC1759. I got the link files from LPCXpresso IDE, but I don't use it, I have my own makefile. The link files are:
INCLUDE "./link/LPCmem.ld" /* see below */
ENTRY(ResetISR)
SECTIONS
{
/* MAIN TEXT SECTION */
.text : ALIGN(4)
{
FILL(0xff)
__vectors_start__ = ABSOLUTE(.) ;
KEEP(*(.isr_vector))
/* Global Section Table */
. = ALIGN(4) ;
__section_table_start = .;
__data_section_table = .;
LONG(LOADADDR(.data));
LONG( ADDR(.data));
LONG( SIZEOF(.data));
LONG(LOADADDR(.data_RAM2));
LONG( ADDR(.data_RAM2));
LONG( SIZEOF(.data_RAM2));
__data_section_table_end = .;
__bss_section_table = .;
LONG( ADDR(.bss));
LONG( SIZEOF(.bss));
LONG( ADDR(.bss_RAM2));
LONG( SIZEOF(.bss_RAM2));
__bss_section_table_end = .;
__section_table_end = . ;
/* End of Global Section Table */
*(.after_vectors*)
} >FLASH
.text : ALIGN(4)
{
*(.text*)
*(.rodata .rodata.* .constdata .constdata.*)
. = ALIGN(4);
} > FLASH
/*
* for exception handling/unwind - some Newlib functions (in common
* with C++ and STDC++) use this.
*/
.ARM.extab : ALIGN(4)
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx : ALIGN(4)
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
_etext = .;
/* DATA section for SRAM0 */
.data_RAM2 : ALIGN(4)
{
FILL(0xff)
*(.ramfunc.$RAM2)
*(.ramfunc.$SRAM0)
*(.data.$RAM2*)
*(.data.$SRAM0*)
. = ALIGN(4) ;
} > SRAM0 AT>FLASH
/* MAIN DATA SECTION */
.uninit_RESERVED : ALIGN(4)
{
KEEP(*(.bss.$RESERVED*))
. = ALIGN(4) ;
_end_uninit_RESERVED = .;
} > SRAM
/* Main DATA section (SRAM) */
.data : ALIGN(4)
{
FILL(0xff)
_data = . ;
*(vtable)
*(.ramfunc*)
*(.data*)
. = ALIGN(4) ;
_edata = . ;
} > SRAM AT>FLASH
/* BSS section for SRAM0 */
.bss_RAM2 : ALIGN(4)
{
*(.bss.$RAM2*)
*(.bss.$SRAM0*)
. = ALIGN(4) ;
} > SRAM0
/* MAIN BSS SECTION */
.bss : ALIGN(4)
{
_bss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4) ;
_ebss = .;
PROVIDE(end = .);
} > SRAM
/* NOINIT section for SRAM0 */
.noinit_RAM2 (NOLOAD) : ALIGN(4)
{
*(.noinit.$RAM2*)
*(.noinit.$SRAM0*)
. = ALIGN(4) ;
} > SRAM0
/* DEFAULT NOINIT SECTION */
.noinit (NOLOAD): ALIGN(4)
{
_noinit = .;
*(.noinit*)
. = ALIGN(4) ;
_end_noinit = .;
} > SRAM
PROVIDE(_pvHeapStart = .);
PROVIDE(_vStackTop = __top_SRAM - 0);
}
/* Define each memory region */
MEMORY
{
FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x80000 /* 512K bytes */
SRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 0x8000 /* 32K bytes */
SRAM0 (rwx) : ORIGIN = 0x2007c000, LENGTH = 0x8000 /* 32K bytes */
}
/* Define a symbol for the top of each memory region */
__top_FLASH = 0x0 + 0x80000;
__top_SRAM = 0x10000000 + 0x8000;
__top_SRAM0 = 0x2007c000 + 0x8000;
Above is the LPCmem.ld file included by the previous file.
I'm forcing the freertos heap variable to be in the custom section, like this:
static unsigned char ucHeap[ configTOTAL_HEAP_SIZE ]
__attribute__((section(".data_RAM2")));
The linking of objects files are done without errors, but the variable isn't placed in the right memory position, how I could check with nm command:
...
10000028 d ucHeap
10002028 d uxCriticalNesting
...
I try to change the section to other that doesn't exists, just to check if the linker verify the names and apparently it doesn't.
TL;DR - You are just missing the dollar sign.
You are naming the section wrong. The relevant portions of the linker file are,
/* DATA section for SRAM0 */
.data_RAM2 : ALIGN(4)
{
FILL(0xff)
*(.ramfunc.$RAM2)
*(.ramfunc.$SRAM0)
*(.data.$RAM2*)
*(.data.$SRAM0*)
/* *(.data_RAM2); You need this, without a code change, */
/* but it will still match data. */
. = ALIGN(4) ;
} > SRAM0 AT>FLASH
/* Main DATA section (SRAM) */
.data : ALIGN(4)
{
FILL(0xff)
_data = . ;
*(vtable)
*(.ramfunc*)
*(.data*) /* Otherwise, this matches your section. */
. = ALIGN(4) ;
_edata = . ;
} > SRAM AT>FLASH
Currently, you have ucHeap
in .data_RAM2
. The linker file used .data.$RAM2*
, but this will not match. The *
is a wild card. So the *(.data*)
will match your code as you currently have it. I don't know if you have an issue with,
static unsigned char ucHeap[ configTOTAL_HEAP_SIZE ]
__attribute__((section(".data_$RAM2")));
This seems to work with my version of gcc. You are just missing the dollar sign.
See the gnu ld documentation, specifically the input sections. The form is,
archive:object file(input section ...); where you can use the wild cards and can omit the archive:, if you like. The wildcards are a limited reg-ex form. You can give many input sections if you like; for example *(.text* .rodata*)
will place the .text
and .rodata
from the same object together. Where as, *(.text*); *(.rodata*);
will keep all .text
together from all object files and then place the .rodata
.