没有标准库的裸机C++?

20

像GCC和Clang这样的编译器允许在没有C++标准库的情况下编译C ++程序,例如使用-nostdlib命令行标志。 然而这些编译器常常失败,无法链接程序,例如:

<code>void f() noexcept { throw 42; }
int main() { f(); }
</code>

通常因为未定义的符号而无法链接,例如__cxa_allocate_exceptiontypeinfo for int__cxa_throw__gxx_personality_v0__clang_call_terminate__cxa_begin_catchstd::terminate()等。

即使是简单的

int main() {}

链接失败

ld: 警告: 找不到入口符号 _start;默認為0000000000400120

并且在执行时被操作系统杀死。使用-c标志,编译器仍会运行链接器,但以下错误会明显导致链接失败:

ld: mytest(.eh_frame)中的错误;将不会创建.eh_frame_hdr表。

是否有可能在不使用和链接到标准库的情况下编写和编译C++应用程序或库?如何在Linux上使用GCC或Clang编译代码?如果没有标准库,哪些核心语言特性将无法使用?


我认为你需要:libcrt(包含_start的C运行时库)和你可能需要异常库支持的libsupc++ - Alexander Oh
1
你的编译器应该记录详细信息。你可能只需要链接一堆启动代码(例如crtn.o等)。对于异常,一些C++ ABI运行时库应该提供必要的功能(libcxxabi?)。 - Kerrek SB
3
"-c 链接" 是什么?-c 告诉GCC不要进行链接。 - interjay
我将这个问题标记为“过于宽泛”,因为答案取决于编译器(我们假设是GCC),ABI(我们假设是在具有glibc的x86 / x86_64 System V ABI系统上)以及您要实现的具体内容(我涵盖了一个小样本)。 [osdev.org](http://wiki.osdev.org/)是我所知道的关于这个主题最全面的资源。 - user6339982
2个回答

29

你基本上可以在osdev.org找到所有问题的答案,但我还是会简要概述一下。

当你使用GCC的-nostdlib选项时,相当于说“没有启动或库文件”。这包括:

  • crti.ocrtbegin.ocrtend.ocrtn.o。通常内核开发人员只需要实现crti.ocrtend.o,并通过向链接器传递-print-file-name=参数让GCC提供crtbegin.ocrtend.o。通常这些只是由.init.fini构成的存根,分别留出空间让GCC塞入crtbegin.ocrtend.o的内容。这些文件对于调用全局构造函数/析构函数是必需的。
  • 你无法避免链接libgcc“低级运行时库”-lgcc),因为即使你传递了-nostdlib,GCC仍然会在你使用它的函数时发出调用,导致似乎没有原因的链接错误。即便你正在实现/移植一个C库也是如此。
  • 你不一定需要libstdc++,但通常内核开发者会想要它。从头实现C++标准库是一项极其困难的任务,需要先移植C库再进行实现。(参考文档)
  • 如果你只是想去除“标准库”,但保留libc(在Linux系统上),那么你基本上是在使用一个仅具有C库的C++。当然,这并没有什么问题,你可以按照自己的方式编程,但除非你打算开发内核,否则我看不出有什么意义。

    必读:

    OSDev的C++页面 - 如果你真的关心RTTI /异常支持,实现起来比听起来更麻烦。通常人们只是传递-fno-rtti-fno-exceptions,然后以后再解决或完全不用担心它。(参考文档)


    如果你在计算闪存字节数,这也是必要的。这主要适用于微型微控制器。 - Alexander Oh
    内核开发人员难道不关心crti.o和crtn.o,而不是crtend.o吗? - penguin359

    7
    “标准”是一个误称。在这个上下文中,它不是指“由C++标准定义的库(函数、类等)”,而是指“gcc默认链接的常用库和对象(以特定格式编译的文件)”。其中一些对于大多数甚至所有程序都是必需的。
    如果您使用此标志,则需要负责提供任何缺失的功能。有几种方法可以实现:
    1.从默认集合中挑选出程序实际需要的库和对象。(这样做很少有意义,因为结果很可能与默认链接标志完全相同);
    2.提供缺失功能的自己的实现;
    3.通过编译器标志明确禁用语言功能,您的程序不使用。我知道两个这样的功能:异常和运行时类型信息(RTTI)。这是必要的,因为即使这些功能没有在该模块中显式使用,编译器仍然需要生成与异常相关的代码和RTTI信息。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接