┬ÁTasker Forum

┬ÁTasker Forum => NXPTM M522XX, KINETIS and i.MX RT => Topic started by: AlexS on May 30, 2018, 12:13:03 PM

Title: Undefined reference to _sbrk
Post by: AlexS on May 30, 2018, 12:13:03 PM

Been working to port the original project (based on Processor Expert and CodeWarrior) to uTasker and MCUXpresso. Things are going quite smoothly, support is great, but, as some parts of my code use dynamic memory allocation, ran into an 'undefined reference _sbrk' linker error. Did some digging and found the reason to be the lack of libcr_c.a and libcr_eabihelpers.a, which, as far as I can work out, are archives with Redlib implementations for these functions.

The new linker error is an undefined reference to _pvHeapStart which I can easily sort by defining those symbols in the linker file, but it somehow doesn't feel right.


Title: Re: Undefined reference to _sbrk
Post by: mark on May 30, 2018, 11:49:37 PM
Hi Alex

I'll start by explaining the concept of dynamic memory in the uTasker project:
- Basically its use is avoided due to the fact that there are potential dangers with fragmentation and dynamic memory utilisation is considered as inappropriate in (small) embedded systems. Dynamic memory utilisation is typically not allowed in safety critical systems.
- The project uses uMalloc() which essentially allows "static" memory allocation at run time, which has some advantages over compile time static memory allocation but no management overhead. uMallocAlign() is about the same but ensures alignment and is very practical for driver code which requires such objects to be aligned to boundaries suiting the HW (eg. Ethernet or USB buffer descriptors). Both always give zeroed memory.
- Here is an overview of uMalloc() memory location in memory: http://www.utasker.com/forum/index.php?topic=96.msg384#msg384
- Recently uCalloc() was added which is a real dynamic memory (with uCFree()) implementation, whereby the heap used by it is actually a static allocation with uMalloc(), thus occupying also the uMalloc() heap area. This was added as an alternative to library malloc()/calloc()/free() so that memory use can be accurately monitored when the technique is absolutely necessary, as well as keeping the implementation fully integrated (see further points about this later). This was in specifically added due to the fact that mbedTLS (used for MQTTS) makes extensive use of calloc() and it wouldn't be feasibly to modify mbedTLS to achieve a static method (which I think WolfSSL can do). A TLS handshake based on mbedTLS uses a mind-boggling >20'000 calloc()/free() calls during the key exchange!!
- malloc() is also generally delivered by the libraries available but how they operate and how they organise the memory is not necessarily the same. Library malloc() is thus a potential source or portability issues.

To your issues:
- it has been noticed that using some functions such as sprintf() causes an issue with _sbrk() (or other similar functions), and sometimes a problem with a section overlap "section .ARM.exidx loaded at [00000000,00000007] overlaps" [with GCC] {http://www.utasker.com/forum/index.php?topic=1923.msg7057#msg7057}
- _sbrk() seems to be due to some such library functions using malloc(), which in return requires the HW system to deliver this routine. I understand that it is needed when there is not enough memory so that malloc()'s memory pool can be extended, which may be possible in systems with virtual memory or Windows or Linux. The solution to this has been to add a dummy _sbrk() routine anywhere in the code. Putting a break point in this would show whether it is every actually called, which I never saw happening to date.
To solve the .ARM.exidx issue a section has been added to some GCC linker scripts which gives it its own section so that it then doesn't overlap with code. This is understood to be something to do with C++ library code which, for some reason, wants to be at the address 0 if no section is found in the linker script.
- Since different libraries may be used and also the library versions change over time such issues can come and go, which is also why libraries are avoided if possible. In some cases the inclusion of a single library routine causes many other such library routines to be linked in and code bloat occurs.
- In your case _pvHeapStart is probably a pointer that you need to deliver to the area of memory that your library heap can use (there may also be a size setting or it may use all available SRAM above that address). Therefore it will be necessary to know some details about the malloc() implementation so that you can ensure that there are no overall memory utilisation conflicts; eg. you could have a static array for malloc() use and set this to its start address. Or you could use uMalloc() to allocate a block of memory and set its address to _pvHeapStart. You will however need to be sure that the malloc() function understands its bounds (size) as well as its are address!

I don't know whether this allows you to be able to solve the issue but it may give pointers as to where to start looking. The uTasker memory utilisation should be clear and you really just need to ensure that the library has an area that it can use without conflicts. Once you know what the library wants (how it operates) it should be easy to achieve.

Good luck



Title: Re: Undefined reference to _sbrk
Post by: AlexS on June 01, 2018, 01:00:27 PM
Hi Mark,

Thanks for the reply. As mentioned privately, I've got it running without too much hassle just by defining those variables at the start and end of the heap in the linker file. Plan is that, by the end of this development run, to move the entire project to statically allocated memory anyway.

Title: Re: Undefined reference to _sbrk
Post by: mark on June 04, 2018, 09:24:12 PM
Barr Group's discussion of dynamic memory in embedded systems: