【问题标题】:How Linux & windows Program differ [closed]Linux和Windows程序有何不同[关闭]
【发布时间】:2013-11-14 23:53:00
【问题描述】:

我在 GCC 中编译了一个小型“Hello World”程序,它在 Linux 中运行。然后我在程序中添加了 .exe 扩展名,看看它是否适用于 Windows。但它没有用。程序无法在 Windows 中运行的原因是什么。基本上二进制和汇编指令在 windows 和 linux 下编译的程序中是相同的(如果不使用操作系统特定的库)。操作系统只需将程序加载到 RAM 中,处理器就会执行它。那么,为什么它不起作用。

【问题讨论】:

  • 请出示代码
  • @LithuT.V 开个玩笑!
  • @LithuT.V 不需要代码。
  • 我要求提供代码只是为了确定他在没有操作系统支持能力的情况下是如何做到的。
  • 这不起作用的原因有很多。 (系统架构、系统库/头文件、处理器架构链接器 itnerface 实现定义的行为等等......)

标签: c linux windows ram processor


【解决方案1】:

我会把你的问题分解成更小的子集

我在 GCC 中编译了一个小型“Hello World”程序,它在 Linux 中运行。

这是意料之中的,因为系统上安装的常用 GCC 和 binutils 被配置为在执行它们时针对相同的目标和主机进行编译。或者用外行的话来说,它们将生成一个适用于 Linux 内核和 GNU C 标准库(或兼容的 libc)运行时的可执行文件。

也有编译器可以构建程序以在不同类型的操作系统和/或 CPU 架构上运行,而不是它们本身在其上执行。这些就是所谓的交叉编译器,例如,您正在使用它们在您的台式计算机上构建智能手机应用程序。当您使用 Windows Android NDK 创建本机 Android 可执行文件时,实际上是针对 Linux 内核和不同的 CPU(很可能是 ARM 或 MIPS)进行交叉编译。

然后我在程序中添加了 .exe 扩展名,看看它是否适用于 windows。

在这里,您陷入了一个误解,我永远无法理解它为什么会出现在首位。文件名后缀必须与它可以做的任何事情有关。 Windows 使用它在注册表中查找,如何处理它,但仅此而已。在 Windows 中,您可以注册任何您希望被识别为“可执行”的后缀。 Linux(作为 Unixoid)做了一些更简单的事情,但恕我直言,它更强大:每个文件都带有一组标志,如果它可以执行,如果可以,那么谁可以执行。

但是要作为一个可以运行的程序对系统真正有用,需要一些不同的东西,并且所有可执行文件(对于给定的操作系统)共享,无论它们的文件名如何:一种特定的内部格式。 Windows 使用所谓的PE 格式(PE 代表可移植可执行文件,这有点可笑,因为唯一支持它的操作系统是 Windows)。 Linux 和 *BSD 使用 ELF(可执行和链接格式),MacOS X 使用称为 Mach 二进制格式 的东西,向 Intel CPU 的过渡扩展到 Mach 通用二进制 格式.从技术上讲,Mach 内核(MacOS X 的基础)也可以理解 ELF 格式,但在 MacOS X 中没有启用 AFAIK。

虽然这两种文件格式本质上是做同样的事情(描述如何将文件加载到内存中、它依赖于哪些库、必须加载哪些库、加载它们的位置、实际启动程序的哪个点),但它们的结构非常不同。 Windows 不知道如何加载和执行 ELF,Linux 不知道如何加载和执行 PE。

即使其中一方支持另一方,系统仍将缺少程序期望加载和运行的库。至少您需要(操作系统)相关的运行时环境,它负责从操作系统检索启动参数等“平凡”的事情,为操作系统特定的内存管理功能提供接口等等。这些也从根本上说Linux 和 Windows 的区别。

请注意,完全有可能提供一个兼容性包装器,它建立在操作系统特定的东西之上,将其他操作系统模拟到程序中,并且还知道如何加载、链接和启动外部可执行文件。在 Linux 上加载和执行 Windows 程序的包装器称为 WINE,也存在称为 LINE 的相反的东西,它在 Windows 上运行 Linux 可执行文件。

但它没有工作。程序在windows中无法运行的原因是什么。

Windows 与 Linux 不同。它有一个完全不同的系统级 API,它使用不同的二进制格式,甚至像标准输入/标准输出(由 C 标准库定义)这样的基本功能也有很大不同的实现方式。哎呀,他们甚至使用不同的callingconventions

Linux 使用标准的 C 调用约定 (stdcall)。 Windows 主要使用 cdecl 约定,它是 pascal 和 stdcall 约定的混合体。

基本上二进制和汇编指令在 windows 和 linux 下编译的程序中是相同的(如果不使用操作系统特定的库)。

呃,不,他们绝对不是。调用约定的不同会产生不同的程序集。

操作系统只需将程序加载到 RAM 中,处理器就会执行它。

