How to add heap memory in linker file - c

Hi I am working on RiscV Ibex core recently and due to shortage of memory on my FPGA I have to use dynamic memory allocation (malloc() and free()) in my C code. But I should first define heap memory in linker file so that I can use this functions. Does anyone know how can I do that? Or is there anyway of using this functions with defined stack memory of Ibex core?
Here is the linker file for Ibex:
OUTPUT_ARCH(riscv)
/* required to correctly link newlib */
GROUP( -lc -lgloss -lgcc -lsupc++ )
SEARCH_DIR(.)
__DYNAMIC = 0;
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 0x36800 /* 218 kB */
stack : ORIGIN = 0x00036800, LENGTH = 0x4F000 /* 316 kB */
}
/* Stack information variables */
_min_stack = 0x2000; /* 8K - minimum stack space to reserve */
_stack_len = LENGTH(stack);
_stack_start = ORIGIN(stack) + LENGTH(stack);
/* We have to align each sector to word boundaries as our current s19->slm
* conversion scripts are not able to handle non-word aligned sections. */
SECTIONS
{
.vectors :
{
. = ALIGN(4);
KEEP(*(.vectors))
} > rom
.text : {
. = ALIGN(4);
_stext = .;
*(.text)
*(.text.*)
_etext = .;
__CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
*(.ctors)
LONG(0)
__CTOR_END__ = .;
__DTOR_LIST__ = .;
LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
*(.dtors)
LONG(0)
__DTOR_END__ = .;
*(.lit)
*(.shdata)
. = ALIGN(4);
_endtext = .;
} > rom
.rodata : {
. = ALIGN(4);
*(.rodata);
*(.rodata.*)
} > rom
.shbss :
{
. = ALIGN(4);
*(.shbss)
} > rom
.data : {
. = ALIGN(4);
sdata = .;
_sdata = .;
*(.data);
*(.data.*)
edata = .;
_edata = .;
} > rom
.bss :
{
. = ALIGN(4);
_bss_start = .;
*(.bss)
*(.bss.*)
*(.sbss)
*(.sbss.*)
*(COMMON)
_bss_end = .;
} > rom
/* ensure there is enough room for stack */
.stack (NOLOAD): {
. = ALIGN(4);
. = . + _min_stack ;
. = ALIGN(4);
stack = . ;
_stack = . ;
} > stack
.stab 0 (NOLOAD) :
{
[ .stab ]
}
.stabstr 0 (NOLOAD) :
{
[ .stabstr ]
}
}

Related

GCC Posistion independent code: Variables are not loaded correctly

The Program works fine as a stand alone on CC2650 (M3). But it shall be used also as a firmware which is loaded over the radio channel. For this purpose the position independent code is needed. The problem is, all of the variables defined as described below are not set.
uint32_t u32Timer_g = 2000;
static DeviceInterfaceStructure_t suInterfaceStructure_g =
{
.timeOut = 0,
.state = STATE_IDLE,
.lastState = STATE_IDLE,
.Config.reconnect = 0,
.Config.lVersion = 0x01,
};
The Program is compiled with GCC (gcc-arm-none-eabi-7-2018-q2-update) using the following flags:
--asm
-fPIE
-pie
-fno-strict-aliasing
-fdata-sections
-ffunction-sections
-fno-exceptions
and using the following linker script
ENTRY( ResetISR )
MEMORY
{
CRC (RX) : ORIGIN = 0x00001000, LENGTH = 0x00000004
OHD (RX) : ORIGIN = 0x00001004, LENGTH = 0x0000000C
INT_VEC (RX) : ORIGIN = 0x00001010, LENGTH = 0x000000C8
FWU_DESCR (RX) : ORIGIN = 0x000010D8, LENGTH = 0x00000040
APP_DESCR (RX) : ORIGIN = 0x00001118, LENGTH = 0x00000040
FLASH (RX) : ORIGIN = 0x00001158, LENGTH = 0x0000AF2F
SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x00005000
/* Application can use GPRAM region as RAM if cache is disabled in the CCFG
(DEFAULT_CCFG_SIZE_AND_DIS_FLAGS.SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM = 0) */
GPRAM (RWX) : ORIGIN = 0x11000000, LENGTH = 0x2000
}
/*. Generate a link error if heap and stack don’t fit into RAM .*/
_Min_Heap_Size = 0x800;
_Min_Stack_Size = 0x800;
/*. Highest address of the stack. Used in startup file .*/
_estack = ORIGIN(SRAM) + LENGTH(SRAM); /*end of SRAM .*/
REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_BSS", SRAM);
REGION_ALIAS("REGION_DATA", SRAM);
REGION_ALIAS("REGION_STACK", SRAM);
REGION_ALIAS("REGION_HEAP", SRAM);
REGION_ALIAS("REGION_ARM_EXIDX", FLASH);
REGION_ALIAS("REGION_ARM_EXTAB", FLASH);
/* Section allocation in memory */
SECTIONS
{
.SHADOW_CRC :
{
KEEP(*(.SHADOW_CRC))
} > CRC = 0xFF
.IMAGE_HEADER :
{
KEEP(*(.IMAGE_HEADER))
} > OHD = 0xFF
.intvec :
{
KEEP(*(.vectors))
} > INT_VEC = 0xFF
.firmwareDescr :
{
KEEP(*(.firmwareDescr))
} > FWU_DESCR = 0xFF
.applicationDescr :
{
KEEP(*(.applicationDescr))
} > APP_DESCR = 0xFF
.text :
{
_text = .;
*(.text*)
*(.rodata)
*(.rodata*)
*(.init)
*(.fini*)
*(.eh_frame*)
_etext = .;
} > FLASH = 0xFF
.ARM.exidx :
{
__exidx_start = .;
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
__exidx_end = .;
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
.data :
{
_data = .;
*(vtable)
*(.data)
*(.data*)
_edata = .;
*(.got)
*(.got*)
*(.igot*)
} > SRAM AT > FLASH
_ldata = LOADADDR(.data);
.bss :
{
__bss_start__ = .;
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
__bss_end__ = .;
} > SRAM
/* User_heap_stack section, used to check that there is enough SRAM left */
._user_heap_stack :
{
__heap_start__ = .;
end = __heap_start__;
_end = end;
__end = end;
KEEP(*(.heap))
__heap_end__ = .;
__HeapLimit = __heap_end__;
. = . + _Min_Stack_Size;
} > SRAM
.gpram :
{
} > GPRAM
}
The question is: What I'm doing wrong???
Update
The initialisation and realocation:
//*****************************************************************************
void
ResetISR(void)
{
uint32_t *pui32Src, *pui32Dest;
//
// CC26xx PG1 workaround: Check backdoor when coming from POR
//
EnableAndCheckBackdoor();
//
// Final trim of device
//
trimDevice();
//
// Copy the data segment initializers from flash to SRAM.
//
pui32Src = &_etext;
for(pui32Dest = &_data; pui32Dest < &_edata; )
{
*pui32Dest++ = *pui32Src++;
}
//
// Zero fill the bss segment.
//
__asm(" ldr r0, =_bss\n"
" ldr r1, =_ebss\n"
" mov r2, #0\n"
" .thumb_func\n"
"zero_loop:\n"
" cmp r0, r1\n"
" it lt\n"
" strlt r2, [r0], #4\n"
" blt zero_loop");
//
// Call the application's entry point.
//
main();
//
// If we ever return signal Error
//
FaultISR();
}
Even though you compiled your code position independent, your linker script makes it not-that-way. Your data relocation loop uses flash addresses to do the data copy:
pui32Src = &_etext;
You need to modify that to handle the OTA case and copy the initialized data over from wherever it is in RAM.

Erasing and writing into flash gives an error while building

I am writing a program in C for NXP freescale kinetis microcontroller KEA128. I modified the linker description file and proceeded to write a simple C program in C. But when I build the project, it gives the following error message
build\src\flash.o:(.rodata.flashLocat+0x0): multiple definition of `flashLocat'
build\src\main.o:(.rodata.flashLocat+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
Here I am attaching my C program file and main file that calls the functions for erasing and writing into the flash and my linker description file. Following is my flash.c and flash.h files
#include "flash.h"
int flashEraseSector(long int locat)
{
int temp1,temp2,temp3;
temp1 = (locat << 8);
temp1 = temp1 >> 24;
temp2 = (locat << 16);
temp2 = temp2 >> 24;
temp3 = (locat << 24);
temp3 = temp3 >> 24;
while(((FTMRE_FSTAT)&(1UL << 7))==0x00);
if(!((FTMRE_FSTAT)==0x80))
{FTMRE_FSTAT = 0x30;}
int IX = 0;
FTMRE_FCCOBIX = temp1;
IX = 1;
FTMRE_FCCOBIX = temp2;
IX = 2;
FTMRE_FCCOBIX = temp3;
IX = 3;
FTMRE_FCCOBIX = 0x0A; //erase a sector
FTMRE_FSTAT = 0x80;
while(((FTMRE_FSTAT)&(1UL << 7))==0x00);
return 1;
}
/*------------------------------------------------------------------------------
Write a long word to an erased flash block
*------------------------------------------------------------------------------*/
int flashWriteLongWord(long int locat,long int value)
{
int temp1,temp2,temp3,temp4,temp5,temp6,temp7;
temp1 = (locat << 8);
temp1 = temp1 >> 24;
temp2 = (locat << 16);
temp2 = temp2 >> 24;
temp3 = (locat << 24);
temp3 = temp3 >> 24;
temp4 = value >> 24;
temp5 = (value << 8);
temp5 = temp5 >> 24;
temp6 = (value << 16);
temp6 = temp6 >> 24;
temp7 = (value << 24);
temp7 = temp7 >> 24;
while(((FTMRE_FSTAT)&(1UL << 7))==0x00);
if(!((FTMRE_FSTAT)==0x80))
{FTMRE_FSTAT = 0x30;}
int IX = 0;
FTMRE_FCCOBIX = 0x06; //0x06 is instruction code for write long word.
IX = 1;
FTMRE_FCCOBIX = temp1;
IX = 2;
FTMRE_FCCOBIX = temp2;
IX = 3;
FTMRE_FCCOBIX = temp3;
IX = 4;
FTMRE_FCCOBIX = temp4;
IX = 5;
FTMRE_FCCOBIX = temp5;
IX = 6;
FTMRE_FCCOBIX = temp6;
IX = 7;
FTMRE_FCCOBIX = temp7;
FTMRE_FSTAT = 0x80;
while(((FTMRE_FSTAT)&(1UL << 7))==0x00);
return 1;
}
Here is my flash.h file
#ifndef SRC_FLASH_H_
#define SRC_FLASH_H_
#include "derivative.h" /* include peripheral declarations */
const long int flashLocat = 0x00000800;
int flashEraseSector(long int locat);
int flashWriteLongWord(long int locat,long int value);
#endif /* SRC_FLASH_H_ */
Here is my main file
int main(void)
{
long int value;
uint8_t flashStatus;
value = 2147483648;
NVIC_ISER |= ((unsigned int)0x1<<22); // Interrupt Set-Enable Register, IRQ22 (PIT_CH0)
PIT_TFLG0 = 0x1; // clear TIF
PIT_TCTRL0 = 0x03; // CHN = 0 -> not chained, TIE = 1 -> interrupt enabled, TEN = 1 -> timer enabled
CpuComm_Init();
flashStatus = flashEraseSector(flashLocat);
flashWriteLongWord(flashLocat,value);
for(;;)
{
}
return 0;
}
Here is my linker description file:
/*
**
** File : KEAZ128M4_flash.ld
**
** Default linker command file for Flash targets
**
*****************************************************************************
*/
/* Entry Point */
/*ENTRY(__init_hardware)*/
ENTRY(RESET_handler)
/* Highest address of the user mode stack */
_estack = 0x20003000; /* end of SRAM */
__SP_INIT = _estack;
/* Generate a link error if heap and stack don't fit into RAM */
/*__heap_size = 0x100; */ /* required amount of heap is 256 Bytes */
/*__stack_size = 0x100; */ /* required amount of stack is 256 Bytes*/
/* Specify the memory areas */
MEMORY
{
m_interrupts (rx) : ORIGIN = 0x00000000, LENGTH = 0xC0 /*192 Bytes*/
m_cfmprotrom (rx) : ORIGIN = 0x00000400, LENGTH = 0x10 /*16 Bytes*/
m_text (rx) : ORIGIN = 0x00000800, LENGTH = 128K - 0x800
/*reserving the last 2KB of flash by subtracting those bytes (0x800) from m_text segment*/
m_data (rwx) : ORIGIN = 0x1FFFF000, LENGTH = 16K /* SRAM */
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into Flash */
/*'.' means the location coounter, at the start of SECTIONS
* command the location counter is set to the value '0'
*/
.interrupts :
{
__vector_table = .;
. = ALIGN(4);
KEEP(*(.vectortable)) /* Startup code */
. = ALIGN(4);
} > m_interrupts
/* Above lines of code mean an output section '.interrupts'
* has input sections called vector_table and *(.vectortable)
* means all '.vectortable' input sections in all input files.
*/
.cfmprotect :
{
. = ALIGN(4);
KEEP(*(.cfmconfig)) /* Flash Configuration Field (FCF) */
. = ALIGN(4);
} > m_cfmprotrom
/* The program code and other data goes into Flash */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} > m_text
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > m_text
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} > m_text
.ctors :
{
__CTOR_LIST__ = .;
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
/* We don't want to include the .ctor section from
from the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
} > m_text
.dtors :
{
__DTOR_LIST__ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
} > m_text
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} > m_text
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} > m_text
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
___ROM_AT = .;
} > m_text
/* reserve MTB memory at the beginning of m_data */
.mtb : /* MTB buffer address as defined by the hardware */
{
. = ALIGN(8);
_mtb_start = .;
KEEP(*(.mtb_buf)) /* need to KEEP Micro Trace Buffer as not referenced by application */
. = ALIGN(8);
_mtb_end = .;
} > m_data
/* Initialized data sections goes into RAM, load LMA copy after code */
__stacktop = ORIGIN(m_data) + LENGTH(m_data);
__data_load = LOADADDR(.data);
. = ORIGIN(m_data);
.data : AT(___ROM_AT)
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} > m_data
___data_size = _edata - _sdata;
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
__START_BSS = .;
PROVIDE ( __bss_start__ = __START_BSS );
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__END_BSS = .;
PROVIDE ( __bss_end__ = __END_BSS );
} > m_data
_romp_at = ___ROM_AT + SIZEOF(.data);
.romp : AT(_romp_at)
{
__S_romp = _romp_at;
LONG(___ROM_AT);
LONG(_sdata);
LONG(___data_size);
LONG(0);
LONG(0);
LONG(0);
} > m_data
/* User_heap_stack section, used to check that there is enough RAM left */
/* ._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
__heap_addr = .;
. = . + __heap_size;
. = . + __stack_size;
. = ALIGN(4);
} > m_data
*/
.ARM.attributes 0 : { *(.ARM.attributes) }
}
In the header file you should declare the constant:
extern const long int flashLocat;
Then in one single source file, in the global scope outside of any function, you define the constant:
const long int flashLocat = 0x00000800;
Since you include flash.h in both flash.c and main.c, the variable flashLocat is defined twice. That's why you are getting an error.

linker script error invalid syntax error

linker script throwing error but i think there is no
the code casing error is:
SECTIONS
{
ENTRY(_entry)
/DISCARD/ : {
*(.note*);
*(.iplt*);
*(.igot*);
*(.rel*);
*(.comment);
*(.eh_frame);
}
. = 0x600;
.tls : {
_tls = .;
. += 0x80;
_tls_end = .;
_tls_size = _tls_end - _tls;
_tls_stack_limit = _tls + 0x30;
}
.bss : {
_bss = .;
*(.bss);
_bss_end = .;
_bss_size = _bss_end - _bss;
}
. = 0x5000;
.stack : {
_stack = .;
. += 0x4000;
_stack_end = .;
# Non-Rust functions use stack space but do not check the stack. For
# their sake, set Rust's checked stack limit somewhat above the true
# limit.
_stack_rust_limit = _stack + 0x1000;
}
. = 0x9000;
.image16 : {
*(.text16);
*(.data16);
}
.image : {
*(.text);
*(.text.*);
*(.rodata);
*(.rodata.*);
*(.data);
*(.data.*);
*(.got);
*(.got.*);
}
. = 0xc800;
.stage2 : {
_stage2 = .;
_stage2_segment = . >> 4;
_stage2_reloc = 0x5000; # Address to copy stage2 to.
_stage2_reloc_segment = _stage2_reloc >> 4;
. += 0x73000;
_stage2_end = .;
_stage2_size = _stage2_end - _stage2;
_stage2_para_size = _stage2_size >> 4;
# When stage2 is moved, the src and dest regions overlap. If the dest
# were greater than the src, the move direction would need to change.
ASSERT(_stage2_reloc <= _stage2 - 16, "stage2");
}
. = 0x7ff80;
# This section reserves memory for the routine that transfers control to
# stage2 That routine will move stage2 into place and potentially
# overwrite parts of stage1.
.transfer_code : {
_transfer_code_segment = . >> 4;
. += 0x80;
}
}
the errors is:
ld:src/stage1/stage1.ld:82: syntax error
i user cross compiler ld for linking and even normal gives the same error

Cortex-M3 Linking _sidata located incorrectly

I'm in the process of changing compiler from the Codesourcery Codebench Lite for ARM EABI gcc (v4.7.2) to the arm GCC 2014 q1 (v4.8.3) and am having an issue with the location of certain memory addresses defined in the linker file for my program. The chip is the STM32F103RBT6.
The Reset handler function is the first function called and is attempting to copy the data segment initialisers from flash to SRAM. The following code is executed:
void Reset_Handler(void)
{
unsigned long *pulSrc, *pulDest;
//
// Copy the data segment initializers from flash to SRAM.
//
pulSrc = &_sidata;
for(pulDest = &_sdata; pulDest < &_edata; )
{
*(pulDest++) = *(pulSrc++);
}
//
// Zero fill the bss segment.
//
for(pulDest = &_sbss; pulDest < &_ebss; )
{
*(pulDest++) = 0;
}
__libc_init_array();
//
// Call the application's entry point.
//
main();
}
Memory definitions are as follows:
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K /* also change _estack below */
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
The _sidata value on the original (working) version of the program is defined as 0x8008400 but this value changes when I compile using the new compiler with the same linker script. The device is hard faulting because of this issue. I can hard code the values into the reset handler and the code executes fine so it's just an issue with these sections as far as I can tell. How can I ensure that these addresses are correct and why are they changing even though the linker script hasn't been changed?
stm32.ld:
/*
Linker script for STM32F10x
Copyright RAISONANCE 2007 (modified by Lanchon 1-Feb-2008)
You can use, copy and distribute this file freely, but without any waranty.
Configure memory sizes, end of stack and boot mode for your project here.
*/
/* include the common STM32F10x sub-script */
INCLUDE "STM32_COMMON.ld"
/* Memory Spaces Definitions */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K /* also change _estack below */
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
/* highest address of the user mode stack */
_estack = 0x20005000;
/* include the section management sub-script */
/* (either "STM32_SEC_FLASH.ld" or "STM32_SEC_RAM.ld") */
INCLUDE "STM32_SEC_FLASH.ld"
STM32_COMMON.ld:
/*
Common part of the linker scripts for STR32 devices
Copyright RAISONANCE 2007
You can use, modify and distribute thisfile freely, but without any waranty.
*/
/* default stack sizes.
These are used by the startup in order to allocate stacks for the different modes.
*/
__Stack_Size = 2048 ;
PROVIDE ( _Stack_Size = __Stack_Size ) ;
__Stack_Init = _estack - __Stack_Size ;
/*"PROVIDE" allows to easily override these values from an object file or the commmand line.*/
PROVIDE ( _Stack_Init = __Stack_Init ) ;
/*
There will be a link error if there is not this amount of RAM free at the end.
*/
_Minimum_Stack_Size = 0x800 ;
/*
this sends all unreferenced IRQHandlers to reset
*/
PROVIDE ( Undefined_Handler = 0 ) ;
PROVIDE ( SWI_Handler = 0 ) ;
PROVIDE ( IRQ_Handler = 0 ) ;
PROVIDE ( Prefetch_Handler = 0 ) ;
PROVIDE ( Abort_Handler = 0 ) ;
PROVIDE ( FIQ_Handler = 0 ) ;
PROVIDE ( NMIException = 0 ) ;
PROVIDE ( HardFaultException = 0 ) ;
PROVIDE ( MemManageException = 0 ) ;
PROVIDE ( BusFaultException = 0 ) ;
PROVIDE ( UsageFaultException = 0 ) ;
/* PROVIDE ( SVCHandler = 0 ) ; */
PROVIDE ( DebugMonitor = 0 ) ;
/* PROVIDE ( PendSVC = 0 ) ; */
/* PROVIDE ( SysTickHandler = 0 ) ; */
PROVIDE ( WWDG_IRQHandler = 0 ) ;
PROVIDE ( PVD_IRQHandler = 0 ) ;
PROVIDE ( TAMPER_IRQHandler = 0 ) ;
PROVIDE ( RTC_IRQHandler = 0 ) ;
PROVIDE ( FLASH_IRQHandler = 0 ) ;
PROVIDE ( RCC_IRQHandler = 0 ) ;
PROVIDE ( EXTI0_IRQHandler = 0 ) ;
PROVIDE ( EXTI1_IRQHandler = 0 ) ;
PROVIDE ( EXTI2_IRQHandler = 0 ) ;
PROVIDE ( EXTI3_IRQHandler = 0 ) ;
PROVIDE ( EXTI4_IRQHandler = 0 ) ;
PROVIDE ( DMAChannel1_IRQHandler = 0 ) ;
PROVIDE ( DMAChannel2_IRQHandler = 0 ) ;
PROVIDE ( DMAChannel3_IRQHandler = 0 ) ;
PROVIDE ( DMAChannel4_IRQHandler = 0 ) ;
PROVIDE ( DMAChannel5_IRQHandler = 0 ) ;
PROVIDE ( DMAChannel6_IRQHandler = 0 ) ;
PROVIDE ( DMAChannel7_IRQHandler = 0 ) ;
PROVIDE ( ADC_IRQHandler = 0 ) ;
PROVIDE ( USB_HP_CAN_TX_IRQHandler = 0 ) ;
PROVIDE ( USB_LP_CAN_RX0_IRQHandler = 0 ) ;
PROVIDE ( CAN_RX1_IRQHandler = 0 ) ;
PROVIDE ( CAN_SCE_IRQHandler = 0 ) ;
PROVIDE ( EXTI9_5_IRQHandler = 0 ) ;
PROVIDE ( TIM1_BRK_IRQHandler = 0 ) ;
PROVIDE ( TIM1_UP_IRQHandler = 0 ) ;
PROVIDE ( TIM1_TRG_COM_IRQHandler = 0 ) ;
PROVIDE ( TIM1_CC_IRQHandler = 0 ) ;
PROVIDE ( TIM2_IRQHandler = 0 ) ;
PROVIDE ( TIM3_IRQHandler = 0 ) ;
PROVIDE ( TIM4_IRQHandler = 0 ) ;
PROVIDE ( I2C1_EV_IRQHandler = 0 ) ;
PROVIDE ( I2C1_ER_IRQHandler = 0 ) ;
PROVIDE ( I2C2_EV_IRQHandler = 0 ) ;
PROVIDE ( I2C2_ER_IRQHandler = 0 ) ;
PROVIDE ( SPI1_IRQHandler = 0 ) ;
PROVIDE ( SPI2_IRQHandler = 0 ) ;
PROVIDE ( USART1_IRQHandler = 0 ) ;
PROVIDE ( USART2_IRQHandler = 0 ) ;
PROVIDE ( USART3_IRQHandler = 0 ) ;
PROVIDE ( EXTI15_10_IRQHandler = 0 ) ;
PROVIDE ( RTCAlarm_IRQHandler = 0 ) ;
PROVIDE ( USBWakeUp_IRQHandler = 0 ) ;
/******************************************************************************/
/* Peripheral memory map */
/******************************************************************************/
/*this allows to compile the ST lib in "non-debug" mode*/
/* Peripheral and SRAM base address in the alias region */
PERIPH_BB_BASE = 0x42000000;
SRAM_BB_BASE = 0x22000000;
/* Peripheral and SRAM base address in the bit-band region */
SRAM_BASE = 0x20000000;
PERIPH_BASE = 0x40000000;
/* Flash registers base address */
PROVIDE ( FLASH_BASE = 0x40022000);
/* Flash Option Bytes base address */
PROVIDE ( OB_BASE = 0x1FFFF800);
/* Peripheral memory map */
APB1PERIPH_BASE = PERIPH_BASE ;
APB2PERIPH_BASE = (PERIPH_BASE + 0x10000) ;
AHBPERIPH_BASE = (PERIPH_BASE + 0x20000) ;
PROVIDE ( TIM2 = (APB1PERIPH_BASE + 0x0000) ) ;
PROVIDE ( TIM3 = (APB1PERIPH_BASE + 0x0400) ) ;
PROVIDE ( TIM4 = (APB1PERIPH_BASE + 0x0800) ) ;
PROVIDE ( RTC = (APB1PERIPH_BASE + 0x2800) ) ;
PROVIDE ( WWDG = (APB1PERIPH_BASE + 0x2C00) ) ;
PROVIDE ( IWDG = (APB1PERIPH_BASE + 0x3000) ) ;
PROVIDE ( SPI2 = (APB1PERIPH_BASE + 0x3800) ) ;
PROVIDE ( USART2 = (APB1PERIPH_BASE + 0x4400) ) ;
PROVIDE ( USART3 = (APB1PERIPH_BASE + 0x4800) ) ;
PROVIDE ( I2C1 = (APB1PERIPH_BASE + 0x5400) ) ;
PROVIDE ( I2C2 = (APB1PERIPH_BASE + 0x5800) ) ;
PROVIDE ( CAN = (APB1PERIPH_BASE + 0x6400) ) ;
PROVIDE ( BKP = (APB1PERIPH_BASE + 0x6C00) ) ;
PROVIDE ( PWR = (APB1PERIPH_BASE + 0x7000) ) ;
PROVIDE ( AFIO = (APB2PERIPH_BASE + 0x0000) ) ;
PROVIDE ( EXTI = (APB2PERIPH_BASE + 0x0400) ) ;
PROVIDE ( GPIOA = (APB2PERIPH_BASE + 0x0800) ) ;
PROVIDE ( GPIOB = (APB2PERIPH_BASE + 0x0C00) ) ;
PROVIDE ( GPIOC = (APB2PERIPH_BASE + 0x1000) ) ;
PROVIDE ( GPIOD = (APB2PERIPH_BASE + 0x1400) ) ;
PROVIDE ( GPIOE = (APB2PERIPH_BASE + 0x1800) ) ;
PROVIDE ( ADC1 = (APB2PERIPH_BASE + 0x2400) ) ;
PROVIDE ( ADC2 = (APB2PERIPH_BASE + 0x2800) ) ;
PROVIDE ( TIM1 = (APB2PERIPH_BASE + 0x2C00) ) ;
PROVIDE ( SPI1 = (APB2PERIPH_BASE + 0x3000) ) ;
PROVIDE ( USART1 = (APB2PERIPH_BASE + 0x3800) ) ;
PROVIDE ( DMA = (AHBPERIPH_BASE + 0x0000) ) ;
PROVIDE ( DMA_Channel1 = (AHBPERIPH_BASE + 0x0008) ) ;
PROVIDE ( DMA_Channel2 = (AHBPERIPH_BASE + 0x001C) ) ;
PROVIDE ( DMA_Channel3 = (AHBPERIPH_BASE + 0x0030) ) ;
PROVIDE ( DMA_Channel4 = (AHBPERIPH_BASE + 0x0044) ) ;
PROVIDE ( DMA_Channel5 = (AHBPERIPH_BASE + 0x0058) ) ;
PROVIDE ( DMA_Channel6 = (AHBPERIPH_BASE + 0x006C) ) ;
PROVIDE ( DMA_Channel7 = (AHBPERIPH_BASE + 0x0080) ) ;
PROVIDE ( RCC = (AHBPERIPH_BASE + 0x1000) ) ;
/* System Control Space memory map */
SCS_BASE = 0xE000E000;
PROVIDE ( SysTick = (SCS_BASE + 0x0010) ) ;
PROVIDE ( NVIC = (SCS_BASE + 0x0100) ) ;
PROVIDE ( SCB = (SCS_BASE + 0x0D00) ) ;
STM32_SEC_FLASH.ld:
/*
Common part of the linker scripts for STR71x devices in FLASH mode
(that is, the FLASH is seen at 0)
Copyright RAISONANCE 2005
You can use, modify and distribute thisfile freely, but without any waranty.
*/
EXTERN(Reset_Handler)
ENTRY(Reset_Handler)
/* Sections Definitions */
SECTIONS
{
/* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* the program code is stored in the .text section, which goes to Flash */
.text :
{
*(.text .text.* .gnu.linkonce.t.*)
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.eh_frame_hdr)
*(.eh_frame)
*(.gcc_except_table)
*(.eh_frame_hdr)
*(.eh_frame)
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
_etext = .;
/* This is used by the startup in order to initialize the .data secion */
_sidata = _etext;
} >FLASH
/* .ARM.exidx is sorted, so has to go in its own output section. */
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
. = ALIGN(4);
__exidx_end = .;
.data :
{
_flash_data = LOADADDR(.data);
_data = .;
_sdata = .;
*(vtable)
*(.data .data.* .gnu.linkonce.d.*)
_edata = .;
} >RAM AT >FLASH
/* This is the uninitialized data section */
.bss :
{
_bss = .;
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .;
__bss_start__ = _sbss;
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
/* This is used by the startup in order to initialize the .bss secion */
_ebss = . ;
__bss_end__ = _ebss;
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
/* end of allocated ram _end */
/* This is the user stack section
This is just to check that there is enough RAM left for the User mode stack
It should generate an error if it's full.
*/
._usrstack :
{
. = ALIGN(4);
_susrstack = . ;
. = . + _Minimum_Stack_Size ;
. = ALIGN(4);
_eusrstack = . ;
} >RAM
}
I had a similar problem. For some reason, the linker doesn't set _sidata = _etext per what's in the linker script. Instead, the linker sets _sidata = _etext-2. This resulted in the _sidata value being on a half word boundary, which causes the CPU to end up in the Default_Handler().
In your linker script you show the following:
_etext = .;
/* This is used by the startup in order to initialize the .data secion */
_sidata = _etext;
To fix the problem, change it to the following so that _sidata is explicitly set to ".":
_etext = .;
/* This is used by the startup in order to initialize the .data secion */
_sidata = .;

Newlib fails to allocate heap on first call in ARM embedded system

I am using gcc-arm-none-eabi 4.9 2014q4 to write a bare-metal application for the Cortex-M4. When the application loads the first call to _sbrk appears to be invalid.
I have implemented _sbrk as follows:
extern unsigned int _start_of_heap;
extern unsigned int _end_of_heap;
caddr_t heap = (caddr_t)&_start_of_heap;
#include "hardware/uart.h"
// low level bulk memory allocator - used by malloc
caddr_t _sbrk ( int increment ) {
caddr_t prevHeap;
caddr_t nextHeap;
send_str("_sbrk(");
send_dec(increment);
send_str(")\n");
prevHeap = heap;
// Always return data aligned on a 8 byte boundary
nextHeap = (caddr_t)(((unsigned int)(heap + increment) + 7) & ~7);
// get current stack pointer
register caddr_t stackPtr asm ("sp");
send_str("\tstackPtr(");
send_hex((uint32_t)stackPtr);
send_str(")\n");
send_str("\tprevHeap(");
send_hex((uint32_t)prevHeap);
send_str(")\n");
// Check enough space and there is no collision with stack coming the other way
// if stack is above start of heap
if((nextHeap < stackPtr) && (nextHeap >= (caddr_t)&_start_of_heap) && (nextHeap < (caddr_t)&_end_of_heap)) {
heap = nextHeap;
return (caddr_t) prevHeap;
}
send_str("*\n");
return NULL; // error - no more memory
}
Linker defines the heap limits as follows:
MEMORY
{
SRAM_L (rwx) : ORIGIN = 0x00000000, LENGTH = 32K
SRAM_U (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
SECTIONS
{
.vectors 0x00000000 :
{
*o(.vectors_)
} >SRAM_L
.text :
{
. = ALIGN (4);
*(.text);
} >SRAM_L
. = . ;
_datai = . ;
.data :
{
. = ALIGN (4);
_data = . ; *(.data .data.*); _edata = . ;
} >SRAM_U AT >SRAM_L
.data_init :
{
_edatai = .;
} >SRAM_L
.bss :
{
. = ALIGN (4);
_bss = . ; *(.bss) *(COMMON); _ebss = . ;
} >SRAM_U
. = ALIGN (4);
. += 8;
free_memory_start = .;
_end_of_stack = .;
end = .;
_start_of_heap = .;
. = 0x20007000;
_start_of_stack = .;
_end_of_heap = .;
}
The program code runs a quick stack and heap test:
extern unsigned int _start_of_heap;
extern unsigned int _end_of_heap;
extern caddr_t heap;
void foo(uint8_t i)
{
unsigned long blah = 0;
unsigned long * halb;
halb = malloc(sizeof(unsigned long));
iprintf("blah(%08x) halb(%08x) heap(%08x)\n", &blah, halb, heap);
if(i)
foo(i - 1);
free(halb);
}
int main(int argc, char ** argv)
{
init_uart((void*)UART2_IPS_BASE_ADDR, 115200);
iprintf("Heap test (%08x - %08x)\n", &_start_of_heap, &_end_of_heap);
foo(10);
return 0;
}
The following output is produced:
_sbrk(1040965006) <----- Note large size
stackPtr(20006E18)
prevHeap(2000089C)
* <----- '*' indicates out of range
_sbrk(626)
stackPtr(20006E18)
prevHeap(2000089C)
Heap test (2000089c - 20007000)
blah(20006fb8) halb(00000410) heap(20000b10)
blah(20006fa0) halb(00000420) heap(20000b10)
blah(20006f88) halb(00000430) heap(20000b10)
blah(20006f70) halb(00000440) heap(20000b10)
blah(20006f58) halb(00000450) heap(20000b10)
blah(20006f40) halb(00000460) heap(20000b10)
blah(20006f28) halb(00000470) heap(20000b10)
blah(20006f10) halb(00000480) heap(20000b10)
blah(20006ef8) halb(00000490) heap(20000b10)
blah(20006ee0) halb(000004a0) heap(20000b10)
blah(20006ec8) halb(000004b0) heap(20000b10)
The first allocation is for 1040965006 bytes, this seems incorrect and it fails. After this i assume malloc proceeds to allocate 626 bytes. Every subsequent call to malloc for halb appears to return an address that is outside of the range of my stack. Does this first call look like an error, or should it be ignored and if so, what's up with the addresses returned by malloc?
Thanks,
Devan
It appears that some variables may have been improperly initialized. I have updated my linker script as follows:
SECTIONS
{
. = ORIGIN(SRAM_L);
.vectors :
{
KEEP(*o(.vectors_))
} >SRAM_L
.text :
{
. = ALIGN(4);
_start_text = .;
*(.text)
*(.text*)
*(.rodata)
*(.rodata*)
_end_text = .;
} >SRAM_L
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > SRAM_L
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > SRAM_L
__exidx_end = .;
_end_text = .;
. = . ;
_datai = . ;
.data :
{
. = ALIGN (4);
_data = . ;
*(.data)
*(.data*)
. = ALIGN (4);
_edata = . ;
} >SRAM_U AT >SRAM_L
.data_init :
{
_edatai = .;
} >SRAM_L
.bss :
{
. = ALIGN (4);
_bss = . ;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
} >SRAM_U
. = ALIGN (4);
. += 8;
free_memory_start = .;
_end_of_stack = .;
PROVIDE(end = .);
_start_of_heap = .;
. = 0x20007000;
_start_of_stack = .;
_end_of_heap = .;
}
Thanks to sushihangover blog post.
I have had problems with GNU Tools ARM Embedded arm-none-eabi 4.9 2015q1 and an _sbrk that worked well with CodeSourcery's arm-none-eabi 4.5.2. I thought I would try a newer version.
I then went and tried it with 4.7 2013q1 and 4.8 2014q1, the mallocs also give the negative value for the initial request to sbrk.
I had to adjust my _sbrk to ignore negative values in order for it to work properly with both versions of the compiler. please correct me if I'm wrong but I understand that _sbrk should not be called with negative values but only the re-entrant version _sbrk_r (For OSes) should work with negatives.
Here is my implementation, if anyone is interested
extern char __heap_start__; // defined by the linker script
extern char __heap_end__; // defined by the linker script
unsigned char * HeapSize;
unsigned char * _sbrk ( int incr )
{
unsigned char *prev_heap;
if (HeapSize == 0)
HeapSize = (unsigned char *)&__heap_start__; // initialize the Heap to the start
prev_heap = HeapSize; // store the start of this block of memmory
if(incr > 0)
{ // only allow increments to the heap allocation
// check that we don't run out of memory
// could try using the stack pointer to maximise memmory use
if(((unsigned long)HeapSize + incr) >= (unsigned long)&__heap_end__)
return (unsigned char *) -1; // out of memmory
HeapSize += incr; // increase the heap
}
return prev_heap; // return the start of the next block of memory
}

Resources