什么是应用程序二进制接口(ABI)?
我从来不清楚ABI是什么。 请不要将我指向维基百科文章。 如果我能理解它,我不会在这里发布这么长的帖子。
这是我对不同接口的看法:
电视遥控器是用户和电视机之间的接口。 它是一个现有的实体,但它本身无用(不提供任何功能)。 遥控器上每个按钮的所有功能都在电视机中实现。
接口:它是该functionality
和consumer
之间的“现有实体”层。 一个接口本身并不做任何事情。 它只是调用后面的功能。
现在取决于用户是谁,有不同类型的接口。
命令行界面(CLI)命令是现有的实体,消费者是用户和功能所在。
functionality:
我的软件功能可以解决我们描述该界面的某些目的。
existing entities:
命令
consumer:
用户
图形用户界面(GUI)窗口,按钮等是现有实体,并且消费者也是用户和功能落后。
functionality:
我的软件功能可以解决我们描述该界面的某些目的。
existing entities:
窗口,按钮等。
consumer:
用户
应用程序编程接口(API)函数或更正确的接口(在基于接口的编程中)是现有实体,这里的消费者是另一个不是用户的程序,并且功能也在此层之后。
functionality:
我的软件功能可以解决我们描述该界面的某些目的。
existing entities:
函数,接口(函数数组)。
consumer:
另一程序/应用程序。
应用程序二进制接口(ABI)这是我的问题开始的地方。
functionality:
???
existing entities:
???
consumer:
???
维基百科说:
ABI涵盖了诸如
其他ABI标准化的细节,如
谁需要这些细节? 请不要说操作系统。 我知道程序集编程。 我知道如何链接和加载工作。 我知道里面到底发生了什么。
为什么C ++的名字会加入进来? 我以为我们在二元层面上谈论。 语言为什么进来?
无论如何,我已经下载了[PDF] System V Application Binary Interface Edition 4.1(1997-03-18),以查看它究竟包含了什么。 那么,其中大部分没有任何意义。
为什么它包含两章(第四和第五)来描述ELF文件格式? 实际上,这是规范中唯一的两个重要章节。 其余章节是“处理器特定的”。 无论如何,我认为这是一个完全不同的话题。 请不要说ELF文件格式规范是ABI。 根据定义,它不符合接口要求。
我知道,因为我们在这么低的层面上谈论,所以它必须非常具体。 但我不确定它是如何“指令集架构(ISA)”特定的?
我在哪里可以找到Microsoft Windows'ABI?
所以,这些是困扰我的主要疑问。
理解“ABI”的一个简单方法是将其与“API”进行比较。
您已经熟悉API的概念。 如果您想使用某些库或您的操作系统的功能,那么您将使用API。 API由数据类型/结构,常量,函数等组成,您可以在代码中使用它们来访问该外部组件的功能。
ABI非常相似。 可以将其视为API的编译版本(或作为机器语言级别的API)。 当您编写源代码时,您可以通过API访问该库。 编译代码后,应用程序将通过ABI访问库中的二进制数据。 ABI定义了编译后的应用程序将用来访问外部库的结构和方法(就像API一样),只是在较低的级别上。
当涉及到使用外部库的应用程序时,ABI很重要。 如果一个程序被构建为使用特定的库并且该库稍后更新,那么您不希望重新编译该应用程序(并且从最终用户的角度来看,您可能没有源代码)。 如果更新的库使用相同的ABI,那么您的程序将不需要更改。 即使内部工作可能已经改变,图书馆的界面(这也是你的程序真正关心的)。 具有相同ABI的库的两个版本有时称为“二进制兼容”,因为它们具有相同的低级接口(您应该能够用新版本替换旧版本,而不存在任何主要问题)。
有时候,ABI的变化是不可避免的。 发生这种情况时,任何使用该库的程序都将无法工作,除非它们被重新编译为使用该库的新版本。 如果ABI变化但API不变,那么新旧版本库有时称为“源兼容”。 这意味着虽然为一个库版本编译的程序不能与另一个编译器一起工作,但如果重新编译,为其中一个编写的源代码将为另一个编译。
出于这个原因,图书馆编写者往往试图保持他们的ABI稳定(以尽量减少中断)。 保持ABI稳定意味着不改变函数接口(返回类型和数量,类型和参数顺序),数据类型或数据结构的定义,定义的常量等。可以添加新的函数和数据类型,但是现有的函数和数据类型必须保留一样。 如果将一个16位数据结构字段扩展为32位字段,那么使用该数据结构的已编译代码将无法正确访问该字段(或其后的任何字段)。 在编译过程中访问数据结构成员会被转换为内存地址和偏移量,并且如果数据结构发生变化,那么这些偏移量将不会指向代码期望它们指向的内容,并且结果最好是不可预测的。
除非您希望人们使用汇编与您的代码进行交互,否则ABI不一定是您明确提供的内容。 它也不是特定于语言的,因为(例如)C应用程序和Pascal应用程序在编译后将使用相同的ABI。
编辑:关于您在SysV ABI文档中关于ELF文件格式章节的问题:包含此信息的原因是因为ELF格式定义了操作系统和应用程序之间的接口。 当你告诉OS运行一个程序时,它希望程序以某种方式被格式化,并且(例如)期望二进制文件的第一部分是一个ELF头部,其中包含特定内存偏移处的某些信息。 这是应用程序如何向操作系统传递有关自身的重要信息。 如果使用非ELF二进制格式(例如a.out或PE)构建程序,那么期望ELF格式应用程序的操作系统将无法解释二进制文件或运行该应用程序。 这是为什么Windows应用程序无法在Linux机器上直接运行(或反之亦然)而无需重新编译或在可从一种二进制格式转换为另一种格式的某种类型的仿真层内运行的一大原因。
IIRC,Windows当前使用可移植可执行文件(或PE)格式。 维基百科页面的“外部链接”部分包含更多关于PE格式信息的链接。
另外,关于您关于C ++名称修改的注意事项:ABI可以为C ++编译器定义一种“标准化”方式来进行名称修改,以实现兼容性。 也就是说,如果我创建了一个库并且开发了一个使用该库的程序,那么您应该可以使用与我不同的编译器,并且不必担心由于不同的名称修改方案而导致生成的二进制文件不兼容。 如果你正在定义一个新的二进制文件格式或者编写一个编译器或链接器,这真的只能用。
如果您知道程序集以及操作系统级别的工作方式,那么您就符合某个ABI。 ABI控制参数如何传递,返回值的位置。 对于许多平台,只有一个ABI可供选择,在这些情况下,ABI只是“工作方式”。
然而,ABI也管理着类如何在C ++中进行布局。 如果您希望能够跨模块边界传递对象引用,或者想要混合使用不同编译器编译的代码,则这是必需的。
另外,如果您有一个可以执行32位二进制文件的64位操作系统,那么对于32位和64位代码,您将拥有不同的ABI。
通常,链接到同一个可执行文件的任何代码都必须符合相同的ABI。 如果您想使用不同的ABI在代码之间进行通信,则必须使用某种形式的RPC或序列化协议。
我认为你正在努力将不同类型的接口挤进一组固定的特性中。 例如,一个接口不一定要分成消费者和生产者。 接口只是两个实体交互的约定。
ABI可以(部分)ISA不可知的。 某些方面(例如调用约定)依赖于ISA,而其他方面(例如C ++类布局)则不会。
一个明确定义的ABI对编写编译器的人非常重要。 没有明确定义的ABI,就不可能生成可互操作的代码。
编辑:一些说明澄清:
应用程序二进制接口(ABI)与API类似,但函数不能在源代码级调用。 只有二进制表示可以访问/可用。
ABI可以在处理器架构级别或OS级别上定义。 ABI是编译器的代码生成器阶段所遵循的标准。 该标准是由操作系统或处理器修复的。
功能:定义独立于实现语言或特定编译器/链接器/工具链进行函数调用的机制/标准。 提供允许JNI或Python-C接口等的机制
现有实体:机器代码形式的函数。
消费者:另一种功能(包括另一种语言中的一种,由另一种编译器编译或由另一个链接器链接)。
链接地址: http://www.djcxy.com/p/41887.html