Answers:
普通的已编译程序确实可以在CPU上“直接运行”,但是程序不能在真空中运行:
许多程序依赖于外部动态加载的库(DLLs
或.so
库)。链接它们的方式取决于编译器/链接器,并且每个OS都有不同的标准。但是,也有“静态链接”程序提供所有自己的代码。
现代操作系统无法完全控制正在运行的程序的计算机。程序依赖于“系统调用”来进行I / O,访问硬件以及诸如信号之类的事情并进入睡眠状态。可用的服务和接口由操作系统定义。操作系统还控制允许程序使用系统的哪些部分(内存,寄存器,中断)。
GUI程序还必须在图形用户环境中工作,以便在屏幕上绘制自己。但是您可能已经考虑过了。
由于这些原因,与OS无关的应用程序必须依赖某种“虚拟机”,例如java运行时提供的那种。至关重要的是,VM为OS资源(I / O,信号等)提供了标准接口。当然,java或python也会解释“字节码”,而不是处理Intel指令集的怪癖。但这是一个不同的故事。
不同的操作系统也具有不同的功能。Windows具有I / O完成端口,Linux没有。FreeBSD有kqueue,Linux没有。Linux有能力,Windows没有。他们也有不同的方式来做相同的事情-您打开文件时传递了哪些参数?他们按什么顺序?您如何具体调用操作系统的“打开文件”功能?
通常,由于其应用程序二进制接口(ABI)的差异,程序不兼容。
程序不直接在CPU上运行吗?
不!这是操作系统的工作,可以防止应用程序在CPU上“直接”运行。通常,在最低级别(即构建OS API的级别)上,应用程序与操作系统的内核交互。
是否因为编译后的程序本身需要引用操作系统特定的库?
是的。编写了许多OS库来促进与操作系统本身的接口,但是有很多跨平台的。这些隐藏了与开发人员的低级OS接口,并假定该OS的编译版本将在运行时可用(请参见下文)。
尽管可以跨平台的方式编写库,但是在编译时不能跨平台运行它们。仍然需要针对特定目标操作系统重新编译它们,以再次利用操作系统(内核)的特定基础组件。
一个操作系统与另一个操作系统的已编译程序有什么区别?
最后,可执行文件本身通常包含非常特定的二进制加载标头等等,例如Windows 的PE可执行文件格式[.exe,.dll等...],Linux的ELF文件格式[none,.o,.so等等...])。这些还可以包括用于加载特定软件库的已编译OS特定二进制文件的代码。
最后,从程序员的角度来看:调用Convention。编译后的代码以给定的方式(即通过寄存器或堆栈)以非常特定的顺序将变量传递给函数。即使这样,也需要就谁负责“清理”函数调用(调用方或被调用方?)达成共识。尽管有几种标准且使用广泛的x86调用约定,但某些操作系统可能不支持某些约定(这是ABI的一部分)。