【问题标题】:Does C have a standard ABI?C 有标准 ABI 吗?
【发布时间】:2011-05-28 04:52:49
【问题描述】:

来自somewhere else的讨论:

C++ 没有标准的 ABI(应用程序二进制接口)

但 C 也不行,对吧?

在任何给定的平台上都差不多。如果缺少一种语言,它就无法作为跨语言交流的通用语言。

您对此有何看法?

【问题讨论】:

  • ABI?你的意思是API“应用程序编程接口”吗?
  • 我认为 OP 是指应用程序二进制接口
  • 不,ABI 在应用程序二进制接口中。
  • 我认为@FredOverflow 的意思是ABI 应用程序二进制接口en.wikipedia.org/wiki/Application_binary_interface
  • 我认为“在任何给定的平台上”有点狡猾,可能是偶然的。您几乎可以将“平台”定义为“始终使用相同的 C ABI”。具体来说,任何为动态加载代码定义的格式都必须为跨可执行边界的调用定义 ABI。该 ABI 当然需要支持 C 才能有任何实际用途(假设人们将使用 C 或 C++ 编写可执行文件),如果幸运的话,可能也支持 C++。如果它支持 C 但不支持 C++,则在您发布的所有内容上使用 extern "C" 编写 C++,和/或对链接的可执行文件使用相同的编译器。

标签: c abi


【解决方案1】:

C 没有定义 ABI。事实上,它向后弯曲以避免定义 ABI。那些像我一样的人,他们大部分时间都在用 C 语言编写 16/32/64 位架构,具有 8 位字节、2 的补码算法和平面地址空间,通常会在阅读令人费解的语言时感到非常惊讶当前的 C 标准。

例如,阅读有关指针的内容。该标准并没有说“指针是地址”这样简单的东西,因为那将是对 ABI 的假设。特别是,它允许指针位于不同的地址空间并具有不同的宽度。

ABI 是从语言的执行模型到特定机器/操作系统/编译器组合的映射。在语言规范中定义一个是没有意义的,因为这会冒着在某些架构上排除 C 实现的风险。

【讨论】:

  • “[…] 通常会在阅读当前 C 标准的复杂语言时感到非常惊讶。”:从哪个版本的标准开始?关于指针,我从未检查过 ISO C 是否允许这样做,但我知道有所谓的小型、拥抱和中型内存模型(中等有点混合),它们在 16 位时代很有名DOS(很多时候在 32 位机器上运行);指针已经不保证始终保持相同的大小。
  • @Hibou57 在我写答案时,当前的 C 标准是 C99。我怀疑 C11 是否发生了很大变化。小型、大型和中型内存模型不是 C 的一部分,而是 8086 架构上大多数 C 实现的一部分。
  • @curiousguy 好吧,它可以是数组的索引,也可以是通过地址表重定向的句柄,也可以是段和偏移量,也可以是带标记的描述符。 C 标准没有规定它必须是地址。
  • @curiousguy 如果您要说任何可以解码为地址的东西都是地址,那么除了文字之外的一切都是地址。你使这个词实际上毫无意义。
  • @curiousguy 为什么不呢?
【解决方案2】:

C 原则上没有标准 ABI,但在实践中,这并不重要:你做你的操作系统供应商所做的事情。

以 x86 Windows 上的调用约定为例:Windows API 使用所谓的“标准”调用约定 (stdcall)。因此,任何想要与操作系统交互的编译器都需要实现它。然而,stdcall 并不支持所有的 C90 语言特性(例如调用没有原型的函数、可变参数函数)。由于 Microsoft 提供了 C 编译器,因此需要第二个调用约定,称为“C”调用约定 (cdecl)。 Windows 上的大多数 C 编译器都使用它作为默认调用约定,因此是可互操作的。

原则上,C++ 也可能发生同样的情况,但由于 C++ ABI(包括调用约定)必然要复杂得多,编译器供应商并未就单一 ABI 达成一致,但仍可以通过回退到 @ 来实现互操作987654321@.

【讨论】:

  • 这是正确的,但不够清楚。与其说供应商之间没有就共同的 ABI 达成一致(这可以通过标准化委员会来解决)。更多的是同一个供应商在不同时间不同意自己的观点,因为他们并不总是预测未来的发展。
【解决方案3】:

C 的 ABI 是特定于平台的 - 它涵盖了寄存器分配和调用约定等问题,这些问题显然是特定于特定处理器的。以下是一些示例:

x86 有很多调用约定,在 Windows 下扩展来声明使用哪一个。嵌入式 Linux 的平台 ABI 也随着时间发生变化,导致用户空间不兼容。查看ARM Linux port here 的一些历史记录,其中显示了在过渡到更新的 ABI 时遇到的问题。

【讨论】:

  • 我继续删除了损坏的链接。
【解决方案4】:

