GCC:如何在 MCU 上完全禁用堆使用?
GCC: How to disable heap usage entirely on an MCU?
我有一个 运行 在基于 ARM Cortex-M 的 MCU 上使用 C 和 C++ 编写的应用程序。我使用 gcc
和 g++
来编译它,并希望完全禁用任何堆使用。
在 MCU 启动文件中,堆大小已设置为 0。除此之外,我还想禁止在代码中意外使用堆。
换句话说,我希望链接器(and/or 编译器)在 malloc
、calloc
、free
函数或使用了 new
、new[]
、delete
、delete[]
运算符。
到目前为止,我已经尝试了 -nostdlib
,这给了我 undefined reference to _start
这样的问题。我也试过 -nodefaultlibs
但当我尝试调用 malloc
时那个人仍然没有抱怨。正确的做法是什么?
备注:
- 此应用运行在“裸机”上运行,没有操作系统。
- 我还想避免在第 3 方代码(特定于供应商的库、标准库、printf 等)中使用任何 malloc。
- 我完全同意不使用需要动态内存分配的 C/C++ 标准库部分。
- 我更喜欢编译时解决方案而不是 运行 时解决方案。
我不确定这是最好的方法,但是您可以使用 ld
的 --wrap
标志(可以使用 -Wl
通过 gcc
).
想法是 --wrap
允许您请求 ld
将 "real" 符号重定向到您的自定义符号;例如,如果您执行 --wrap=malloc
,那么 ld
将查找要调用的 __wrap_malloc
函数,而不是原来的 `malloc.
现在,如果你 --wrap=malloc
没有定义 __wrap_malloc
如果没有人使用它,你将逃脱它,但如果有人引用 malloc
你会得到一个链接错误。
$ cat test-nomalloc.c
#include <stdlib.h>
int main() {
#ifdef USE_MALLOC
malloc(10);
#endif
return 0;
}
$ gcc test-nomalloc.c -Wl,--wrap=malloc
$ gcc test-nomalloc.c -DUSE_MALLOC -Wl,--wrap=malloc
/tmp/ccIEUu9v.o: In function `main':
test-nomalloc.c:(.text+0xa): undefined reference to `__wrap_malloc'
collect2: error: ld returned 1 exit status
对于 new
,您可以使用损坏的名称 _Znwm
(operator new(unsigned long)
) 和 _Znam
(operator new[](unsigned long)
),这应该是每个 new
应该归结到最后。
(作为答案发布,因为它不适合评论)
如果 OS 您 运行 支持 the use of LD_PRELOAD
,此代码应检测使用堆的尝试:
/* remove the LD_PRELOAD from the environment so it
doesn't kill any child process the app may spawn */
static void lib_init(void) __attribute__((constructor));
static void lib_init( void )
{
unsetenv( "LD_PRELOAD" );
}
void *malloc( size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
void *calloc( size_t n, size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
void *realloc( void *ptr, size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
void *valloc( size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
void *memalign( size_t alignment, size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
int posix_memalign( void **ptr, size_t alignment, size_t bytes )
{
*ptr = NULL;
kill( getpid(), SIGSEGV );
return( -1 );
}
假设 new
是使用 malloc()
实现的,而 delete
是使用 free()
实现的,这将捕获所有堆使用情况并为您提供一个带有堆栈跟踪的核心文件,假设启用了核心文件。
添加正确的头文件,编译文件:
gcc [-m32|-m64] -shared heapdetect.c -o heapdetect.so
运行 您的应用:
LD_PRELOAD=/path/to/heapdetect.so /your/app/here args ...
我有一个 运行 在基于 ARM Cortex-M 的 MCU 上使用 C 和 C++ 编写的应用程序。我使用 gcc
和 g++
来编译它,并希望完全禁用任何堆使用。
在 MCU 启动文件中,堆大小已设置为 0。除此之外,我还想禁止在代码中意外使用堆。
换句话说,我希望链接器(and/or 编译器)在 malloc
、calloc
、free
函数或使用了 new
、new[]
、delete
、delete[]
运算符。
到目前为止,我已经尝试了 -nostdlib
,这给了我 undefined reference to _start
这样的问题。我也试过 -nodefaultlibs
但当我尝试调用 malloc
时那个人仍然没有抱怨。正确的做法是什么?
备注:
- 此应用运行在“裸机”上运行,没有操作系统。
- 我还想避免在第 3 方代码(特定于供应商的库、标准库、printf 等)中使用任何 malloc。
- 我完全同意不使用需要动态内存分配的 C/C++ 标准库部分。
- 我更喜欢编译时解决方案而不是 运行 时解决方案。
我不确定这是最好的方法,但是您可以使用 ld
的 --wrap
标志(可以使用 -Wl
通过 gcc
).
想法是 --wrap
允许您请求 ld
将 "real" 符号重定向到您的自定义符号;例如,如果您执行 --wrap=malloc
,那么 ld
将查找要调用的 __wrap_malloc
函数,而不是原来的 `malloc.
现在,如果你 --wrap=malloc
没有定义 __wrap_malloc
如果没有人使用它,你将逃脱它,但如果有人引用 malloc
你会得到一个链接错误。
$ cat test-nomalloc.c
#include <stdlib.h>
int main() {
#ifdef USE_MALLOC
malloc(10);
#endif
return 0;
}
$ gcc test-nomalloc.c -Wl,--wrap=malloc
$ gcc test-nomalloc.c -DUSE_MALLOC -Wl,--wrap=malloc
/tmp/ccIEUu9v.o: In function `main':
test-nomalloc.c:(.text+0xa): undefined reference to `__wrap_malloc'
collect2: error: ld returned 1 exit status
对于 new
,您可以使用损坏的名称 _Znwm
(operator new(unsigned long)
) 和 _Znam
(operator new[](unsigned long)
),这应该是每个 new
应该归结到最后。
(作为答案发布,因为它不适合评论)
如果 OS 您 运行 支持 the use of LD_PRELOAD
,此代码应检测使用堆的尝试:
/* remove the LD_PRELOAD from the environment so it
doesn't kill any child process the app may spawn */
static void lib_init(void) __attribute__((constructor));
static void lib_init( void )
{
unsetenv( "LD_PRELOAD" );
}
void *malloc( size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
void *calloc( size_t n, size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
void *realloc( void *ptr, size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
void *valloc( size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
void *memalign( size_t alignment, size_t bytes )
{
kill( getpid(), SIGSEGV );
return( NULL );
}
int posix_memalign( void **ptr, size_t alignment, size_t bytes )
{
*ptr = NULL;
kill( getpid(), SIGSEGV );
return( -1 );
}
假设 new
是使用 malloc()
实现的,而 delete
是使用 free()
实现的,这将捕获所有堆使用情况并为您提供一个带有堆栈跟踪的核心文件,假设启用了核心文件。
添加正确的头文件,编译文件:
gcc [-m32|-m64] -shared heapdetect.c -o heapdetect.so
运行 您的应用:
LD_PRELOAD=/path/to/heapdetect.so /your/app/here args ...