【问题标题】:Are OS libraries written in assembly or in C操作系统库是用汇编语言还是用 C 语言编写的
【发布时间】:2021-10-28 03:49:06
【问题描述】:

我问这个,因为我得到的系统调用定义非常矛盾。

一方面,我已经看到它们是操作系统提供的用户程序可以调用的 API 的定义。由于此 API 是高级接口,因此必须使用 C 等高级语言实现。

另一方面,我看到实际的操作系统系统调用是机器指令,您必须设置某些寄存器才能调用(根据操作系统设置的某些合规标准)。但这看起来不像 UNIX API,如 open()、write() 和 read(),所以这里发生了什么。

我还读到这些高级接口是在 C 库中实现的,这些库执行实际的汇编代码系统调用。既然如此,我们为什么说操作系统提供了这个接口,而实际上它是由C语言提供的。如果我想在不使用 C 的情况下直接对操作系统执行 UNIX 系统调用怎么办?

【问题讨论】:

  • Linux 是开源的。 gnu 库是开源的。是什么阻止你检查?这很简单,会给你答案。
  • 不使用标准 C 库通常是愚蠢的。如果你真的需要避免这样做,你可能也知道该怎么做。
  • What if I want to perform a UNIX syscall directly to the OS without having to use C? 你可以。您还可以在汇编程序中编写整个应用程序。但问题是为了什么?为什么?你想达到什么目标?出于教育目的 - 是的,用于现实生活中的编程 - 永远不会
  • 是的,我知道我们不应该这样做,我只是想知道底层是怎么做的,操作系统提供的接口到底是什么
  • “由于这个 API 是一个高级接口,它必须用 C 等高级语言来实现。”不,这只是意味着库必须使用其他高级语言可以与之交互的 ABI。通常,操作系统本身是从 C 源代码编译的。

标签: c unix operating-system system system-calls


【解决方案1】:

操作系统库是用汇编还是 C 编写的

这是一个无法真正回答的问题,因为它取决于它。从技术上讲,实现没有限制(即它可以用任何语言编写,尽管 C 可能是最常见的,其次是汇编)。

这里的重要部分是 ABI。这定义了如何进行操作系统调用。

您可以在汇编中进行系统调用(如果您知道 ABI,您可以手动编写所有代码来遵守),C 编译器知道 ABI 并会自动生成进行调用所需的所有代码。

尽管大多数语言都允许您进行系统调用,但它们要么知道 ABI,要么拥有一个封装 API,可将调用从语言调用转换为该操作系统的适当 ABI。


我问这个,因为我得到的系统调用定义非常矛盾。

定义将取决于上下文。您必须举例说明定义的含义AND在什么上下文中使用。


一方面,我看到了它们是操作系统提供的用户程序可以调用的 API 的定义。

当然,这是看待它的一种方式。

更严格地说,我认为操作系统提供了一组可用于执行特权任务的接口。现在,这些接口可以通过特定环境提供的 API 公开,使其更易于使用。


由于这个 API 是一个高级接口,它必须用 C 等高级语言来实现。

有点真实。

一个环境可以暴露一个 API 并不意味着它需要一种高级语言(而 C 不是高级语言,它比汇编高出一步,它被认为是一种低级语言)。并且仅仅因为它被该语言公开并不意味着它是用该语言实现的。


另一方面,我看到实际的操作系统系统调用是机器指令,您必须设置某些寄存器才能调用(根据操作系统设置的某些合规标准)。

好的。在这里,我们从System Calls 移动到syscalls。我们应该非常小心地使用这些术语,以确保我们不会混淆不同的术语。

我会(这仍然有点抽象)将计算机视为几个抽象层次:

                      Hardware 
        ------        --------------
                      syscalls
          OS          --------------
                      System Calls       (read/write etc..)
        ------        --------------
                      Language Interface (read/write etc..)

