裸机,无需全球运营商新

Bare metal without global operator new

本文关键字:运营商 裸机      更新时间:2023-10-16

考虑安全软件,其中一般不允许动态分配,不允许例外。仅当类显式定义运算符newdelete时,才允许动态分配。对其他类使用运算符new应该会导致编译失败。

在所述情况下导致编译失败的最简单方法是删除全局新运算符:

void* operator new(std::size_t) = delete;

一方面,这会导致标准库的副作用。例如,包含<array>通过<stdexcept>将包含传播到<new_allocator><new_allocator>使用运算符::new这会导致生成失败,即使你不想使用异常和内存分配。根据Scoot Meyers的说法<array>应该是裸机友好的。

另一方面,这会导致编译器内置运算符出错

src/main.cpp:91:31: error: deleted definition of 'void* operator new(std::size_t)'
void* operator new(std::size_t) = delete;                               ^
<built-in>: note: previous declaration of 'void* operator new(std::size_t)'

有什么解决方案可以禁止::new并使用<array>吗?

是否有任何解决方案可以在全球范围内禁止::new

如果你使用GCC和GNU LD,那么我认为你可以在你的链接器标志中添加--wrap=malloc。由于全局::new在内部使用malloc(),因此应用程序中对malloc()的所有调用都将替换为__wrap_malloc()。如果未定义此函数,则链接将失败。

另一个可能更简单的选择是将ASSERT(DEFINED(malloc) == 0, "Dynamic allocation used!");添加到链接器脚本中。这将断言未定义malloc()

这两个选项都不保护您重新定义全局::new以使用某种其他形式的全局分配。您可以在链接器脚本中对全局符号::new执行相同的操作,但是它的名称被破坏了(在此处_Znwj),所以这会有点奇怪......

不管你使用什么编程语言:

在任何有声的裸机系统上,只需从链接器脚本中完全删除.heap段即可。然后,任何依赖于动态分配的代码都将无法链接。而且,您不必为无论如何都不打算使用的段分配RAM。

我想强调两件事:

如果异常没有
  1. 进入代码,则包含与异常相关的标头及其定义不应打扰您。
  2. 禁用异常时,无法在代码中使用它们(如果禁用,编译将失败)。但是,它不会从标准库中删除异常的使用。标准库可能包含模板类的预编译版本,例如std::string(即std::basic_string<char, ...>) 或std::streambuf(即std::basic_streambuf<char, ...>),当您在代码中使用它时,编译器不会尝试实例化模板,它只是重用预编译的版本,但有例外。

为了更好地控制您的代码,我强烈建议使用 G++ 编译器-nostdlib编译选项完全排除标准库。它不会阻止您使用各种模板类,例如 STL 中的std::array,它只会为您排除整个C++库和运行时。

我还建议阅读裸机C++实用指南。它可能会更深入地了解C++裸机内部结构。