我一直不清楚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?

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


当前回答

让我至少回答你问题的一部分。通过一个例子说明Linux ABI如何影响系统调用,以及它为什么有用。

A systemcall is a way for a userspace program to ask the kernelspace for something. It works by putting the numeric code for the call and the argument in a certain register and triggering an interrupt. Than a switch occurs to kernelspace and the kernel looks up the numeric code and the argument, handles the request, puts the result back into a register and triggers a switch back to userspace. This is needed for example when the application wants to allocate memory or open a file (syscalls "brk" and "open").

现在系统调用有简短的名称“brk”等和相应的操作码,这些在系统特定的头文件中定义。只要这些操作码保持不变,您就可以使用不同更新的内核运行相同的已编译用户域程序,而无需重新编译。这样就有了预编译二进制文件使用的接口,因此就有了ABI。

其他回答

应用程序二进制接口(ABI)

功能:

从程序员的模型到底层系统的域数据的转换 类型,大小,对齐,调用约定,它控制如何 函数的参数被传递并返回检索到的值;的 系统调用编号以及应用程序应该如何进行系统调用 到操作系统;高级语言编译器的名称 破坏方案、异常传播和调用约定 在同一平台上的编译器之间,但不需要 跨平台兼容性……

现有的实体:

直接参与程序执行的逻辑块:ALU, 通用寄存器,用于内存/ I/O映射的寄存器,等等…

消费者:

语言处理器,链接器,汇编器…

任何必须确保构建工具链作为一个整体工作的人都需要这些。如果你用汇编语言写一个模块,用Python写另一个模块,而不是你自己的引导加载程序想要使用操作系统,那么你的“应用程序”模块是跨“二进制”边界工作的,需要这种“接口”的协议。

c++命名混乱,因为应用程序中可能需要链接来自不同高级语言的目标文件。考虑使用GCC标准库对Visual c++构建的Windows进行系统调用。

ELF是用于解释的来自对象文件的链接器的一种可能期望,尽管JVM可能有其他想法。

对于一个Windows RT商店应用程序,如果你真的想让一些构建工具链一起工作,尝试搜索ARM ABI。

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

区分ABI和API的最好方法是了解它的用途和原因:

对于x86-64,通常有一个ABI(对于x86 32位,有另一组ABI):

http://www.x86-64.org/documentation/abi.pdf

https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html

http://people.freebsd.org/~obrien/amd64-elf-abi.pdf

Linux + FreeBSD + MacOSX紧随其后,略有变化。Windows x64有自己的ABI:

http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/

Knowing the ABI and assuming other compiler follows it as well, then the binaries theoretically know how to call each other (libraries API in particular) and pass parameters over the stack or by registers etc. Or what registers will be changed upon calling the functions etc. Essentially these knowledge will help software to integrate with one another. Knowing the order of the registers / stack layout I can easily piece together different software written in assemblies together without much problem.

但是API是不同的:

它是一个定义了参数的高级函数名,这样如果不同的软件使用这些API构建,就可以相互调用。但是必须遵守SAME ABI的附加要求。

例如,Windows曾经是POSIX API兼容的:

https://en.wikipedia.org/wiki/Windows_Services_for_UNIX

https://en.wikipedia.org/wiki/POSIX

Linux也是POSIX兼容的。但是二进制文件不能被移动并立即运行。但是因为它们在POSIX兼容的API中使用了相同的NAMES,所以您可以在C语言中使用相同的软件,在不同的操作系统中重新编译它,并立即让它运行起来。

API是为了简化软件集成-预编译阶段。所以在编译之后,如果ABI不同的话,软件看起来会完全不同。

ABI的目的是在二进制/汇编级别定义软件的精确集成。

为了调用共享库中的代码,或者在编译单元之间调用代码,object文件需要包含调用的标签。c++修改了方法标签的名称,以加强数据隐藏并允许重载方法。这就是为什么您不能混合来自不同c++编译器的文件,除非它们显式地支持相同的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的结构,这些都可以隐藏在库中。你为此付出的代价是涉及到堆操作。