虽然已经多次尝试 在定义一个单一的 ABI 为 跨多个给定架构 操作系统(特别是对于 i386 在 Unix 系统上),努力 没有遇到过这样的成功。 相反,操作系统倾向于 定义自己的 ABI ...

引用 ...Linux System Programming 第 4 页。

【讨论】:

    【解决方案5】:

    即使对于 C,ABI 也具有完全独立于平台的部分,依赖于处理器的部分(应保存哪些寄存器,用于传递参数,...)和依赖于操作系统的部分(与处理器的因素或多或少相同,因为某些选择不是由体系结构强加的,而是权衡的结果,再加上某些操作系统具有与语言无关的异常概念,因此任何语言的编译器都必须生成正确的处理这些的事情,线程的处理也可能对 ABI 强加一些东西——如果一个寄存器指向 TLS,你就不能用它来做你想要的)。

    理论上,每个编译器都可能有自己的 ABI。但通常,对于一对处理器/操作系统,ABI 由操作系统供应商修复,通常还提供 C 编译器和使用该 ABI 的通用库,而竞争对手更愿意兼容。 (如果 C 不是主要编程语言的某些操作系统存在例外情况,我不会感到惊讶)。

    但操作系统供应商可能出于某种原因切换 ABI(新版本的处理器可能具有您想在 ABI 中使用的功能之一 - 例如,有些人要求 x86_64 的 32 位 ABI 允许使用所有寄存器)。在迁移阶段(可能会持续很长时间),您可能需要处理两个 ABI。

    【讨论】:

      【解决方案6】:

      C也不行,对吧?

      在任何给定的平台上几乎都能做到。如果缺少这种语言,它作为语言间通信的通用语言就没有用处。
      几乎可能指的是 C 编译器供应商选择的特定于体系结构的默认值,这些默认值在其他语言中进行了调整。因此,如果 Keil 的 ARM C 编译器将使用从左到右的小端参数排序和堆栈来传递参数和一些预定的返回值寄存器,那么来自其他编译器的 extern "C" 将假定与这种方案兼容。

      虽然此类协议可能被视为 ABI 的一部分,但与托管执行上下文(例如 JVM 浏览器沙箱)不同,这远非完整的标准 ABI。

      【讨论】:

        【解决方案7】:

        C 没有标准的 ABI。这很容易通过所有使用的调用约定(cdecl、fastcall 和 stdcall)来说明。每个都是不同的 ABI。

        【讨论】:

          【解决方案8】:

          在 C89 标准之前,许多平台的 C 编译器使用基本相同的 ABI,除了数据大小的变化。对于堆栈向下增长的机器,调用函数的代码会按从右到左的顺序将参数压入堆栈,然后调用该函数(在进程中压入返回地址)。被调用的函数会将其参数留在堆栈上,调用者将在闲暇时调整堆栈指针以删除它们[或者,在某些架构上,可能会调整堆栈值]。虽然<stdarg.h> 使大多数程序不必依赖该约定,但它仍然使用了很多年,因为它简单且运行良好。虽然没有“官方”文档将其确立为跨平台“标准”,但大多数针对堆栈向下增长的机器的编译器都是以这种方式工作的,从而实现了比现在更高水平的一致性。

          【讨论】:

          • 所以,就像 ABI 一样,只有在整个过程中进行了足够多的更改,才称它为 ABI 没有意义? ;)
          • @hmijail:几乎所有为此类机器编写 C 编译器的人都知道其他编译器做了什么,并且在没有理由做其他任何事情的情况下跟随他们。许多“标准”不是由标准机构制定的,而是由一个人做某事,其他人做同样事情的过程。
          • 大多数 CPU 可以比堆栈更快地访问寄存器,因此标准化需要在堆栈上传递所有参数的调用转换确实没有意义。任何喜欢使用寄存器传递参数的方法显然都高度依赖硬件,不能成为标准的跨平台。
          【解决方案9】:

          没有标准的 ABI,因为 C 一直是关于最大运行时性能的,而具有最高性能的 ABI 取决于底层硬件。因此,ABI 可能只使用堆栈或首选寄存器来传递函数调用参数并根据任何给定硬件的需要返回值。

          例如,即使是 amd64(又名 x86-64)也有两个调用约定:Microsoft x64 和 System V AMD64 ABI。前者将 4 个第一个参数放入寄存器,其余的放入堆栈。后者将 6 个第一个参数放入寄存器,其余的放入堆栈。我不知道为什么微软为 amd64 硬件创建了不兼容的调用约定。据我所知,Microsoft 变体的性能稍差一些,是后来创建的。

          欲了解更多信息,请参阅https://en.wikipedia.org/wiki/X86_calling_conventions

          【讨论】:

            猜你喜欢
            • 2013-07-01
            • 1970-01-01
            • 2010-12-03
            • 1970-01-01
            • 2011-02-20
            • 2019-12-07
            • 1970-01-01
            • 2010-10-16
            相关资源
            最近更新 更多