为什么我们需要针对不同的平台(例如Windows/Linux)进行编译? [英] Why do we need to compile for different platforms (e.g. Windows/Linux)?

查看:319
本文介绍了为什么我们需要针对不同的平台(例如Windows/Linux)进行编译?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经了解了有关CPU/ASM/C的基础知识,并且不了解为什么我们需要针对不同的OS目标以不同的方式编译C代码.编译器所做的是创建汇编代码,然后将其汇编为二进制机器代码.当然,由于指令集架构不同,因此每个CPU架构(例如ARM)的ASM代码也不同.

I've learned the basics about CPUs/ASM/C and don't understand why we need to compile C code differently for different OS targets. What the compiler does is create Assembler code that then gets assembled to binary machine code. The ASM code of course is different per CPU architecture (e.g. ARM) as the instruction set architecture is different.

但是,由于Linux和Windows在同一CPU上运行,因此MOVE/ADD/...之类的机器操作应相同.虽然我确实知道有特定于OS的功能,例如打印到终端,但是此功能可以由stdio.h的不同实现提供.而且,我仍然可以创建一个非常基本的程序,该程序只计算a + b而不打印任何内容,因此我不需要任何特定于OS的代码.为什么我仍然需要针对Linux和Windows进行编译,而不仅仅是将.exe-Extension添加到我的Linux可执行文件中?

But as Linux and Windows run on the same CPU, the machine operations like MOVE/ADD/... should be identical. While I do know that there are OS-specific functions like printing to a terminal, this functionality could be provided by different implementations of stdio.h, for example. And still, I could create a very basic program that just calculates a + b without printing anything, so that I do not need any OS-specific code. Why do I still need to compile for Linux and for Windows instead of just adding an .exe-Extension to my Linux executable?

推荐答案

即使CPU相同,仍然存在许多差异:

Even though CPU is the same, there are still many differences:

  • 不同的可执行格式.
  • 可能会使用不同的调用约定.例如 Windows x64在不同于x86-64 System V ABI 的寄存器中传递整数args,并且还有其他一些明显的不同,包括Windows中的调用保留xmm6..15,与其他x86-64不同.
  • 关于堆栈结构的不同约定.类似于Unix的系统具有"红色区域"的概念,以帮助编译器生成更短的代码代码.执行环境必须遵循这样的概念,以避免堆栈损坏.
  • 程序与具有不同ABI的不同标准库链接-字段顺序可能不同,可能存在其他扩展字段.
  • 在C和C ++中,某些数据类型具有与OS相关的大小.例如,在x86_64上,long在Linux上为8字节,在Windows上为4字节. (类型大小和所需的对齐方式以及构成结构/类的布局规则是构成ABI的另一部分.)
  • 标准库可以提供不同的功能集.在Linux libc上,直接提供类似snprintf的功能,但是在Windows上,snprintf可能在头文件中作为static inline函数实现,而该头文件实际上是从C运行时调用另一个函数的.这对程序员是透明的,但会为可执行文件生成不同的导入列表.
  • 程序与OS的交互方式不同:在Linux上,程序可以直接进行系统调用,因为它们被记录在案,并且是所提供接口的一部分,而在Windows上,它们没有被记录在案,而程序应该使用所提供的功能.

  • Different executable formats.
  • Different calling conventions might be used. For example Windows x64 passes integer args in different registers than the x86-64 System V ABI and has several other significant differences, including call-preserved xmm6..15 in Windows, unlike other x86-64.
  • Different conventions regarding stack structure. Unix-like system have a concept of "red zone" to help compiler generate shorter code. Execution environment has to honor such concept to avoid stack corruption.
  • Programs are linked against different standard libraries with different ABIs - field order might differ, additional extension fields might be present.
  • In both C and C++ some data types have OS dependent sizes. For example on x86_64 long is 8 byte on Linux, but 4 bytes on Windows. (Type sizes and required alignments are another part of what makes an ABI, along with struct/class layout rules.)
  • Standard libraries can provide different set of functions. On Linux libc provide functions like snprintf directly, but on Windows snprintf might be implemented as static inline function in a header file that actually calls another function from C runtime. This is transparent for programmer, but generates different import list for executable.
  • Programs interact with OS in a different way: on Linux program might do system call directly as those are documented and are a part of provided interface, while on Windows they are not documented and programs should instead use provided functions.

即使Linux程序仅调用C库的包装函数,Windows C库也不会具有read()ioctl()mmap之类的POSIX函数.相反,Windows程序可能会调用VirtualAlloc,而Linux上没有此程序. (但是使用OS特定系统调用(不仅是ISO C/C ++函数)的程序甚至在源代码级别也无法移植;它们需要#ifdef才能仅在Windows上使用Windows系统调用.)

Even if a Linux program only calls the C library's wrapper functions, a Windows C library wouldn't have POSIX functions like read(), ioctl(), and mmap. Conversely, a Windows program might call VirtualAlloc which isn't available on Linux. (But programs that use OS-specific system calls, not just ISO C/C++ functions, aren't portable even at a source level; they need #ifdef to use Windows system calls only on Windows.)

从理论上讲,这里列出的所有问题都可以解决:可以编写自定义加载程序以支持不同的可执行格式,如果整个程序使用相同的格式,则不同的约定和接口不会引起问题.这就是为什么像Wine这样的项目可以在Linux上运行Windows二进制文件的原因.问题是Wine必须在其他OS提供的功能之上模拟Windows NT内核的功能,从而降低了实现效率.由于使用了不同的不可互操作的界面,因此此类程序与本机程序交互时也会遇到问题.

In theory everything listed here can be resolved: custom loaders can be written to support different executable formats, different conventions and interfaces do not cause problems if the whole program uses the same set of them. This is why projects like Wine can run Windows binaries on Linux. The problem is that Wine has to emulate functionality of Windows NT kernel on top of what other OSes provide, making implementation less efficient. Such program also have problems interacting with native programs as different non-interoperable interfaces are used.

在Windows模型顶部模拟POSIX系统调用(例如fork())时,像Cygwin这样的源兼容性层也可能效率不高.但总的来说,Cygwin比WINE容易得多:程序需要在Cygwin下进行重新编译.它不会尝试在Windows下运行本机Linux二进制文件.

Source-compatibility layers like Cygwin can be inefficient, too, when emulating POSIX system calls like fork() on top of the Windows model. But in general Cygwin has an easier job than WINE: programs need to be recompiled under Cygwin. It doesn't try to run native Linux binaries under Windows.

这篇关于为什么我们需要针对不同的平台(例如Windows/Linux)进行编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