been following the blog series and trying to get my head around a few things. I have a requirement to execute some system control functions from RAM rather than flash and after some reading found a suggestion to just add the .data section attribute to the function. So having added the following:
I can see the relevant code in the disassembly being placed at the start of my RAM region but when I run the test (in a simulation) I can see that the code is still executed from flash. Itās strange as I can see the RAM location being initialised with the correct instructions but thatās the only time they are accessed.
Having done some more reading I saw a note mentioning that the attribute should also be applied to any function that this function calls. But all Iām doing is accessing a memory mapped peripheral to toggle a GPIO as a first pass test.
Am I not using the correct attribute or making another mistake?
So having got the basic case working by adding the above attribute I went a step further and tried to place these functions in my āinstructionā ram. I created a new section in my linker script but running objcopy now creates a huge binary.
This seems to be a common issue with a broken linker script but I canāt a solution. Iāve copied my linker scipt below. My section name is .iram and that should go into the IRAM memory.
/******************************************************************************
* @file gcc_arm.ld
* @brief GNU Linker Script for Cortex-M based device
* @version V2.0.0
* @date 21. May 2019
******************************************************************************/
/*
* Copyright (c) 2009-2019 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
;-------- <<< Use Configuration Wizard in Context Menu >>> -------------------
*/
/*--------------------- Flash Configuration ----------------------------------
; <h> Flash Configuration
; <o0> Flash Base Address <0x0-0xFFFFFFFF:8>
; <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
-----------------------------------------------------------------------------*/
__ROM_BASE = 0x00000000;
__ROM_SIZE = 0x00008000;
/*--------------------- Embedded RAM Configuration ---------------------------
; <h> RAM Configuration
; <o0> RAM Base Address <0x0-0xFFFFFFFF:8>
; <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
-----------------------------------------------------------------------------*/
__IRAM_BASE = 0x10000000;
__IRAM_SIZE = 0x00004000;
__DRAM_BASE = 0x20000000;
__DRAM_SIZE = 0x00008000;
/*--------------------- Stack / Heap Configuration ---------------------------
; <h> Stack / Heap Configuration
; <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
-----------------------------------------------------------------------------*/
__STACK_SIZE = 0x00000400;
__HEAP_SIZE = 0x00000000;
/*
;-------------------- <<< end of configuration section >>> --------------------
*/
INCLUDE "lib-nosys.ld"
MEMORY
{
FLASH (rx) : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE
IRAM (rwx) : ORIGIN = __IRAM_BASE, LENGTH = __IRAM_SIZE
DRAM (rwx) : ORIGIN = __DRAM_BASE, LENGTH = __DRAM_SIZE
}
/* Linker script to place sections and symbol values. Should be used together
* with other linker script that defines memory regions FLASH and RAM.
* It references following symbols, which must be defined in code:
* Reset_Handler : Entry of reset handler
*
* It defines following symbols, which code can use without definition:
* __exidx_start
* __exidx_end
* __copy_table_start__
* __copy_table_end__
* __zero_table_start__
* __zero_table_end__
* __etext
* __data_start__
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* __data_end__
* __bss_start__
* __bss_end__
* __end__
* end
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
*/
ENTRY(Reset_Handler)
SECTIONS
{
.text :
{
KEEP(*(.vectors))
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*))
} > FLASH
/* SG veneers:
All SG veneers are placed in the special output section .gnu.sgstubs. Its start address
must be set, either with the command line option ā--section-startā or in a linker script,
to indicate where to place these veneers in memory.
*/
/*
.gnu.sgstubs :
{
. = ALIGN(32);
} > FLASH
*/
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
.copy.table :
{
. = ALIGN(4);
__copy_table_start__ = .;
LONG (__etext)
LONG (__data_start__)
LONG (__data_end__ - __data_start__)
/** Add each additional data section here */
LONG (__etext2)
LONG (__data2_start__)
LONG (__data2_end__ - __data2_start__)
__copy_table_end__ = .;
} > FLASH
.zero.table :
{
. = ALIGN(4);
__zero_table_start__ = .;
/** Add each additional bss section here */
/*
LONG (__bss2_start__)
LONG (__bss2_end__ - __bss2_start__)
*/
__zero_table_end__ = .;
} > FLASH
/* Location counter can end up 2byte aligned with narrow Thumb code but
__etext is assumed by startup code to be the LMA of a section in RAM
which must be 4byte aligned */
__etext = ALIGN (4);
.data : AT (__etext)
{
__data_start__ = .;
*(vtable)
*(.data)
*(.data.*)
. = ALIGN(4);
*(.dram)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
KEEP(*(.jcr*))
. = ALIGN(4);
/* All data end */
__data_end__ = .;
} > DRAM
/**
* Secondary data section, optional
*
* Remember to add each additional data section
* to the .copy.table above to asure proper
* initialization during startup.
*/
__etext2 = ALIGN (4);
.data2 : AT (__etext2)
{
. = ALIGN(4);
__data2_start__ = .;
*(.iram)
. = ALIGN(4);
__data2_end__ = .;
} > IRAM
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > DRAM
/**
* Secondary bss section, optional
*
* Remember to add each additional bss section
* to the .zero.table above to asure proper
* initialization during startup.
*/
/*
.bss2 :
{
. = ALIGN(4);
__bss2_start__ = .;
*(.bss2)
*(.bss2.*)
. = ALIGN(4);
__bss2_end__ = .;
} > RAM2
*/
.heap :
{
. = ALIGN(4);
__end__ = .;
PROVIDE(end = .);
. = . + __HEAP_SIZE;
. = ALIGN(4);
__HeapLimit = .;
} > DRAM
.stack :
{
. = ORIGIN(DRAM) + LENGTH(DRAM) - __STACK_SIZE;
. = ALIGN(4);
__StackLimit = .;
. = . + __STACK_SIZE;
. = ALIGN(4);
__StackTop = .;
} > DRAM
PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
}
I think your problem might be that you need both the declaration and the definition to have the attribute. If I read your code right, you only put it in the .h file (not the .c)?
Thanks, the original issue was solved by reducing the optimisation level. Iām now stuck with understanding how to reduce the binary size after my linker script changes.
The first line is setting the cursor to the end of the previous placed section, so the binary ends up with a very high address for the LMA. I think you want the AT expression to point to the end of the LMA for the .data section.
Thanks. Yeah, I solved it in the end after some help on the Slack channel. I ended up using __etext to define the end of the text section and then the second .data2 section was started at __etext + SIZEOF(.data).
I had assumed that the syntax of AT() would take care of that for you. Iām still not clear on how it works as the .bss section that comes after doesnāt have any special treatment and ends up in the right place.