《Linux系统编程(第2版)》——1.2 API和ABI

1.2 API和ABI

程序员都希望自己实现的程序能够一直运行在其声明支持的所有系统上。他们希望能在自己的Linux版本上运行的程序也能够运行于其他Linux版本,同时还可以运行在其他支持Linux体系结构的更新(或更老)的Linux版本上。

在系统层,有两组独立的影响可移植性的定义和描述。一是应用程序编程接口(Application Programming Interface,API),二是应用程序二进制接口(Application Binary Interface,ABI),它们都是用来定义和描述计算机软件的不同模块间的接口的。

1.2.1 API
API定义了软件模块之间在源代码层交互的接口。它提供一组标准的接口(通常以函数的方式)实现了如下抽象:一个软件模块(通常是较高层的代码)如何调用另一个软件模块(通常位于较低层)。举个例子,API可以通过一组绘制文本函数,对在屏幕上绘制文本的概念进行抽象。API仅仅是定义接口,真正提供API的软件模块称为API的实现。

通常,人们把API称为“约定”,这并不合理,至少从API这个术语角度来讲,它并非一个双向协议。API用户(通常是高级软件)并没有对API及其实现提供任何贡献。API用户可以使用API,也可以完全不用它:用或不用,仅此而已!API的职能只是保证如果两个软件模块都遵循API,那么它们是“源码兼容”(source compatible),也就是说,不管API如何实现,API用户都能够成功编译。

API的一个实际例子就是由C标准定义的接口,通过标准C库实现。该API定义了一组基础函数,比如内存管理和字符串处理函数。

在本书中,我们会经常提到各种API,比如第3章将要讨论的标准I/O库。1.3节给出了Linux系统编程中最重要的API。

1.2.2 ABI
API定义了源码接口,而ABI定义了两个软件模块在特定体系结构上的二进制接口。它定义了应用内部如何交互,应用如何与内核交互,以及如何和库交互。API保证了源码兼容,而ABI保证了“二进制兼容(binary compatibility)”,确保对于同一个ABI,目标代码可以在任何系统上正常工作,而不需要重新编译。

ABI主要关注调用约定、字节序、寄存器使用、系统调用、链接、库的行为以及二进制目标格式。例如,调用约定定义了函数如何调用,参数如何传递,分别保留和使用哪些寄存器,调用方如何获取返回值。

尽管曾经在不同操作系统上为特定的体系结构定义一套唯一的ABI,做了很多努力,但是收效甚微。相反地,操作系统(包括Linux)往往会各自定义自己独立的ABI,这些ABI和体系结构紧密关联,绝大部分ABI表示了机器级概念,比如特定的寄存器或汇编指令。因此,在Linux,每个计算机体系结构都定义了自己的ABI。实际上,我们往往通过机器体系结构名称来称呼这些ABI,如Alpha或x86-64。因此,ABI是操作系统(如Linux)和体系结构(如x86-64)共同提供的功能。

系统编程需要有ABI意识,但通常没有必要记住它。ABI并没有提供显式接口,而是通过工具链(toolchain),如编译器、链接器等来实现。尽管如此,了解ABI可以帮助你写出更优化的代码,而如果你的工作就是编写汇编代码或开发工具链(也属于系统编程范畴),了解ABI就是必需的。

ABI是由内核和工具链定义和实现的。

时间: 2024-10-22 22:57:28

《Linux系统编程(第2版)》——1.2 API和ABI的相关文章

《Linux系统编程(第2版)》——第1章 入门和基本概念 1.1 系统编程

第1章 入门和基本概念 摆在你面前的是一本关于系统编程的书,你将在本书中学习到编写系统软件的相关技术和技巧.系统软件运行在系统的底层,与内核和系统核心库进行交互.常见的系统软件包括Shell.文本编辑器.编译器.调试器.核心工具(GNU Core Utilities)以及系统守护进程.此外,网络服务.Web服务和数据库也属于系统软件的范畴.这些程序都是基于内核和C库实现的,可以称为"纯"系统软件.相对地,其他软件(如高级GUI应用),很少和底层直接交互.有些程序员一直在编写系统软件,而

《Linux系统编程(第2版)》——导读