如果您愿意(如果您知道如何),您可以直接戳硬件,但如果您可以进行系统调用(如果您知道如何)会更好,但最好使用使用明确定义的 ABI 的 OS 系统调用,但最好使用语言接口(您将调用 API)来调用底层系统调用。


但这看起来不像 UNIX API,如 open()、write() 和 read(),所以这里发生了什么。

这里 UNIX OS 提供了打开/关闭/读取接口。

C 库在 OS 系统调用之上提供了一个非常薄的 API 包装器接口。然后,C 编译器将生成正确的指令,以使用正确的 ABI 调用系统调用,进而调用操作系统中的下一层以使用系统调用。


我还读到这些高级接口是在 C 库中实现的,这些库执行实际的汇编代码系统调用。

高级界面可以用任何语言编写。但是 C 语言非常易于使用,以至于大多数其他语言都懒得自己动手,只需通过 C 接口调用即可。

【讨论】:

  • 非常感谢您提供如此详细的回答!我还有一个问题。如何在不通过 C 包装函数的情况下直接调用操作系统的系统调用。例如,我想调用操作系统(在本例中为 Linux)的 read(fd, buf, count),而不是 C 库的包装器版本。我该怎么做呢?它必须正确存在,因为 Linux 明确声明它提供了这个 API 来调用 read 函数。
  • 知道它是Linux 是不够的。您需要了解操作系统在您的特定硬件上使用的 ABI(请注意,没有标准的 ABI,这是您必须研究的内容)。您必须找到适当的文档。注意 C API 的存在是有原因的。通过手动调用操作系统,您将删除一层抽象,这会使您的代码更不便携且更易更改;此外,C API 增加的开销可能并不显着,因此存在严重的缺点,但这样做没有显着的好处。
  • 啊,我明白了。我知道这样做不是一个好主意,但我只是好奇操作系统如何提供这项服务。非常感谢!
【解决方案2】:

有两个open 函数——一个是操作系统(例如Linux)公开的系统调用open,二是C 标准库(例如glibc)公开的C 库函数open .

您可以看到这些函数的两个不同手册页 - 运行 man 2 open 可查看有关系统调用的手册页,运行 man 3 open 可查看有关 C 标准函数的手册页。


您提到的函数,例如 openwriteread,可能会让人感到困惑——因为它们既作为系统调用又作为 C 标准函数存在。但它们完全是独立的实体——事实上,glibc 的open 函数甚至不使用open 系统调用——它使用openat 系统调用。

在 Windows 上,系统调用 open 甚至不存在 - C 标准库函数 open 确实 仍然存在,并在幕后使用 WinAPI 的 CreateFile


如果我想直接对操作系统执行 UNIX 系统调用,而无需 必须使用 C 吗?

这是可能的——事实上,glibc 必须这样做才能实现 C 标准库函数。但这很棘手,并且涉及为系统调用实现包装器,有时甚至需要手工组装。


如果你想自己看东西,可以看how glibc implements open

int
__libc_open (const char *file, int oflag, ...)
{
  int mode = 0;
  if (__OPEN_NEEDS_MODE (oflag))
    {
      va_list arg;
      va_start (arg, oflag);
      mode = va_arg (arg, int);
      va_end (arg);
    }
  return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag, mode);
}
...
weak_alias (__libc_open, open)

请注意,函数以调用宏 SYSCALL_CANCEL 结束,该宏最终将调用 OS 公开的 openat 系统调用。

【讨论】:

  • 谢谢,这对我的问题很有帮助。
【解决方案3】:

在汇编中直接写东西是非常罕见的。通过用 C 语言编写,您可以为许多不同的 CPU 架构编译它,而通过用汇编语言编写,您基本上只能使用一种特定的架构。大多数操作系统都是用 C 编写的。我们说操作系统提供接口是因为您正在与恰好用 C 编写的操作系统进行交互。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 2015-04-26
    • 2020-04-22
    • 2011-10-15
    • 2016-07-05
    • 1970-01-01
    相关资源
    最近更新 更多