cancel
Showing results for 
Search instead for 
Did you mean: 

Using malloc

per2399
Associate II
Posted on March 18, 2015 at 09:04

Hi

I have a bit of a problem when using malloc so I was wondering what others think about this. I use malloc in my application, mainly because the application is entirely asynchronous so either I have to use malloc or I need buffers of my datatypes declared in masses. I chose malloc due to its flexibility.

I was using Atollic TrueStudio and everything built just fine, but now I wanted to try my hand with basic Eclipse and the following toolchain: https://launchpad.net/gcc-arm-embedded

Once I made this switch I was struck with undefined reference to `_sbrk'. Fair enough since I use malloc so I look around and find a newlib.c with some basic functions for read and write (using UART) and also an _sbrk implementation.

caddr_t _sbrk(int incr) {

    extern char _ebss; // Defined by the linker

    static char *heap_end;

    char *prev_heap_end;

    if (heap_end == 0) {

        heap_end = &_ebss;

    }

    prev_heap_end = heap_end;

    char * stack = (char*) __get_MSP();

    if (heap_end + incr >  stack)

    {

        _write (STDERR_FILENO, ''Heap and stack collision\n'', 25);

        errno = ENOMEM;

        return  (caddr_t) -1;

     }

    heap_end += incr;

    return (caddr_t) prev_heap_end;

}

The problem is that __get_MSP is deprecated as far as google could tell me. So if you aren't allowed to read the stack pointer value, how can you detect a stack collision?

So my questions are many:

Can I link with another library to get malloc to work or maybe even just a linker flag?

Is it possible to get the stack pointer value or should I instead create a large buffer in memory and let it be the borders form _sbrk?

Should I use another toolchain?

Is there some other solution or angle I am not seeing?

So feel free to point out anything I am open to any idea or solution.

Many thanks in advance,

Per Smitt

 

#stack-pointers
3 REPLIES 3
jpeacock
Associate II
Posted on March 18, 2015 at 13:17

One immediate problem in your sbrk code is that it assumes the heap and stack are contiguous.  Depending on what STM32 you are using there can be as many as four separate RAM regions.  On an STM32F4 I assign the heap and task stacks (allocated from heap) to CCM and system stack at the end of SRAM2.  There is intervening SRAM at fixed addresses (SRAM1 for DMA buffers, lower SRAM2 for globals).  And with FreeRTOS task stack space is inside the heap, your sbrk would fail every time.

The other immediate problem is which SP to check.  A Cortex M has two stack pointers, PSP for user tasks and MSP for system and interrupts.  Are you using both?  Most RTOSes will use PSP for tasks and MSP for interrupt and startup.

You need to look at your link map to see where heap and stack are placed, and if multi-tasking where the task stacks are allocated.  Then your sbrk needs to determine context to decide which SP to check and where the boundaries are.  Assuming heap and stack are contiguous in an embedded design isn't a good idea.

  Jack Peacock

Posted on March 18, 2015 at 14:05

Other systems do a large uninitialized static allocation for both the heap and stack, so both have known bounds. The linker can fix symbolic links, and the allocator knows which region(s) belong to it.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
per2399
Associate II
Posted on March 18, 2015 at 15:04

Thanks for the replies.

I am using a STM32L152 without any RTOS. The application is in itself rather easy so I felt an RTOS was rather overkill. So in my case it would be the MSP I would look at, but I understand I should stay away from looking at the stack pointer.

I made a simple solution which works as far as I can tell:

#define HUGE_MEMORY_SIZE (18000)

static char huge_memory[HUGE_MEMORY_SIZE];

caddr_t _sbrk(int incr) {

    static char *heap_end;

    char *prev_heap_end;

    if (heap_end == 0) {

    heap_end = huge_memory;

    }

    prev_heap_end = heap_end;

    if (heap_end + incr > huge_memory + HUGE_MEMORY_SIZE)

    {

        errno = ENOMEM;

        return  (caddr_t) -1;

    }

    heap_end += incr;

    return (caddr_t) prev_heap_end;

}

If I understand you correctly Clive, this is similar to your suggestion. According to your suggestion I should have made the limits in the linker scripts and used extern symbols to get those in _sbrk.

Jack, do you see something fatal in what I have done that I haven't noticed right now but will shoot me in the foot in 6 months time?

Best regards,

Per Smitt