前言 这本书是关于Linux上的系统编程."系统编程"是指编写系统软件,其代码在底层运行,直接跟内核和核心系统库对话.换句话说,本书的主题是Linux系统调用和底层函数说明,如C库定义的函数. 虽然已经有很多书探讨UNIX上的系统编程,却很少有专注于探讨Linux方面的书籍,而探讨最新版本的Linux以及Linux特有的高级接口的书籍更是凤毛麟角.此外,本书还有一个优势:我为Linux贡献了很多代码,包括内核及其上面的系统软件.实际上,本书中提到的一些系统调用和系统软件就是我实现的.因

《Linux系统编程(第2版)》——2.12 结束语

2.12 结束语 本章讨论了Linux系统编程的基础:文件I/O.在Linux这样遵循一切皆文件的操作系统中,了解如何打开.读.写和关闭文件是非常重要的.所有这些操作都是传统的UNIX方式,很多标准都涵盖它们.

《Linux系统编程(第2版)》——1.4 Linux编程的概念

1.4 Linux编程的概念 本节给出了Linux系统提供的服务的简要概述.所有的UNIX系统,包括Linux,提供了共同的抽象和接口集合.实际上,UNIX本身就是由这些共性定义的,比如对文件和进程的抽象.管道和socket的管理接口等等,都构成了UNIX系统的核心. 本概述假定你对Linux环境很熟悉:会使用shell的基础命令.能够编译简单的C程序.它不是关于Linux或其编程环境的,而是关于Linux系统编程的基础. 1.4.1 文件和文件系统文件是Linux系统中最基础最重要的抽象.Li

《Linux系统编程(第2版)》——1.5 开始系统编程

1.5 开始系统编程 这一章着眼于Linux系统编程的基础概念并从程序员视角探索Linux系统.下一章将讨论基本的文件I/O,这当然包括读写文件,但是由于Linux把很多接口以文件形式实现,因此文件I/O的至关重要性不仅仅是对于文件而言,对于Linux系统的很多其他方面亦是如此. 了解了这些基础知识后,可以开始深入探索真正的系统编程了.我们一起动手吧.

linux系统编程之文件与I/O(六) fcntl函数与文件锁

一.fcntl函数 功能:操纵文件描述符,改变已打开的文件的属性 int fcntl(int fd, int cmd, ... /* arg */ ); cmd的取值可以如下: 复制文件描述符 F_DUPFD (long) 设置/获取文件描述符标志 F_GETFD (void) F_SETFD (long) 设置/获取文件状态标志 F_GETFL (void) F_SETFL (long) 获取/设置文件锁 F_GETLK F_SETLK,F_SETLKW 其中复制文件描述符可参见<linux系

LINUX系统编程 LINUX 虚拟内存

LINUX 虚拟内存 以32位操作系统为例子,因为64位系统虚拟地址过大为2^64,32位仅仅为2^32=4G更利于描述,但是原理东西都一样 这首先要从程序和进程之间的关系开始,我们一般写好一段C\C++代码编译后仅仅为可执行文件假设为a.out,我们 运行a.out的时候,这个才叫进程,进程是OS级别抽象的实体(PCB task_struct结构体),为程序运行进行各种检查和 系统资源分配,一个PCB包含部分信息如下: (摘至刑文鹏LINUX系统编程讲义) * 进程id.系统中每个进程有唯一的

《Linux系统编程(第2版)》——1.3 标准

1.3 标准 UNIX系统编程是门古老的艺术.UNIX编程的基础理念在几十年来一直根深蒂固.但是,对于UNIX系统,变化却是无处不在.各种行为不断变化,特性不断增加.为了使UNIX世界变得有序,标准化组织为系统接口定义了很多套官方标准.虽然存在很多这样的官方标准,但是Linux没有遵循任何一个标准.相反地,Linux致力于和两大主流标准兼容:POSIX和单一UNIX规范(Single UNIX Specification,SUS). 除了其他内容,POSIX和SUS为类UNIX操作系统定义了一套

《Linux系统编程(第2版)》——2.2 通过read()读文件

2.2 通过read()读文件 前面讨论了如何打开文件,现在一起来看如何读文件.在接下来的一节中,我们将讨论写操作. 最基础.最常见的读取文件机制是调用read(),该系统调用在POSIX.1中定义如下: 每次调用read()函数,会从fd指向的文件的当前偏移开始读取len字节到buf所指向的内存中.执行成功时,返回写入buf中的字节数:出错时,返回-1,并设置errno值.fd的文件位置指针会向前移动,移动的长度由读取到的字节数决定.如果fd所指向的对象不支持seek操作(比如字符设备文件),