Compiler construction 了解不同平台对编译器的需求

Compiler construction 了解不同平台对编译器的需求,compiler-construction,operating-system,Compiler Construction,Operating System,我正在努力学习整个构建链是如何工作的,这样我就能更好地理解在构建/链接/编译等过程中发生的事情 我遇到的一个问题是:如果编译器将源代码转换为本机程序集,为什么同一个程序不能在不同的操作系统上运行?程序集不是直接由CPU运行吗?因此,只要是相同的体系结构,每个操作系统上都应该运行相同的机器代码,不是吗?为什么不呢 编辑:到目前为止,大多数答案都是关于调用操作系统的API。这显然是个问题。我的问题是关于机器代码的问题。它是否直接传递给CPU?如果我用汇编语言编写程序,我还需要为每个操作系统分别编译吗

我正在努力学习整个构建链是如何工作的,这样我就能更好地理解在构建/链接/编译等过程中发生的事情

我遇到的一个问题是:如果编译器将源代码转换为本机程序集,为什么同一个程序不能在不同的操作系统上运行?程序集不是直接由CPU运行吗?因此,只要是相同的体系结构,每个操作系统上都应该运行相同的机器代码,不是吗?为什么不呢


编辑:到目前为止,大多数答案都是关于调用操作系统的API。这显然是个问题。我的问题是关于机器代码的问题。它是否直接传递给CPU?如果我用汇编语言编写程序,我还需要为每个操作系统分别编译吗?(侧重点:如果使用标准C++ CIN/CUT,是依赖于OS的,编译为直接汇编I/O,还是答案取决于编译器?)

,因为,一方面,与操作系统的接口能力在平台之间不一致。即使在Linux/x86、Windows和Mac/Intel(可能都使用相同的CPU)之间,操作方式也可能有很大的不同

因此,虽然编译器可能会生成可以工作的对象文件,但当您将这些对象链接到特定于平台的库时,它们本身就变得不可移植

一个例子是内存分配。当您希望在UNIX下从操作系统请求更多内存时,可以使用
brk
sbrk
库函数。这不是C标准库的一部分,更确切地说是一个特定于UNIX的库


另一方面,Windows可能会提供一个
Win32GetMem
函数来做同样的事情。

是的,机器代码直接由CPU运行。但是,即使是32位的“x86”指令集(即机器代码)也经过了多年的修改。但一般来说,为体系结构编译的代码应该在其他系统上运行。一个更大的问题是,在不同的操作系统中编译的编译器和操作系统支持不同的二进制格式(例如ELF和COFF)、不同的动态链接器(在分发二进制文件后,在运行时链接*.so、*.dll和*.dylib文件),并为使用操作系统提供的功能提供不同的函数集和库


例如,可以通过单一UNIX规范/IEEE Std.1003.1(POSIX)来解决不同的功能集,该规范规定在所有操作系统中为各种操作系统任务提供一组单一的功能(不幸的是,并非所有操作系统——ahem、Windows——都符合)。关于二进制格式(以及CPU指令集体系结构),处理这一问题的一种方法是分发一些更高级的二进制格式(字节码),然后对目标指令集和二进制格式进行实时转换(尽管这更多的是关于在执行时进行更改……这仍然需要完成)。例如,低级虚拟机(LLVM)提供了这种转换。

是的,它提供了。例如,这就是在Wine下在Linux中运行Windows应用程序的方法。您可以出于多种原因直接运行该程序。例如,可执行文件的格式在不同的系统中是不同的,所以系统通常不知道如何加载和执行彼此的可执行文件。除此之外,大多数程序都需要调用系统例程和一些库函数,在这里我们讨论的是关于如何在每个系统中执行的完全不同的协议集。

你说得对,编译器只关心为特定的目标CPU生成正确的汇编指令。但是编译器并不是独立的——应用程序通常必须与主机操作系统接口才能正常运行

因此,问题不在于编译器本身,而在于每个操作系统提供的一组标准库,用于执行访问文件、分配内存或与图形窗口系统交互等常见任务。例如,Windows XP和Solaris x86的代码将被编译为同一组机器代码指令,但这些代码必须进行不同的调用才能与操作系统接口


专有编译器仅与用于它们的操作系统的头文件和库捆绑在一起。其他更不可知的编译器(如GNU GCC)确实共享大量代码,用于跨不同操作系统编译到相同的CPU类型。

这归结于操作系统的和


不同的操作系统提供了不同的、以及不同的机制来调用这些系统调用。例如,POSIX提供了
fork
execv
来创建新进程,而Windows提供了
CreateProcess

此外,在装配层面也存在差异。您使用什么汇编代码来调用函数?不同的操作系统期望不同的性能。操作系统也不一定同意可执行二进制文件的格式,也不同意动态链接等其他机制

另一个要考虑的问题是并发性以及操作系统是如何处理的。一些操作系统在内核级别识别线程,而另一些则不识别。有些人可能更喜欢使用多个流程,有些人可能使用完全不同的模型。API不同,抽象也可能不同。例如,一个操作系统可能使用锁和信号量,另一个操作系统可能使用消息传递。

您的问题“因此每个操作系统上都应该运行相同的机器代码,只要它是相同的体系结构,否?”是不正确的。 机器代码在硬件上运行,而不是在操作系统上运行。 操作系统向用户/系统程序提供服务,这些服务在每个操作系统中的实现方式不同。比如说,为了论证起见,如果您要从arch“A”上的OS“X”获取程序的机器代码,并将其直接馈送到具有相同弧的OS“Y”的系统