没有标准库的Barebones C++
Barebones C++ without standard library?
GCC和Clang等编译器允许在没有C++标准库的情况下编译C++程序,例如使用-nostdlib
命令行标志。这似乎经常无法将你联系起来,例如:
void f() noexcept { throw 42; }
int main() { f(); }
通常由于__cxa_allocate_exception
、typeinfo for int
、__cxa_throw
、__gxx_personality_v0
、__clang_call_terminate
、__cxa_begin_catch
、std::terminate()
等未定义的符号而导致链路失败。
即使是一个简单的
int main() {}
无法与链接
ld:警告:找不到入口符号
_start
;默认为000000000040120
并且在执行时被OS杀死。使用-c
,编译器仍然运行明显失败的链接器:
ld:
mytest
(.eh_frame
)错误;则不会创建CCD_ 13表。
在不使用和链接到标准库的情况下对C++应用程序或库进行编程和编译是一个现实的目标吗?如何在Linux上使用GCC或Clang编译代码?如果没有标准库,人们将无法使用哪些核心语言功能?
您基本上会在osdev.org上找到所有问题的答案,但我还是会做一个简短的总结。
当你给GCC -nostdlib
时,你说的是"没有启动或库文件"。这包括:
crti.o
、crtbegin.o
、crtend.o
和crtn.o
。通常,内核开发人员只关心实现crti.o
和crtend.o
,并让GCC通过将-print-file-name=
传递给链接器来提供crtbegin.o
和crtend.o
。通常,这些只是分别由.init
和.fini
组成的存根,为GCC分别推送crtbegin.o
和crtend.o
的内容留出了空间。这些文件是调用全局构造函数/析构函数所必需的- 您无法避免链接
libgcc
("低级运行库"(-lgcc
),因为即使您传递-nostdlib
,GCC也会在您使用它时发出对其函数的调用,从而导致莫名其妙的链接错误。即使在实现/移植C库时也是如此 - 你不需要
libstdc++
,但通常内核开发人员需要它。移植C库然后从头开始实现C++标准库是一项极其困难的任务
既然你只想去掉"标准库",但保留libc(在Linux系统上),那么你本质上就是在用一个C库编程C++。当然,这并没有错,你也可以这样做,但最终我看不出有什么意义,除非你计划开发一个内核。
所需读数:
OSDev的C++页面-如果你真的关心RTTI/异常支持,那么实现起来比听起来更烦人。通常情况下,人们只是通过-fno-rtti
或-fno-exceptions
,然后担心它到底是不是。
"标准"用词不当。在这种情况下,它并不意味着"C++标准定义的库(函数集、类等)",而是"默认情况下gcc链接的常用库和对象集(以特定格式编译的文件)"。其中一些是大多数甚至所有程序运行所必需的。
如果您使用此标志,则您有责任提供任何缺失的功能。有几种方法可以做到这一点:
- Cherry从默认集合中挑选程序真正需要的库和对象。(没有什么意义,因为结果很可能与默认链接标志完全相同)
- 提供您自己的缺失功能实现
- 通过编译器标志显式禁用程序未使用的语言功能。我知道两个这样的功能:异常和RTTI。这是必要的,因为编译器需要生成与异常相关的代码和RTTI信息,即使这些功能没有在该模块中显式使用