0

I am seeking the implementation details of malloc() and free() in the arm-none-eabi-gcc source code. I have observed that malloc()/free() functions work on STM32 without an operating system and any additional implementation.

So that I want to understand how malloc works in arm-none-eabi-gcc on bare-metal systems. How is it implemented at the low level in the source code?

As far as my understanding goes, using malloc typically requires the implementation of functions like _sbrk_r or _malloc_r. However, in my case, it seems to work without explicitly implementing these functions.

I have examined several .c files such as malloc.c, mallocr.c, nano-mallocr.c, which I assume might be related to the malloc implementation in the gcc source directory. However, I haven't been able to confirm whether these functions in the files are indeed called by malloc() to implement allocating function.

4
  • Have a look into your linker generated map file. There you see from which source malloc is linked into your application and which malloc implementation files are used, too. Commented Jan 17, 2024 at 5:21
  • Thanks for your answer! I realized it was my misinterpretation while reading "mallocr.c". "mallocr.c" implements malloc, free, and other functions defined in malloc.h. Commented Jan 17, 2024 at 7:11
  • On the same topic: Why should I not use dynamic memory allocation in embedded systems? One of the numerous problems mentioned is that the heap is implemented as a fixed size segment, meaning no matter the implementation it will waste memory compared to allocating everything as fixed size. Commented Jan 17, 2024 at 7:41
  • "How" is a very broad question. It works by allocating memory. Commented Jan 17, 2024 at 7:51

3 Answers 3

1

GCC does not implement malloc. This is part of the C standard library.

The usual C library used on bare metal ARM microcontrollers is newlib.

You are correct that malloc depends on _sbrk_r, which in turn is a thread safe version of sbrk or _sbrk.

The typical brk/sbrk implementation usually keeps a single word of state, which is a pointer to the end of the heap. Every time you ask for more heap it increments this pointer and returns its previous value.

The initial value for the end of the heap is set using a symbol which is defined in the linker script. Traditionally this is called _end or end.

So maybe all you need to have malloc working is a liker script that defines _end. The ones in STM32Cube do this.

Sometimes there is also a symbol for the point beyond which the heap must not grow, and the brk implementation may check for that too. You would have to look at the source for your C library to see if this is the case for you.

If this is not done then malloc will always return ever-increasing pointers, but eventually they will point beyond the end of memory and things will stop working as you expect.

Traditionally on some embedded systems the heap grows upwards into the same memory block into which the stack is growing downwards from the other end. In this case allocating too much memory with malloc will overrun the stack, and you can compare the returned pointers to the stack pointer to see how close you are to this happening.

Sign up to request clarification or add additional context in comments.

3 Comments

In Newlib sbrk_r is a reentrancy support wrapper for sbrk. Not sure where you are seeing brk. Not mentioned in the Newlib documentation. I think the s is for "standalone", and it is likely the brk is a glibc symbol.
just from memory, but also trying to not be newlib specific
Understood the question does indeed not mention Newlib - even if that is likely, uclib and glibc being both hosted.
0

They are implemented in the C library, not by the compiler. On a stand-alone (bare-metal) compiler such as arm-none-eabi-gcc, the C library is most normally Newlib (not glibc which is possibly the source you were looking at).

Newlib is retargetted to the platform by implementing a number of "syscalls". One of those syscalls is indeed sbrk/sbrk_r (most others are related to I/O - but anything target dependent or target defined).

In most cases sbrk is a simple implementation that simply increments a pointer within the statically allocated heap pool. Failing if the heap is exhausted.

The static heap block is usually allocated in the linker script (.ld file), and is typically automatically sized to use all available memory after all other allocations (static data objects and system stack).

If your implementation's malloc() already works, then your toolchain clearly already comes with a working sbrk implementation in syscalls.

The following would be a typical sbrk() implementation for a standalone system:

caddr_t sbrk(int incr) 
{
  extern char _end;     // Defined by the linker
  static char *heap_end;
  char *prev_heap_end;
 
  if (heap_end == 0) 
  {
    heap_end = &_end;
  }

  prev_heap_end = heap_end;

  if (heap_end + incr > stack_ptr)
  {
    write (1, "Heap and stack collision\n", 25);
    abort ();
  }

  heap_end += incr;
  return (caddr_t) prev_heap_end;
}

If sbrk were not defined, and your code used standard library dynamic memory allocation, your code would fail to link.

Often default syscall stubs are provided, most of which do nothing, and often that is fine - for example kill() and getpid() are often not relevant, and seldom necessary on a standalone system. But you can only getaway without implementing sbrk() if dynamic memory allocation is never used. Beating in mind that it is used internally by some standard library calls such as strdup() (explicitly) and in many printf implementations, of ncluding Newlib's.

Comments

0

How does arm-none-eabi-gcc 9.2 implement malloc/free?

In Linux world, it is way more fragmented. Compiler gcc compiles code. Standard C library implementation brings C functions. In the case of arm-none-eabi-gcc C standard library is typically newlib. Newlib is also compiled with gcc.

Gcc does not implement malloc/free, the "toolchain" as a whole does, newlib as part of the toolchain.

There are several malloc implementations in newlib. There is mallocr and nano-mallocr, but you seem to have already found them.

how malloc works in arm-none-eabi-gcc on bare-metal systems.

Follow the comments and the source code in the files linked above to learn about the intricacies of these specific allocation implementations.

How is it implemented at the low level in the source code?

It is implemented in these source files.

using malloc typically requires the implementation of functions like _sbrk_r or _malloc_r.

No, malloc does not typically require anything. Typically malloc requires nothing to work. Specifically in the case of newlib malloc calls a function called malloc_r which is a specific newlib interface to handle reentrant code. This is very specific to newlib implenentation and is not typical. There are many _r(struct _reent *) functions in newlib, like write_r read_r. They all are specific to newlib.

confirm whether these functions in the files are indeed called by malloc() to implement allocating function.

You can use a map file to check from where a symbol comes.

$ arm-none-eabi-gcc -specs=rdimon.specs  -Xlinker -Map=output.map  1.c
$ cat output.map  | grep .text.malloc
 .text.malloc   0x00008308       0x20 /usr/lib/gcc/arm-none-eabi/13.2.0/../../../../arm-none-eabi/lib/libc.a(libc_a-malloc.o)


$ arm-none-eabi-gcc -specs=nano.specs -specs=rdimon.specs  -Xlinker -Map=output.map  1.c
$ cat output.map  | grep .text.malloc
 .text.malloc   0x000082ec       0x20 /usr/lib/gcc/arm-none-eabi/13.2.0/../../../../arm-none-eabi/lib/libc_nano.a(libc_a-malloc.o)

where is _sbrk ?

The default _sbrk implementation looks like to be the following https://github.com/eblot/newlib/blob/2a63fa0fd26ffb6603f69d9e369e944fe449c246/libgloss/arm/redboot-syscalls.c#L203 . Every platform has its own sbrk. The "end" symbol is set by the linker to the end of used RAM.

1 Comment

Your first paragraph is confusing. You seem to be suggesting that Newlib is typically the C library for Linux. I don't think that was your intention. Remove the first sentence and it makes sense. No need to mention Linux at all.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.