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
sbrk()
is called, the argument passed has either not been initialized (and contains a randomly large value, or intentionally passed as a very large value. Is this something you have checked, or have I got it wrong. – ryyker