我一直不清楚ABI是什么。别给我指维基百科上的文章。如果我能理解,我就不会在这里发这么长的帖子了。

这是我对不同界面的看法:

电视遥控器是用户和电视之间的接口。它是一个现有的实体,但本身无用(不提供任何功能)。遥控器上每个按钮的所有功能都在电视机中实现。

Interface: It is an "existing entity" layer between the functionality and consumer of that functionality. An interface by itself doesn't do anything. It just invokes the functionality lying behind. Now depending on who the user is there are different type of interfaces. Command Line Interface (CLI) commands are the existing entities, the consumer is the user and functionality lies behind. functionality: my software functionality which solves some purpose to which we are describing this interface. existing entities: commands consumer: user Graphical User Interface(GUI) window, buttons, etc. are the existing entities, and again the consumer is the user and functionality lies behind. functionality: my software functionality which solves some problem to which we are describing this interface. existing entities: window, buttons etc.. consumer: user Application Programming Interface(API) functions (or to be more correct) interfaces (in interfaced based programming) are the existing entities, consumer here is another program not a user, and again functionality lies behind this layer. functionality: my software functionality which solves some problem to which we are describing this interface. existing entities: functions, Interfaces (array of functions). consumer: another program/application. Application Binary Interface (ABI) Here is where my problem starts. functionality: ??? existing entities: ??? consumer: ???

我用不同的语言编写过软件,并提供过不同类型的接口(CLI、GUI和API),但我不确定是否曾经提供过ABI。

维基百科说:

abi涵盖了诸如 数据类型、大小和对齐方式; 调用约定,它控制函数的实参 传递和返回检索到的值; 系统调用编号以及应用程序应该如何进行系统调用 到操作系统; 其他abi标准化细节,如 c++名字mangling, 异常传播,以及 调用约定的编译器之间在同一平台,但做 不需要跨平台兼容性。

谁需要这些细节?请不要说操作系统。我懂汇编编程。我知道如何链接和加载工作。我知道里面发生了什么。 为什么c++会出现名字混淆?我以为我们是在谈论二元的层面。为什么会出现语言?

无论如何,我已经下载了[PDF] System V应用程序二进制接口版4.1(1997-03-18)来看看它到底包含了什么。大部分都说不通啊。

Why does it contain two chapters (4th & 5th) to describe the ELF file format? In fact, these are the only two significant chapters of that specification. The rest of the chapters are "processor specific". Anyway, I though that it is a completely different topic. Please don't say that ELF file format specifications are the ABI. It doesn't qualify to be an interface according to the definition. I know, since we are talking at such a low level it must be very specific. But I'm not sure how is it "instruction set architecture (ISA)" specific? Where can I find Microsoft Windows' ABI?

这些是困扰我的主要问题。


当前回答

答:简单地说,ABI与API的一个共同之处是它是一个接口。可重用程序公开了一个稳定的接口(API),可用于在另一个程序中重用该程序。

B. However, an ABI is an interface issued for some specific processor-platform for some specific language. All compiler-vendors desiring to target that platform for that same language will have to ensure that not only compiled code in form of relocatable object codes comply with the interface to be able to link and cross-link with each other but also executables comply with it to be able to run on the platform at all. So, ABI is much broader set of specifications/standard than a typical function API. It may include some API objects to be enforced upon the language-users by the compiler. The compiler-vendor will have to include support for the same in their distributions. Needless to say, the platform vendor is the rightful authority to issue ABIs for its platform. Both compiler vendors and ABIs need to comply with the corresponding language-standard (e.g. ISO standard for C++).

C.平台供应商对ABI的定义是:

“1。可执行文件为了在特定的执行环境中执行而必须遵守的规范。例如,Arm架构的Linux ABI。

独立生成的可重定位文件必须遵守的规范的一个特定方面,以便静态可链接和可执行。例如,Arm架构的c++ ABI, Arm架构的运行时ABI, Arm架构的C库ABI。”

D.举例;基于Itanium架构的c++通用ABI也由一个联盟发布。平台供应商自己的c++的abi在多大程度上符合它完全取决于平台供应商。

E.作为另一个例子。Arm架构的c++ ABI在这里。

F.前面已经说过,处理器体系结构的ABI将确保一个可重用程序和另一个重用它的程序之间的API适用于该处理器体系结构。

G. That brings us to service-oriented components (e.g. SOAP-based web services). They too require an API to exist between a SOAP-based web service and client program (could be an app, front-end or another web service) for the client program to reuse the web service.The API is described in terms of standardized protocols like WSDL (interface description) and SOAP(message format) and is language-neutral and platform-neutral. It is not targeted to any specific processor-platform and thus it is not "binary" like ABI. A client-program on any one platform type and written in any language can remotely reuse a web service written in any other language and hosted on an entirely different processor-platform. This is made possible by the fact that both WSDL and SOAP are text-based (XML) protocols. In case of RESTful web services, the transport protocol http--also a text-based protocol-- itself acts as the API (CRUD methods).

其他回答

为了调用共享库中的代码,或者在编译单元之间调用代码,object文件需要包含调用的标签。c++修改了方法标签的名称,以加强数据隐藏并允许重载方法。这就是为什么您不能混合来自不同c++编译器的文件,除非它们显式地支持相同的ABI。