事情没那么简单。该程序还必须“连接”到操作系统,才能做任何有用的事情。您想在控制台上看到打印的字符串吗?然后你必须将它连接到一些操作系统功能,这样做。

在 Linux 中,控制台已经存在,并且有特殊文件 /dev/console/dev/stdin/dev/stdout/dev/stderr,它们在内部与当前的 ptstty 相关联。在进程中,它们总是映射到文件描述符 0、1 和 2。

在 Windows 中,程序可能需要也可能不需要打开自己的控制台窗口(如果它是从 CLI 启动的,它将使用它)。所以它必须调用AllocConsole,如果失败作为后备AttachConsole(parent_PID);然后它可以使用GetStdHandle 来获取标准输入、标准输出、标准错误。这个得到的HANDLEs是任意的,需要连接到C stdio(printf、fwrite等)和C++ iostream的内部实现。

CPU 也不会“神奇地”执行一段二进制文件,只是因为它最终位于 RAM 中的某个位置。操作系统必须创建一个新进程,并且要做到这一点,它必须知道二进制某些重要代码所在的位置(入口点)。这些入口点(除其他外)在二进制文件格式的特殊位置进行描述。正如我已经解释过的,Windows 只理解一种与 Linux 完全不同的可执行二进制格式 (PE)。一旦二进制文件被加载和链接,它就必须真正启动。如上所述,在 Linux 和 Windows 之间启动二进制文件的步骤也不同。

后期编辑,但必须写:

*此外,了解可执行文件的二进制文件在程序启动时根本没有完全加载到 RAM 中是非常重要的。所发生的是,创建了所谓的“虚拟内存映射”。这意味着一个虚拟地址空间是由操作系统创建的,与其他一些数据结构一起这就是通常所说的进程。虚拟地址空间又由一组所谓的“页面”支持,这些页面是映射到实际内存或存储设备的地址空间块。事实上,通常 RAM总是用作磁盘操作的缓存。当程序二进制文件被映射时,虚拟内存页面将始终指向磁盘存储,而 RAM 仅充当缓存。动态分配的内存取自在存储设备上缓存交换空间的磁盘缓存。如果没有交换设备,那么它只是从通用磁盘缓存中获取。*

如您所见,这些是要执行的任务的完全不同的列表。再加上调用约定和二进制格式的差异。

那么,为什么它不起作用。

因为可执行文件不仅仅是惰性汇编指令。程序需要与操作系统对话才能产生有意义的东西。而且 Windows 和 Linux 非常非常不同。

【讨论】:

  • 谢谢 datenwolf 和大家,现在我对如何在操作系统环境下执行可执行文件有了一些了解,但是有没有一本书/电子书更详细地包含所有信息并教导真正发生的事情在编译时进行编码。 &其中深入了解可执行文件和系统调用/系统中断如何工作。
  • Linux 内核是开源的,您可以直接查看或查看有关它的众多书籍之一。 ELF格式可以直接查看specification
  • @user2952250:m0skit0 说了什么。对于 Windows,权威来源是“Windows Internals”technet.microsoft.com/en-us/sysinternals/bb963901.aspx
【解决方案2】:

现代操作系统并不那么容易。如果您获取 Linux 可执行文件,添加 EXE 扩展,然后在 Windows 中运行它,它将无法工作。除了代码和数据之外,现代操作系统在可执行文件中还有很多额外的信息。 Linux 使用ELF executable 格式,Windows 使用EXE format。此格式包括relocation 信息、内存大小、分区和有时仅与使用此可执行格式的操作系统相关的信息。所以仅仅改变文件的扩展名是行不通的。

另外,OS system calls 以及它们的名称也不同。 Linux 使用软件中断 (INT 0x80 IIRC) 进行系统调用,而 Windows uses another system。这意味着您必须为每个目标重新编译,因为甚至系统调用都不是以相同的方式完成的,并且 C 编译器需要针对该目标链接到正确的 libc

【讨论】:

  • 实际上,如果硬件支持快速路径系统调用指令,Linux 不再使用软件中断。
  • @datenwolf 我是这么认为的,但是当我检查源代码(2.4)时确实如此。感谢您的澄清。
  • 2.4 太旧了。是的,那个内核系列依赖于 int 0x80。并且版本 2.6/3.x 中也包含此代码,以支持基于 x86 的体系结构而没有快速路径系统调用功能。然而,在足够现代的发行版和 CPU 上,将使用快速路径。
【解决方案3】:

Linux 和 Windows 可执行文件的主要区别在于格式。 Linux 使用ELF format,Windows 使用PE one

您必须在每个平台上编译您的程序。 MinGW 对于 Windows 来说可能很有趣。

【讨论】:

    【解决方案4】:

    您认为代码应该相同的假设并不完全正确。虽然数学计算的工作原理是一样的,但这是错误的,因为不同的操作系统为程序提供了相同的接口——它们没有。见:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-04
      • 2010-09-30
      • 2017-04-07
      • 1970-01-01
      • 2010-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多