【问题标题】:Barebones C++ without standard library?没有标准库的准系统 C++?
【发布时间】:2023-03-25 13:20:01
【问题描述】:

GCC 和 Clang 等编译器允许在没有 C++ 标准库的情况下编译 C++ 程序,例如使用-nostdlib 命令行标志。似乎这样经常无法链接你,例如:

void f() noexcept { throw 42; }
int main() { f(); }

由于__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(c runtime where _start is)你可能需要libsupc++,这是异常库支持。
  • 你的编译器应该记录细节。您可能只需要链接一堆启动代码(例如crtn.o 等)。对于例外情况,一些 C++ ABI 运行时库应该提供必要的功能(libcxxabi?)。
  • 什么是“-c链接”? -c 告诉 GCC 链接。
  • 我将此问题标记为“过于宽泛”,因为答案取决于编译器(我们假设 GCC)、ABI(我们假设 x86/x86_64 System V ABI 在具有 glibc 的系统上)以及究竟是什么您正在尝试实施(我介绍了一个小样本)。 osdev.org 是我所知道的关于该主题的最全面的资源。

标签: c++ std


【解决方案1】:

您基本上可以在osdev.org 找到所有问题的答案,但我还是会给出一个简短的总结。

当你给 GCC -nostdlib 时,你说的是“没有启动或库文件”。这包括:

  • crti.ocrtbegin.ocrtend.ocrtn.o。通常,内核开发人员只关心实现crti.ocrtend.o,并让GCC 通过将-print-file-name= 传递给链接器来提供crtbegin.ocrtend.o。通常,这些只是分别由.init.fini 组成的存根,从而为GCC 分别推送crtbegin.ocrtend.o 的内容留出了空间。这些文件是调用全局构造函数/析构函数所必需的。
  • 你无法避免链接libgcc ("low-level runtime library" (-lgcc) 因为即使你传递了-nostdlib GCC 也会在你使用它时发出对其函数的调用,从而导致莫名其妙的链接错误,因为看似没有原因。即使您正在实施/移植C library,情况也是如此。
  • 您“不需要”libstdc++ 不,但通常内核开发人员需要它。 Porting a C library 那么从头开始实现 C++ 标准库是一项极其艰巨的任务。

由于您只想摆脱“标准库”,但保留 libc(在 Linux 系统上),您实际上是在使用 C 库编写 C++。当然,这并没有错,你自己做,但最终我不明白这一点,除非你打算开发内核。

必读:

OSDev's C++ page - 如果你真的关心 RTTI/异常支持,那就是more annoying to implement than it sounds。通常,人们只是通过-fno-rtti-fno-exceptions,然后再担心或根本不担心。

【讨论】:

  • 如果您计算闪存中的字节数,这也是必要的。这主要适用于微型微控制器。
【解决方案2】:

“标准”是用词不当。在这种情况下,它并不意味着“由 C++ 标准定义的库(函数集、类等)”,而是“默认情况下 gcc 链接的常用库和对象集(某种格式的编译文件)”。其中一些是大多数甚至所有程序运行所必需的。

如果您使用此标志,则您有责任提供任何缺失的功能。有几种方法可以做到这一点:

  1. 从默认集合中挑选程序真正需要的库和对象。 (没有什么意义,因为结果很可能与默认链接标志完全相同)。
  2. 提供您自己的缺失功能实现。
  3. 通过编译器标志明确禁用程序未使用的语言功能。我知道两个这样的特性:异常和 RTTI。这是必需的,因为编译器需要生成与异常相关的代码和 RTTI 信息,即使这些功能没有在此模块中明确使用

【讨论】:

    猜你喜欢
    • 2017-04-15
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-22
    • 2019-09-03
    相关资源
    最近更新 更多