C有标准的ABI吗?

从其他地方的讨论:

C ++没有标准的ABI

但C也不是吗?

在任何给定的平台上它几乎都可以。 如果没有语言交流,那么作为语言间交流的通用语言就没有用。

你对此有何看法?

C没有定义ABI。 实际上,它会向后弯曲以避免定义ABI。 那些喜欢我的人,他们花费了大部分编程,在C / 16位32/64位架构上使用8位字节,2位补码算法和平面地址空间进行编程,通常会在阅读令人费解的语言时感到非常惊讶。目前的C标准。

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

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

C原则上没有标准的ABI,但在实践中,这很少重要:您可以执行操作系统供应商的工作。

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

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

ABI,即使是C,也有与平台无关的部分,依赖于处理器的部分(应该保存哪些寄存器,用于传递参数,……)和依赖于OS的部分(或多或少)与处理器相同的因素,因为一些选择不是由架构强加的,而是权衡的结果,加上一些OS有一个独立于语言的语言概念,因此任何语言的编译器都必须生成正确的处理那些,处理线程也可能会在ABI上强加一些东西 – 如果一个寄存器指向TLS,你就不能将它用于你想要的东西。

理论上,每个编译器都可能有自己的ABI。 但通常,对于一对处理器/ OS,ABI由OS供应商修复,该供应商通常还提供C编译器和使用该ABI且竞争者更喜欢兼容的公共库。 (如果某些操作系统有例外,我不会感到惊讶,因为它不是主要的编程语言)。

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

ABI for C是特定于平台的 – 它涵盖了诸如寄存器分配和调用约定之类的问题,这些问题显然特定于特定处理器。 这里有些例子:

  • ARM ABI (包括C ++)
  • PowerPC Embedded ABI
  • x86的几个ABI

x86有许多调用约定,在Windows下扩展,以声明使用哪一个。 嵌入式Linux的平台ABI也随着时间的推移而发生变化,导致用户空间不兼容。 请参阅此处的ARM Linux端口的一些历史记录,其中显示了向较新的ABI过渡的问题。

C也不是吗?

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

虽然这种协议可能被认为是ABI的一部分,但与JVM浏览器沙箱之类的托管执行上下文不同,这远不是完全标准的ABI本身。

虽然已经在为多个操作系统(特别是Unix系统上的i386)的给定体系结构定义单个ABI方面进行了多次尝试,但是这些努力还没有取得如此成功。 相反,操作系统倾向于定义自己的ABI ……

引用… Linux系统编程第4页。

C没有标准的ABI。 这可以通过在那里使用的所有调用约定(cdecl,fastcall和stdcall)轻松说明。 每个都是不同的ABI。

在C89标准之前,许多平台的C编译器基本上使用相同的ABI,除了数据大小的变化。 对于堆栈向下增长的机器,调用函数的代码将按从右到左的顺序推送堆栈中的参数,然后调用该函数(在该过程中推送返回地址)。 被调用的函数会将其参数保留在堆栈上,并且调用者可以随意调整堆栈指针以将其删除[或者,在某些体系结构上,可能会调整堆栈值到位]。 虽然使大多数程序不必依赖该约定,但它仍然使用多年,因为它很简单并且工作得很好。 虽然没有“官方”文档certificate这是一个跨平台的“标准”,但大多数针对具有向下增长的堆栈的计算机的编译器都以这种方式工作,从而导致比现在更高的一致性。