Hi all, I’m working with an LPC2148 and can’t seem to get malloc working. I’m using the latest codesourcery package to build the project. Everything works fine, except I can’t use malloc (not even 4 bytes). It’s a bare metal project, so you have to define your own versions of the system calls; which for malloc, is apparently _sbrk_r(). So, here’s what I have for that:
register char *stack_ptr asm ("sp");
caddr_t _sbrk_r(void *reent, size_t incr)
{
// Defined by the linker
extern char end asm ("end");
static char *heap_end = NULL;
char *prev_heap_end;
if(heap_end == NULL)
heap_end = &end;
prev_heap_end = heap_end;
if(( heap_end + incr ) > stack_ptr )
return (caddr_t) -1;
heap_end += incr;
return (caddr_t) prev_heap_end;
}
Now when I step through it in the debugger (using OpenOCD), it ends up hitting the line “return (caddr_t) -1;” which I assume is what’s causing malloc to fail. So my question is, what exactly does sbrk_r() do and is that check for (heap_end +inc) > stack_ptr correct? The stack grows downward (so the heap grows upward, right?), so it seems to me you would want to initialize heap_end to the very bottom of the stack. But instead, it’s being initialized to the top of the stack. Here’s my linker script:
/* Reset vector for linker. */
ENTRY(_boot)
/* Stack sizes for C run-time as well as interrupts, supervisor, abort
and undefined conditions. NOTE: This is the only place you have to
change the stack size information. The crt.s assembler uses these values
to set and clear the stack. */
C_STACK_SIZE = 0x1000;
IRQ_STACK_SIZE = 0x400;
FIQ_STACK_SIZE = 0x100;
SVC_STACK_SIZE = 0x100;
ABT_STACK_SIZE = 0x100;
UND_STACK_SIZE = 0x100;
MEMORY
{
flash (rx) : ORIGIN = 0x00000000, LENGTH = 512K
ram_isp_low(a) : ORIGIN = 0x40000120, LENGTH = 223
ram(rw) : ORIGIN = 0x40000000, LENGTH = 0x7f00
ram_isp_high(a) : ORIGIN = 0x40007FE0, LENGTH = 32
ram_usb_dma(rw) : ORIGIN = 0x7FD00000, LENGTH = 8192
}
SECTIONS
{
/* Interrupt vectors must start at memory 0x00000000. */
.crt :
{
. = ALIGN(4);
*crt.o (.text)
. = ALIGN(4);
} >flash
/* Code (text) that is written to flash. */
.text :
{
*(.text) /* all .text sections (code) */
*(.rodata) /* all .rodata sections (constants, strings, etc.) */
*(.rodata*)
*(.glue_7); /* ARM/Thumb inter-networking glue functions */
*(.glue_7t);
. = 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))
} >flash
. = ALIGN(4);
/* Location in flash to save initialized data segment. */
.etext :
{
. = ALIGN(4);
_etext = .;
} >flash
/* All initialized data that is copied to RAM in the crt.s assembler file. */
.data : AT (_etext)
{
. = ALIGN(4);
_data = .;
*(.data)
_edata = .;
} >ram
/* BSS (Block Started by Symbol) block is the unitilized data segment. */
.bss :
{
__bss_start = . ;
*(.bss)
. = ALIGN (4);
__bss_end = .;
} >ram
/* Stack allocation for the application and interrupts and exceptions. */
.stack :
{
. = ALIGN(0x100);
__stack_start = . ;
. += IRQ_STACK_SIZE;
. = ALIGN (4);
__irq_stack_top__ = . ;
. += FIQ_STACK_SIZE;
. = ALIGN (4);
__fiq_stack_top__ = . ;
. += SVC_STACK_SIZE;
. = ALIGN (4);
__svc_stack_top__ = . ;
. += ABT_STACK_SIZE;
. = ALIGN (4);
__abt_stack_top__ = . ;
. += UND_STACK_SIZE;
. = ALIGN (4);
__und_stack_top__ = . ;
. += C_STACK_SIZE;
. = ALIGN (4);
__c_stack_top__ = . ;
__stack_end = .;
} >ram
end = .;
}
…and the pertinent .map section:
.stack 0x40001080 0x2880 load address 0x00014760
0x40001100 . = ALIGN (0x100)
*fill* 0x40001080 0x80 00
0x40001100 __stack_start = .
0x40001500 . = (. + IRQ_STACK_SIZE)
*fill* 0x40001100 0x400 00
0x40001500 . = ALIGN (0x4)
0x40001500 __irq_stack_top__ = .
0x40001600 . = (. + FIQ_STACK_SIZE)
*fill* 0x40001500 0x100 00
0x40001600 . = ALIGN (0x4)
0x40001600 __fiq_stack_top__ = .
0x40001700 . = (. + SVC_STACK_SIZE)
*fill* 0x40001600 0x100 00
0x40001700 . = ALIGN (0x4)
0x40001700 __svc_stack_top__ = .
0x40001800 . = (. + ABT_STACK_SIZE)
*fill* 0x40001700 0x100 00
0x40001800 . = ALIGN (0x4)
0x40001800 __abt_stack_top__ = .
0x40001900 . = (. + UND_STACK_SIZE)
*fill* 0x40001800 0x100 00
0x40001900 . = ALIGN (0x4)
0x40001900 __und_stack_top__ = .
0x40003900 . = (. + C_STACK_SIZE)
*fill* 0x40001900 0x2000 00
0x40003900 . = ALIGN (0x4)
0x40003900 __c_stack_top__ = .
0x40003900 __stack_end = .
0x40003900 end = .
If I set a breakpoint inside the _sbrk_r() function and dump the top 0x100 of the stack (stack top is at 0x40003900, I get the following:
0x40003800: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x40003820: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x40003840: deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef deadbeef
0x40003860: deadbeef deadbeef deadbeef deadbeef deadbeef 8000005f 000109ac 0000002e
0x40003880: 00000020 40000010 4000090c 40003900 40000a06 0000b028 4000090c 00000000
0x400038a0: e01fc040 12345678 16a3cf85 00000050 fb3bf9b3 673deee7 9e5a3e6d 000021a0
0x400038c0: 4000090c 0000d838 0000bdec 400038e0 16a3cf85 0000c270 0000ffff 0000c2c0
0x400038e0: 40000f08 40000a1c 4000090c 00000000 00000000 00000000 12345678 0000011c
0x40003900: b27d4d80 511d7980 47bb5f7b 33917c26 9fd11be2 1859a4b6 bb2fb47d 1398b400
So clearly there’s plenty of space at the bottom of the .stack section to allocate from. The problem seems to be that heap_end is initialized to 0x40003900, which will almost certainly always be larger than the stack pointer… I must not understanding something. Any pointers would be greatly appreciated