我试图在资源不足的应用程序中完全禁用动态内存分配。我不会使用malloc / free等,据我所知,我的任何依赖都没有。
我已经尝试在链接器文件LinkerScript.ld
中清零堆:
_Min_Heap_Size = 0x000; /* required amount of heap */
但这似乎并不保证没有库函数会尝试调用malloc
。
有没有办法强制执行动态内存分配不会发生,如果是这样,构建失败?
这个项目没有操作系统(裸机,STM32F302R8)与arm-none-eabi-gcc
交叉编译。
在most common gcc based Cortex-M toolchain中,库函数由newlib C库提供。 malloc()
和friends的newlib实现使用_sbrk()
函数为堆分配内存,该函数必须由用户软件实现。
如果您的应用程序中没有_sbrk()
,则构建将在链接时失败。找到并删除它。
您可能还想了解如何找到why a symbol is referenced或make the build fail when an arbitrary library function is referenced
我试图在资源不足的应用程序中完全禁用动态内存分配。
这很不寻常。一般来说,人们限制了他们(托管)应用程序使用的动态内存(如何做到这一点是一个不同的问题,通常是特定的operating system)。为什么要完全禁用它?如下所述,动态内存很可能在C standard library实现内部使用。
仔细阅读C11标准n1570(或C99标准版)。
C基本上有两种“模式”或两种“方言”:托管的C语言和独立的C语言。该标准的§4 Conformance中的确切措辞是
这两种符合实施形式是托管和独立的。符合要求的托管实现应接受任何严格符合的程序。符合标准的独立实施应接受任何严格符合的程序,其中使用库条款(第7条)中规定的特征仅限于标准标题
<float.h>
,<iso646.h>
,<limits.h>
,<stdalign.h>
,<stdarg.h>
,<stdbool.h>
,<stddef.h>
,<stdint.h>
的内容。和<stdnoreturn.h>
。
并且定义了malloc
(在<stdlib.h>
中声明)并且应该可用于托管实现,并且通常在独立实现中不可用(但这是特定于实现的)。
显然,您正在使用独立实现(因为您没有标准要求托管实现的malloc
)。海湾合作委员会has为-ffreestanding
模式。你应该使用它。然后<stdlib.h>
不可用,你的代码不能在该模式下使用标准的malloc
(除非它明确声明malloc
)。
在托管实现中,您通常可以重新定义malloc
(前提是它仍具有标准所需的所有属性)。那么你可能会使用像this这样的东西(总是失败但仍然符合标准,malloc
实现)。
最后,如果您使用GNU binutils链接器,如果您的目标文件包含对malloc
的任何外部引用,则始终可以使链接失败。通过在Makefile
中添加一些特定的配方或规则(可能使用nm
),或者如果使用任何体面的build automation工具(如果你的构建自动化在链接之前不允许这样的检查,那么切换到一个确实:make
,ninja
,omake
和其他许多人....)
如果你想在托管环境中的编译时检测到malloc
的任何使用,你可以编写自己的GCC plugin这样做(我觉得这有点矫枉过正,但选择权在你手中)。或者(在实践中更简单)使用一些脚本(例如使用grep)检测C源代码中malloc
或calloc
字的出现。
请注意,在大多数托管实现中,在实践中,fprintf
,fopen
,printf
,fputc
(以及许多其他)等标准函数在内部 - 有时最少 - 使用malloc
。具体地说,如果你的程序(在托管实现之上)使用fopen
,它很可能间接使用malloc
,因为在标准的FILE
内部通常有一些堆分配的缓冲区,fopen
是malloc
-ing(它通常得到free
-d at fclose
时间)。
有没有办法强制执行动态内存分配不会发生,如果是这样,构建失败?
在实践中,是的。只需在Makefile
中添加一些脚本进行此类检查。在源文件上使用grep
,或在目标文件上使用nm
。但是如果你在代码中使用标准的fopen
(来自<stdio.h>
),它通常会在内部做一些malloc
。
在许多operating systems(您的应用程序使用的那个,如果有的话)上,有一种方法可以在运行时限制堆内存。 Linux有setrlimit(2)和RLIMIT_DATA
。
如果您正在使用某些free software或开源C standard library实现(在托管环境中),例如GNU glibc或musl-libc,您可以研究其源代码并检查fopen
是否使用堆内存。