编程语言的标准库是如何实现的?

How is standard library for programming language implemented?

我无法理解除 C 之外的编程语言的标准库是如何编写的。

据我了解,C 标准库可以混合使用 C 和汇编程序来实现,其中需要汇编程序以便可以调用系统调用,因此 fopen, fscanf ...都可以用。

其他编程语言如何使用其标准库实现此功能(使用 i/o、文件和所有其他需要系统调用的东西)?它们都允许像 C 一样内联汇编程序还是有其他方法?

我读到可以使用 C 及其标准库来实现其他语言库,但我不确定这是如何完成的。

edit1. 尝试更具体。
(实现标准库的语言称为 new_lang。)

如果有人可以详细说明第二种方法是如何在目标代码级别和实现级别完成的(使用 C 运行时),因为我无法理解的是:

  1. C 运行时是使用 C 语法还是 new_lang 语法调用?我们如何从 new_lang 库中的某处调用 ssize_t write(int fd, const void *buf, size_t count)?
  2. 如果 new_lang 没有指针作为数据类型会发生什么,第二个参数 const void *buf 如何从 new_lang 传递给 write ?如果 new_lang 没有 C 数据类型,它如何遵循 C 运行时 api
  3. 如果 new_lang 库中的某些函数调用 C 运行时,是否意味着它必须遵守其 abi?整数、char 类型的数据大小必须在 new_lang 和 C 中匹配给定平台(以及由 abi 指定的其他内容,参数是由堆栈或寄存器等传递的)?
    这不是限制过度了吗,例如,如果 new_lang 需要为 char 保留更多字节怎么办?

我试图尽可能笼统,但我不确定如何在不深入细节的情况下解释问题。

视语言而定,甚至可以多选。请注意,在 C 中实现的标准 libraries/runtimes 通常使用编译器特定的扩展和属性,因此不是用标准的未扩展 C 编写的。

对于像 Pascal 这样的语言,多种方法是可能的并且确实存在。 Pascal 是一种与 C 处于同一级别的语言(and/or C++,因为大多数幸存的语言也是面向 object 的),例如FreePascal 在 Pascal 和汇编程序中有其 运行 时间库,并且可以在 Linux 上 运行 而无需链接到任何 C 编译代码。

选择 C ​​的原因通常是管理(工具和程序员的可用性)多于技术

同时 Gnu Pascal 基本上是一个 gcc mod,并建立在 libgcc、glibc 等基础上

edit1 的回答:

  1. Afaik 对于您正在使用的确切目标非常内部。有一些 write() 可以从系统编译器调用,但这可能是一个 运行time (3) 包装系统调用的函数,而不是直接 (2) 系统调用。 Afaik 可以保证 (3) 函数是真正的函数而不是宏,但我对此并不完全确定。

在 BSD 上,系统调用等同于函数调用,而在 Linux/i386 上则不然。语法无关紧要,生成的代码必须是等效的(不相同,但接近)。语法本身并不重要,重要的是 C 编译器如何解释语法。通常唯一保证工作的东西(就经典的 POSIX 哲学而言)是 system C 编译器,这是唯一保证能够工作的解释系统 headers,因为它们通常包含非标准扩展或 mod 修饰符。其他任何东西都必须确保它匹配,可能是在每个目标的基础上。因此,大多数语言都建立在 C 运行time 之上,并且通常有自己的 运行time 的 C 部分。

  1. 您必须以某种方式使它们在每个目标的基础上与每个目标的 C 编译器相匹配,或者通过自动适应(您的整个系统基于 C 和 C 编译器,并且类型等效性在某种程度上自动传播),通过痛苦 target-by-target 制作一些等价物,或者用 C 或汇编代码包装每个函数。有时每个目标多次(例如 MS VC 和 mingw,尽管最近它们比 10-15 年前更兼容,当时 gcc 不兼容,例如 COM)

例如Free Pascal 有一个 cdecl; mod标记 C 可调用函数的标识符,然后编译器生成与该目标上的系统 C 编译器等效的调用代码。

这听起来很糟糕,但通常只有几个变体。但这仍然不容易,例如x86_64 API 在 Linux/FreeBSD 一侧(sysv)、Windows(win64 自己的约定)和 OS X(aix 约定)之间略有不同。人们可以通过尽可能多地用 C 语言实现整个系统来避免这种情况,但随后您将永远受困于它(和混合语言系统)。此外,通过这种方式,Cisms 和 Unixisms 会渗透到您的新语言中,因为它更容易。

*nix 上的许多语言都采用这种方式,因为它更容易快速初始移植到新的东西。但反过来你可以维护一个混合语言系统。通常还继承了许多与构建相关的 C 特性,如外部预处理器、header-are-included 作为文本并一遍又一遍地重新解释,以及基于 make 的构建系统。

有关可能出现的问题的列表,请参阅 How to design a C / C++ library to be usable in many client languages?

  1. 是的,但只有它的二进制部分,因为 C 编译器当然不能进行严格形式的类型检查。但是大小、字段偏移量(打包)、调用顺序、寄存器使用以及是否在寄存器中传递小结构等必须匹配。