C是否有标准的ABI?

cfh9epnr  于 2023-10-16  发布在  其他
关注(0)|答案(9)|浏览(139)

somewhere else讨论:
C++没有标准的ABI(应用程序二进制接口)
但C也不是,对吧?
在任何平台上,它几乎都是如此。如果缺少一种语言,它就不能作为跨语言交流的弗兰卡。
你对此有何看法?

tgabmvqs

tgabmvqs1#

C没有定义ABI。事实上,它是在极力避免定义ABI。像我这样的人,在编程生涯中的大部分时间都在用C在16/32/64位架构上编程,这些架构具有8位字节、2的补码运算和平坦地址空间,通常会在阅读当前C标准的复杂语言时感到非常惊讶。
例如,阅读有关指针的内容。这个标准没有说任何像“指针是一个地址”这样简单的话,因为这是对ABI的一个假设。特别是,它允许指针位于不同的地址空间中并具有不同的宽度。
ABI是从语言的执行模型到特定机器/操作系统/编译器组合的Map。在语言规范中定义一个是没有意义的,因为这样做会冒着在某些体系结构上排除C实现的风险。

332nm8kg

332nm8kg2#

C语言原则上没有标准的ABI,但在实践中,这很少有关系:你做你的操作系统供应商所做的。
以x86 Windows上的调用约定为例:Windows API使用所谓的“标准”调用约定(stdcall)。因此,任何想要与操作系统接口的编译器都需要实现它。然而,stdcall并不支持所有的C90语言特性(例如,调用没有原型的函数,变量函数)。由于微软提供了一个C编译器,第二个调用约定是必要的,称为'C'调用约定(cdecl)。Windows上的大多数C编译器都将此作为默认调用约定,因此是可互操作的。
原则上,C也可能发生同样的情况,但由于C ABI(包括调用约定)必然要复杂得多,编译器供应商并没有就单一ABI达成一致,但仍然可以通过退回到extern "C"来进行互操作。

bbmckpt7

bbmckpt73#

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

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

ejk8hzay

ejk8hzay4#

尽管已经进行了几次尝试,为跨多个操作系统的给定架构(特别是Unix系统上的i386)定义单个ABI,但这些努力并没有取得这样的成功。相反,操作系统倾向于定义自己的ABI。
报价. Linux System Programming第4页。

mbzjlibv

mbzjlibv5#

一个ABI,即使是C语言,也有相当独立于平台的部分,依赖于处理器的部分(应该保存哪些寄存器,哪些寄存器用于传递参数,.)和依赖于操作系统的部分(或多或少与处理器的因素相同,因为有些选择不是由架构强加的,而是权衡的结果,加上一些操作系统有一个独立于语言的异常概念,因此任何语言的编译器都必须生成正确的东西来处理这些,线程的处理也可能会对ABI施加影响-如果一个寄存器指向TLS,你不能用它来做你想要的事情)。
理论上,每个编译器都有自己的ABI。但通常情况下,对于一对处理器/操作系统,ABI是由操作系统供应商固定的,这些供应商通常还提供C编译器和使用ABI的公共库,竞争对手更喜欢兼容。(如果C不是主要编程语言的某些操作系统有例外,我不会感到惊讶)。
但是操作系统供应商可能会因为这样或那样的原因而切换ABI(新版本的处理器可能具有您希望在ABI中使用的功能-例如,有些处理器要求x86_64的32位ABI允许使用所有寄存器)。在迁移阶段(可能会持续很长时间),您可能必须处理两个ABI。

ryhaxcpt

ryhaxcpt6#

C也没有,对吧?

在任何给定的平台上,它都是如此。如果缺少一种语言,它就不能作为跨语言交流的弗兰卡。

  • 几乎 * 可能指的是C编译器供应商选择的特定于体系结构的默认值,这些默认值适用于其他语言。因此,如果Keil的ARM C编译器将使用从左到右的小端参数排序和堆栈来传递参数和一些预定义的寄存器作为返回值,那么来自其他编译器的extern“C”将假定与这种方案兼容。

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

5anewei6

5anewei67#

在C89标准之前,许多平台上的C编译器基本上使用相同的ABI,保存数据大小的变化。对于堆栈向下增长的机器,调用函数的代码将按 * 从右到左 * 的顺序将参数压入堆栈,然后调用函数(在过程中压入返回地址)。一个被调用的函数会把它的参数留在堆栈上,调用者会在空闲的时候调整堆栈指针来删除它们[或者,在某些架构上,可能会调整堆栈的值]。虽然<stdarg.h>使得大多数程序不需要依赖这个约定,但它仍然使用了很多年,因为它很简单,工作得很好。虽然没有“官方”文件将其确定为跨平台“标准”,但大多数针对堆栈向下增长的机器的编译器都是这样工作的,从而导致比今天更高的一致性。

taor4pac

taor4pac8#

没有标准的ABI,因为C语言总是追求最高的运行时性能,而具有最高性能的ABI取决于底层硬件。因此,ABI可能只使用堆栈或首选寄存器来传递函数调用参数和任何给定硬件所需的返回值。
例如,即使amd 64(也称为x86-64)也有两种调用约定:Microsoft x64和System V AMD64 ABI。前者将4个第一个参数放入寄存器,其余的放入堆栈。后者将6个第一个参数放入寄存器,其余的放入堆栈。我不知道为什么微软为amd 64硬件创建了不兼容的调用约定。据我所知,Microsoft变体的性能稍差,并且是后来创建的。
有关详细信息,请参见https://en.wikipedia.org/wiki/X86_calling_conventions

zazmityj

zazmityj9#

C没有标准的ABI。这很容易通过那里使用的所有调用约定(cdecl,fastcall和stdcall)来说明。每个都是不同的ABI。
编辑:虽然C标准没有定义ABI,但我知道的所有平台都有一个标准的可预测ABI或一组ABI。这些往往是有据可查的。

相关问题