C++ 有两种实现方式,托管的和独立的。托管实现确实假设存在malloc,并且经常将其用于内部目的。独立实现假设只存在 new 函数,因为它支持 C++ 关键字 new,但很容易确保不会调用此函数。
两者之间的区别在于,在独立实现中,您可以控制程序启动,并且所需的头文件和库集是有限的。通过设置入口点来控制程序的启动。
g++ -ffreestanding -e _entry program.cpp
program.cpp 可能是:
extern "C" int entry()
{
return 0;
}
extern "C" 是防止 C++ 名称修改所必需的,这可能会导致在链接过程中难以弄清楚 entry 的名称是什么。那么,不要使用new、std::string、流式I/O、STL等,避免使用at_exit。
这应该使您能够控制启动和清理代码,并限制编译器可以隐式依赖的标准库中可用的内容。但是请注意,这可能是一个具有挑战性的环境。您不仅会阻止初始化堆、I/O 流等,还会阻止设置异常、RTTI 和调用静态存储对象构造函数等。您将不得不编写代码或使用库来手动选择您可能想要使用的 C++ 的几个功能。如果你走这条路,你可能想仔细阅读这个 wiki http://wiki.osdev.org/C%2B%2B。您可能希望至少调用全局构造函数,这很容易做到。
说明
标准
C++ 具有“独立实现”的概念,其中可用的标头更少。
3.6.1 主函数[basic.start.main]
1 [snip] 独立环境中的程序是否需要定义 main 函数由实现定义。
17.6.1.3 独立实施 [合规]
1 定义了两种实现:托管和独立 (1.4)。对于托管实现,这
国际标准描述了一组可用的标头。
2 独立实现具有一组实现定义的标头。该集合应至少包括
表 16 中显示的标题。
3 提供的标头 版本应至少声明函数 abort、atexit、at_quick_exit、exit 和 quick_exit (18.5)。 [剪辑]
表16列出ciso646、cstddef、cfloat、limits、climits、cstdint、cstdlib、new、typeinfo、@98765434@2@、@98765434@2 cstdalign、cstdarg、cstdbool、type_traits 和 atomic。
以上大多数标头都包含类型、常量和模板的简单定义。唯一可能看起来有问题的是typeinfo、exception、cstdlib 和new。前两个分别支持 RTTI 和异常,您可以确保通过附加编译器标志禁用它们。 cstdlib 和 new 您可以通过不调用 exit/at_exit 并且不使用 new 表达式来简单地忽略。避免at_exit 的原因是它可能在内部调用new。独立片段中的任何其他内容都不应调用 cstdlib 或 new 中的任何内容。
选项
上面最重要的选项是-e _entry,它可以让您控制程序启动时运行的内容。
-ffreestanding 告诉编译器和标准库(更确切地说,它的独立片段)不要假设整个标准库都存在(即使它仍然存在)。它可以防止生成令人惊讶的代码。请注意,此选项实际上并不限制 您 可以使用哪些标头。例如,您仍然可以使用iostream,但如果您还更改了入口点,这可能不是一个好主意。它的作用是防止支持 freestanding 标头的代码调用 freestanding 标头之外的任何内容,并防止编译器隐式生成任何此类调用。