为什么我们需要为不同的平台(例如Windows / Linux)编译?

时间:2018-01-12 23:51:14

标签: c assembly compilation cpu cpu-architecture

我已经学习了有关CPU / ASM / C的基础知识,并且不了解为什么我们需要为不同的OS目标不同地编译C代码。编译器所做的是创建汇编程序代码,然后汇编到二进制机器代码。 ASM代码当然因CPU架构(例如ARM)而不同,因为指令集架构不同。

但是当Linux和Windows在同一个CPU上运行时,MOVE / ADD / ......之类的机器操作应该是相同的。虽然我知道有一些特定于操作系统的功能,比如打印到终端,但是这个功能可以由stdio.h的不同实现提供。而且,我可以创建一个非常基本的程序,只计算a + b而不打印任何东西,这样我就不需要任何特定于操作系统的代码。为什么我仍然需要为Linux和Windows编译而不是仅仅为我的Linux可执行文件添加.exe-Extension?

4 个答案:

答案 0 :(得分:6)

尽管CPU是相同的,但仍存在许多差异:

  • 不同的可执行格式。
  • 可能会使用不同的调用约定。例如,Windows要求被调用者保存xmm4-xmm5寄存器,而其他操作系统不需要这样。
  • 关于堆栈结构的不同约定。类Unix系统的概念是" red zone"帮助编译器生成更短的代码。执行环境必须遵守这样的概念,以避免堆栈损坏。
  • 程序与具有不同ABI的不同标准库链接 - 字段顺序可能不同,可能存在其他扩展字段。
  • 标准库可以提供不同的功能集。在Linux上,libc直接提供snprintf等函数,但在Windows snprintf上可能会在头文件中实现为static inline函数,该文件实际上从C运行时调用另一个函数。这对程序员来说是透明的,但会为可执行文件生成不同的导入列表。
  • 在C和C ++中,某些数据类型具有与操作系统相关的大小。例如,x86_64 long在Linux上为8字节,在Windows上为4字节。
  • 程序以不同的方式与操作系统交互:在Linux程序上可能直接进行系统调用,因为这些是文档和提供的接口的一部分,而在Windows上它们没有记录,程序应该使用提供的函数。
  • 与操作系统无关,但由不同编译器编译的程序可能无法互操作:可能会使用不同的标准库,例如C ++名称修改可能会有所不同,使得无法将库相互链接,C ++异常实现可能不是-interoperable。
  • 不同的文件系统结构。不仅" \"之间存在差异。在Windows和" /"在Unix喜欢的,但有#34;特殊文件"可能会或可能不会出现像" / dev / null"。

理论上可以解决此处列出的所有内容:可以编写自定义加载器以支持不同的可执行格式,如果整个程序使用相同的一组内容,则不同的约定和接口不会导致问题。这就是Wine之类的项目可以在Linux上运行Windows二进制文件的原因。问题是Wine必须在其他操作系统提供的功能之上模拟Windows NT内核的功能,从而降低实现效率。由于使用了不同的非互操作接口,这样的程序在与本机程序交互时也存在问题。

答案 1 :(得分:1)

除了其他所有内容,即使是相同的指令,即使调用约定也可能不同,即在堆栈或寄存器中放置参数,找到顺序参数,在函数调用中必须保留哪些寄存器,如何返回值从被调用者传递给调用者。

答案 2 :(得分:1)

这就像是说如果我使用相同的字母表所有的书都是相同的生物学教科书和数学教科书是相同的,因为他们使用相同的字母有封面有一些页面,等等。或者我必须滑雪胜地因为他们都使用相同的字母表,因为他们都是关于雪,他们的海报和小册子是相同的。

int main ( void )
{
    return(27);
}

0000000000402cd0 <main>:
  402cd0:   48 83 ec 28             sub    $0x28,%rsp
  402cd4:   e8 d7 e9 ff ff          callq  4016b0 <__main>
  402cd9:   b8 1b 00 00 00          mov    $0x1b,%eax
  402cde:   48 83 c4 28             add    $0x28,%rsp
  402ce2:   c3                      retq   

  00000000004003e0 <main>:
  4003e0:   b8 1b 00 00 00          mov    $0x1b,%eax
  4003e5:   c3                      retq   

细微差别肯定,但关键是这些是两个完全不同的操作系统,程序的进入/退出(上面没有显示的代码的TON变化,而不仅仅是如果主代码在这个计划。

这些是不同的操作系统,它们有不同的调用不同的规则,它们是不同的,指令集是常见的有点无关紧要。它就像是说因为我在linux上运行并使用C作为我的编程语言,然后为arm制作的二进制文件和为x86制作的二进制文件应该是相同且兼容的(因为我说的三件事中有两件是相同的,编程语言和操作系统但不是指令集。或者在您的情况下编程语言和指令集但不是操作系统。)

这甚至指出一个用于Windows的gcc编译程序在所有版本的Windows中都不完全兼容,你只能说“windows”。同样适合linux。它们在自身内部独立于目标而改变,然后操作系统之间存在不兼容的差异。仅仅因为砖和砂浆是相同的,没有两个相同的建筑物。

这是JAVA和Python这类语言的目的,为了画一条线以上这一行是常见的和跨平台的,这条线下面的内容可以是平台和目标特定的,没有理由期待任何形式的跨平台兼容性。如果我们在计算机世界中具有这种兼容性,那么这些语言就不存在了,这些计算机的C编译器或计算机都运行独立于平台的Linux,或者所有运行带有编译器和相同指令集的操作系统。

有一个原因,你下载一些程序,如chrome或7-zip或firefox,handbrake等,根据操作系统和操作系统版本有不同的安装程序和/或二进制文件。指令集通常甚至没有列出,因为它被认为是x86,但是有不同的二进制文件,如果这是微不足道的那么为什么那些长期交付成品的人会提供几种不同的产品版本? / p>

答案 3 :(得分:0)

您可能想查看其他答案。

它的duplicate问题除了它的C而不是C ++

您可以在此处检查编译步骤的过程:

C compilation steps

简而言之,即使C可以跨平台运行,由于编译器不能跨平台编译。