如果您了解汇编以及操作系统级别的工作方式,那么您就符合特定的ABI。ABI控制参数的传递方式、返回值放置的位置等。对于许多平台来说,只有一种ABI可供选择,在这些情况下,ABI只是“事情如何工作”。

然而,ABI也控制着c++中类/对象的布局。如果您希望能够跨模块边界传递对象引用,或者如果您希望混合使用不同编译器编译的代码,这是必要的。

此外,如果您有一个可以执行32位二进制文件的64位操作系统,那么32位和64位代码将有不同的abi。

通常,链接到相同可执行文件中的任何代码都必须符合相同的ABI。如果希望在使用不同abi的代码之间进行通信,则必须使用某种形式的RPC或序列化协议。

我认为你过于努力地将不同类型的界面挤进一个固定的特征集。例如,一个界面不一定要分成消费者和生产者。接口只是两个实体交互的约定。

abi可以(部分地)与isa无关。有些方面(如调用约定)依赖于ISA,而其他方面(如c++类布局)则不依赖于ISA。

定义良好的ABI对于编写编译器的人来说非常重要。如果没有定义良好的ABI,就不可能生成可互操作的代码。

编辑:需要澄清的一些注释:

ABI中的“二进制”并不排除字符串或文本的使用。如果您想要链接一个导出c++类的DLL,则必须对其中的方法和类型签名进行编码。这就是c++名称破坏的用武之地。 您从未提供ABI的原因是绝大多数程序员都不会这样做。ABI是由设计平台(即操作系统)的人提供的,很少有程序员有特权设计一个广泛使用的ABI。

功能:一组影响编译器、程序集编写者、链接器和操作系统的契约。契约规定了函数如何布局,参数在哪里传递,参数如何传递,函数返回如何工作。这些元组通常特定于(处理器体系结构,操作系统)元组。

现有实体:参数布局、函数语义、寄存器分配。例如,ARM架构有许多ABI (APCS, EABI, GNU-EABI,更不用说一堆历史案例)-使用混合ABI会导致你的代码在跨边界调用时无法工作。

使用者:编译器、程序集编写器、操作系统、CPU特定架构。

谁需要这些细节?编译器,程序集编写者,代码生成(或对齐要求)的链接器,操作系统(中断处理,系统调用接口)。如果您进行汇编编程,那么您将遵循ABI!

c++的名称破坏是一个特殊的情况——它是一个以连接器和动态连接器为中心的问题——如果名称破坏没有标准化,那么动态链接将无法工作。从今以后,c++ ABI就这么叫了,c++ ABI。这不是链接器级别的问题,而是代码生成的问题。一旦你有了一个c++二进制文件,如果不从源代码重新编译,就不可能使它与另一个c++ ABI兼容(名称混乱,异常处理)。

ELF是一种用于加载器和动态链接器的文件格式。ELF是二进制代码和数据的容器格式,它指定了一段代码的ABI。我不认为ELF是严格意义上的ABI,因为PE可执行文件不是ABI。

所有的abi都是特定于指令集的。ARM ABI在MSP430或x86_64处理器上没有意义。

Windows有几个abi -例如,fastcall和stdcall是两个常用的abi。系统调用ABI又不同了。

术语ABI用于指代两个不同但相关的概念。

当谈到编译器时,它指的是用于从源级结构转换到二进制结构的规则。数据类型有多大?堆栈是如何工作的?如何将参数传递给函数?调用者和被调用者应该保存哪些寄存器?

当谈到库时,它指的是由编译库提供的二进制接口。这个接口是多种因素的结果,包括库的源代码、编译器使用的规则,以及在某些情况下从其他库中获得的定义。

对库的更改可以在不破坏API的情况下破坏ABI。例如,考虑具有如下接口的库。

void initfoo(FOO * foo)
int usefoo(FOO * foo, int bar)
void cleanupfoo(FOO * foo)

应用程序程序员编写的代码是

int dostuffwithfoo(int bar) {
  FOO foo;
  initfoo(&foo);
  int result = usefoo(&foo,bar)
  cleanupfoo(&foo);
  return result;
}

应用程序程序员并不关心FOO的大小或布局,但应用程序二进制文件最终会硬编码FOO的大小。如果标准库程序员在foo中添加了一个额外的字段,并且有人将新的标准库二进制文件与旧的应用程序二进制文件一起使用,那么标准库可能会进行越界内存访问。

OTOH,如果标准库的作者像这样设计他们的API。

FOO * newfoo(void)
int usefoo(FOO * foo, int bar)
void deletefoo((FOO * foo, int bar))

应用程序程序员编写的代码是

int dostuffwithfoo(int bar) {
  FOO * foo;
  foo = newfoo();
  int result = usefoo(foo,bar)
  deletefoo(foo);
  return result;
}

然后,应用程序二进制文件不需要知道任何关于FOO的结构,这些都可以隐藏在库中。你为此付出的代价是涉及到堆操作。

调用方和被调用方之间的ABI需要一致,以确保调用成功。堆栈使用,寄存器使用,程序结束堆栈弹出。所有这些都是ABI中最重要的部分。