我知道 Linux 或 Windows 之类的操作系统是用 C/C++ 编写的,并编译为给定的架构(例如 AMD64)以生成适合该架构的机器代码。
我的问题 -
- 为什么二进制代码需要单独的规范 - Linux 使用 ELF 而 Windows 使用可移植可执行格式?
- 如果没有这种二进制格式规范,是否可以创建操作系统和在该操作系统上运行的程序?
- 二进制格式是:依赖于架构、依赖于操作系统,还是两者兼而有之?
- 二进制格式是否仅适用于可执行文件还是也适用于操作系统代码?
答案1
您可能已经猜到了,可执行格式不仅仅包含机器代码。例如,它们可以:
指定操作系统的元数据,例如可执行文件适用于哪种体系结构。此元数据包括标题文件的。
指定程序布局在内存中。在现代操作系统中,大多数可执行文件不会以单个块的形式加载到内存中 - 它们通常有许多单独的区域/部分/段其中一些段将包含可执行代码。其中一些段将包含不可变数据,如文本字符串。其中一些段将被指定为可写内存,用于程序堆。
不同的程序对这些部分的大小有不同的要求(请求)。这些都在标题中指定。
有些格式还允许你嵌入电子签名,这可以验证二进制文件的来源。
- 为什么二进制代码需要单独的规范 - Linux 使用 ELF 而 Windows 使用可移植可执行格式?
其原因主要是历史原因,除非有令人信服的理由需要切换,否则操作系统往往会坚持使用其现有的“本机”(或“默认”)格式(例如,在 NT 3.1 中从 DOS MZ 格式转换为 PE,在 Linux 1.2 中从 a.out 转换为 ELF,以及多年来在各种 Unix 中从 COFF 转换为 ELF)。
需要注意的是,底层机器代码取决于 CPU 架构,但除此之外(系统调用和链接库除外),在操作系统之间基本上是可移植的。事实上,现代 Windows 和 Linux 可以运行这两种可执行文件格式:ELF 可执行文件将通过 WSL 在 Windows 上运行,而 PE 可执行文件将通过 WINE 在 Linux 上运行。
- 如果没有这种二进制格式规范,是否可以创建操作系统和在该操作系统上运行的程序?
我们回到这些格式的主要目的。如果没有元数据告诉操作系统在哪里加载程序的各个部分,大多数现代可执行文件都无法运行。一些非常古老的格式,如串口几乎包含纯代码,但不是特别灵活并且已经不再受欢迎。
实际上,操作系统根本不需要存在。在硬件层面,假设存在(传统)BIOS,BIOS 将简单地从磁盘上的特定位置(MBR)开始执行,它可以是任意的机器代码,然后接管并启动操作系统或执行其喜欢的任何其他操作。(您可以将 MBR 本身视为二进制格式,尽管它与可执行代码没有直接关系。)然而,更现代的 UEFI 确实指定了更复杂的可执行格式 (PE)。
- 二进制格式是否依赖于体系结构、操作系统,还是两者兼而有之?
实际上取决于格式。有些格式假定特定的体系结构。其他格式允许您从标头中指定的“魔法数字”列表中选择体系结构。还有一些格式完全与体系结构无关(例如 Java 和 .NET/CIL 字节码)。
同样,格式通常不会对操作系统施加任何限制,尽管操作系统会受到其可以(本机)识别和执行的格式的限制。当然,核心操作系统之上的兼容层可以执行核心操作系统可能无法识别的其他格式(例如 JVM、.NET/CLR、WSL&WINE 等)。
- 二进制格式是否仅适用于可执行文件还是也适用于操作系统代码?
大多数现代操作系统的很大一部分只是“普通”可执行文件的集合。但是,操作系统的某些部分是“特殊的”,不一定使用与其他部分相同的格式。通常,这仅适用于引导加载程序和内核。
举一个非常常见的例子,传统的 BIOS 引导加载程序将不是可以是 Linux 和 Windows 使用的 ELF 或 PE 格式。Linux 内核通常构建在ELF 派生格式GRUB 引导加载程序可以加载,但它可以采用不同的格式以兼容所使用的引导加载程序。Linux 内核还支持EFI 存根模式,它包含最小的 PE/COFF 标头,以兼容直接 UEFI 启动。
答案2
该格式的主要用途是将程序加载到内存中,这由加载器。
- 为什么二进制代码需要单独的规范 - Linux 使用 ELF 而 Windows 使用可移植执行格式?
礼貌回答:因为操作系统不同,有不同的要求。Unix 人员回答:因为微软喜欢重新发明(方形)轮子。
- 如果没有这种二进制格式规范,是否可以创建操作系统和在该操作系统上运行的程序?
是的,但仅限于那些非常简单的程序,一个相当基本的操作系统,可以运行一些简单的程序,这些程序不需要“重新定位”,也不需要链接到任何外部代码。
- 二进制格式是否依赖于体系结构、操作系统,还是两者兼而有之?
无,ELF 格式用于许多操作系统和架构。
- 二进制格式是否仅适用于可执行文件还是也适用于操作系统代码?
在Linux中,可启动内核可能不是ELF,但内核模块使用ELF格式。