STM32 - 动态内存分配实现,如何正确实现_sbrk函数?

Posted

技术标签:

【中文标题】STM32 - 动态内存分配实现,如何正确实现_sbrk函数?【英文标题】:STM32 - Dynamic Memory Allocation Implementation, how to correctly implement the _sbrk function? 【发布时间】:2021-12-28 22:29:03 【问题描述】:

我正在STM32F401RE板上用C++编写一个裸机编程项目,我需要实现malloc()free()函数。

我知道嵌入式系统上的动态内存分配不是一个好主意,但我需要它。

据我所知,为了使用 C 标准库的 mallocfree 函数,我需要手动实现一个名为 _sbkr() 的函数,为此我创建了一个库单个函数并将其添加到 main.cpp 源代码的包含中。

问题是它不起作用,当我尝试动态分配一个变量时,它返回一个 NULL 指针。

用gcc生成main的汇编代码,在要上传到板子的最终对象中好像没有实现_sbrk函数。

如何正确实现这个功能?

【问题讨论】:

要构建一个原始的 _sbrk 函数来生成功能性 GCC libc 和 newlib,您必须定义芯片可用内存的 init 和 end,这通常在链接描述文件中定义符号。一个例子,更多可以在谷歌上找到,在这里:interrupt.memfault.com/blog/boostrapping-libc-with-newlib 您使用的是什么工具链和 C 库?如果 GCC + Newlib,sourceware.org/newlib/libc.html#Syscalls 的示例实现就足够了。 "我知道嵌入式系统上的动态内存分配不是一个好主意"...好吧,您需要了解为什么避免陷阱——不要只是接受公认的智慧,然后以任何方式使用它。这并不总是一个坏主意,但它可能会被错误地使用。你知道你在做什么吗?也许你应该发布一个关于这个的问题?甚至是关于如何避免它的;我们只知道您“需要它” - 总有替代方案 - 这可能是 X-Y 问题。 【参考方案1】:

假设您使用的是 Newlib(在独立系统上与 GCC 一起使用的常用 C 库),则 C 库的目标特定移植层(“系统调用”)定义在 https://sourceware.org/newlib/libc.html#Syscalls。

此处以适用于独立(无操作系统)环境的最小实现为例:

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;

另请注意,如果您使用的是 RTOS 或线程库,您还需要使用您的 RTOS/线程库 mutex 调用来实现 __malloc_lock()__malloc_unlock()

还要注意,如果您使用 ST 的 STM32CubeIDE,它使用 GCC 和 Newlib,并且已经实现了系统调用层。

【讨论】:

不错的答案!谢谢! 谢谢!这个函数帮助我实现了动态内存分配,到目前为止它似乎可以工作。【参考方案2】:

sbrk 是一个在具有 MMU 的系统上有意义的函数,该系统运行一个操作系统,该操作系统保证为单独的进程提供单独的内存空间。

你似乎没有这些。所以,要求sbrk 的功能绝对没有意义。

您需要做的是首先实现一个操作系统,该操作系统利用您的硬件所没有的 MMU——它有一个 MPU。

所以,总而言之,不,这是行不通的。 sbrk 不是没有操作系统和 MMU 的东西。

如果你真的想在你的 STM32 上进行动态内存分配,你将不得不使用一个实现内存池的库(或自己编写一个),然后你可以这样做malloc/free(或者你想给他们打电话)自己。

我正在STM32F401RE板上用C++编写一个裸机编程项目,我需要实现malloc()和free()函数。

哦哦;裸机和动态内存分配?

实际上:您有一个不错的微控制器,并且您希望在其上运行 RTOS。没有任何借口,真的 - 它不会让任何事情变慢,并且使用的内存可以忽略不计,但会让您的编程更加安全和轻松。

大多数现代 RTOS 都有内存堆和分配器。 Chibios 肯定会,maybe you'll want to read FreeRTOS documentation 在自己开始任何事情之前先进行内存管理。

【讨论】:

感谢您的回复!不幸的是,这是一个大学项目,明确要求不要使用任何 RTOS。我会尝试寻找内存池库或者自己实现。 hm,请注意,无论您是在 PC 上的单个进程内存中还是在微控制器上实现它,这实际上并没有什么不同:在 PC 上,您将使用“正常的“malloc”以获得例如 1MB 的 RAM,然后您可以开发内存分配器,以便在调用 gios_malloc 时为程序提供内存块,并在调用 gios_free 时将它们返回到池中。我会强烈建议先在你的 PC 上进行这项工作,调试很容易,然后再获取相同的 C 代码,然后在你的微控制器上运行它(而不是从那里获得 1MB 操作系统,您会在链接描述文件中写下为此目的保留了 1MB 的部分,然后让您的内存分配器处理它。其余的实际上是相同的代码。)目前尚不清楚让您在微控制器上执行此操作的教学价值是什么。 这个答案不准确。它需要澄清,但大多数可能是指 Newlib C 库 not glibc。 Newlib 库系统调用移植层包括一个必须实现以支持动态内存分配的sbrk() 存根。然而,对于独立系统来说,实现是微不足道的——但它仍然需要存在。 sourceware.org/newlib/libc.html#Syscalls 给出了适用于独立系统的实现示例 @Clifford 不,这不是指 newlib 或 glibc。提问者必须处理的目标没有完整的 libc 实现——它无论如何都不是 POSIX 系统。您说的非常对,“给我的内存空间(但只有一个全局内存空间)”的实现非常简单。请注意我的回答的第一句话是“没有意义”:这没有意义。【参考方案3】:

使用STM32CubeMX(例如集成在STM32CubeIDE中),生成的代码将根据动态内存分配的需要包含_sbrk()的实现。这可以在文件sysmem.c 中找到。

【讨论】:

以上是关于STM32 - 动态内存分配实现,如何正确实现_sbrk函数?的主要内容,如果未能解决你的问题,请参考以下文章

stm32网联丢包跟内存分配有关吗

STM32内存管理

STM32内存管理

在 Flash 中为用户数据分配内存(STM32F4 HAL)

C语言在STM32中的内存分配

stm32f4 如何往外部存储sram写数据