我一直想知道可执行二进制文件实际上是如何工作的。编译总是被表述为
获取源代码并将其翻译成机器语言
但这到底意味着什么呢?即:
- 我可以将二进制文件从计算机 A 移动到计算机 B 并期望它能正常工作吗?(假设我还移动了相应的库)
- 每个可执行二进制文件是否都适合于特定的处理器?
- 可执行二进制文件中包含什么样的信息?
- 为什么 Windows 上的可执行文件可以在任何 Windows 版本上启动?(如果它们能正常工作那就另当别论了)
- 为什么我不能在 Windows 上运行 Linux 可执行文件?这与内核有关吗(与处理器无关)?
请记住,我对处理器和编译器的了解有限,对汇编一无所知。
答案1
- 不一定。如果它是为了可移植性而构建的并且平台兼容,那么可以(例如,64 位版本的 Windows 能够执行 32 位和 64 位 Windows 可执行文件,但不再能执行 16 位可执行文件)。
- 不一定。它们是为特定指令集制作的。由于这些通常是扩展,并且具有向后兼容性,因此您可能在较新的处理器上运行较旧的文件,但不一定反过来。例如,为 Windows 95 编译的程序可能仍会在今天的硬件上运行,但您无法在旧的 Windows 95 机器上运行为今天的硬件编译的程序。但是,如果两台机器运行完全不同的指令,则可执行文件将不兼容(例如 Intel 与 ARM)。
- 这是依赖于平台的,有多种格式具有不同的标题和内容,但基本上总是有某种标题作为索引,告诉操作系统在哪里找到特定的东西(例如主入口点)。
- 他们实际上不能(见上面的#2)。
- 首先,Windows 和 Linux 的可执行文件使用不同的格式。但即便如此,它们之间还是存在差异,例如整个环境和提供的平台 API/库。例如,Linux 可执行文件通常会尝试与窗口管理器(如 X11)通信,而 Windows 程序则会尝试调用 Windows API。但是,有办法让这些事情正常运作。据我所知,旧版本的 Windows(NT?)实际上有 POSIX 扩展,因此您可以运行一组有限的 Linux 程序,尽管我从未真正尝试过或仔细研究过。另一方面,对于 Linux,有 Wine 等工具会尝试模拟 Windows 环境,提供 API 文件、路径转换等。它不是完整的模拟(就像使用虚拟机一样)。
答案2
仅在非常受控的情况下:两台计算机必须具有兼容的处理器和操作系统。
不是特定处理器,而是一组兼容的处理器。例如,为兼容 x86 而编译的文件,没有扩展名,将在每个 Intel 或 AMD x86 或 x64 处理器上运行,前提是操作系统兼容。
首先是编译步骤中的机器代码。除此之外,还有一些其他所谓的“部分”,例如资源(有没有想过,为什么可执行文件在 Windows 上有专用图标,即使它没有运行,但只是显示在资源管理器中)、二进制兼容性描述等。
这是 1. 的副作用:只要操作系统提供与可执行格式的兼容性,就可以启动它。现代 Windows 版本提供了一系列兼容性:DOS、Win16、Win32、Win64、dotnet 是最重要的。
操作系统为可执行文件提供了一个执行必不可少的环境。Linux 和 Windows 之间的环境差别很大。这意味着您不能直接在一个操作系统上运行可执行文件。目前正在进行的项目旨在弥补这一差距:WINE 项目旨在允许在 Linux(和其他操作系统)上启动 Windows 可执行文件,而 Cygwin 项目旨在使 Linux 软件可以在 Windows 上运行。Cygwin 的目标不是二进制兼容性,而是允许重新编译未修改的源代码。
重要的是要理解,可执行文件(例如.exe)是不是编译过程的结果 - 它是链接过程,它将编译的输出与创建我在 3 中描述的内容所需的其他要素结合起来。