由高级语言生成的机器指令将适用于提供您进行的调用的库的调用约定,包括任何系统调用(尽管这些通常包装在某处的用户空间库中,因此有关如何进行系统调用的细节可能没有必要)。
此外,它适用于目标指令集架构,但有一些例外(例如,必须注意关于指针大小、原始类型、结构布局、C++ 中的类实现等的假设)。
文件格式将规定必要的挂钩/公开可见的功能和数据,以使操作系统能够将您的代码作为进程执行,并将进程引导到所需的状态。如果您熟悉 Windows 下的 C/C++ 开发,子系统的概念决定了引导级别、提供的资源和入口点签名(通常main(int, char **)
在大多数系统上)。
有一些很好的例子说明了高级语言、指令集架构和可执行文件格式的选择如何影响在任何给定系统上运行二进制文件的能力:
汇编语言必须针对特定的 ISA 进行编码。它们使用特定于 CPU 类型系列的指令。如果这些 CPU 支持给定的指令集,这些指令可能适用于其他 CPU系列。例如,x86 代码在一定程度上可以在 amd64 操作系统上工作,并且肯定可以在运行 x86 操作系统的 amd64 CPU 上工作。
C 抽象了 ISA 的许多细节。一些明显的例外包括指针大小和字节序。各种众所周知的接口,将通过 libc 提供到预期的级别,例如printf
、main
、fopen
等。这些包括预期的寄存器和堆栈状态,以便进行这些调用,使 C 代码能够在不同的操作系统和架构上工作而无需更改。可以直接提供其他接口,也可以通过将特定平台包装到预期的接口中来提供其他接口,以增加 C 代码的可移植性。
Python 和其他类似的“虚拟化”语言在另一个抽象级别上运行,同样也有一些例外,例如特定平台上不存在的功能或字符编码差异,可以在许多系统上运行而无需修改。这是通过为许多不同的 ISA 和操作系统组合提供统一的接口来实现的,但代价是性能和可执行文件大小。