我已经学习了有关CPU / ASM / C的基础知识,并且不了解为什么我们需要为不同的OS目标不同地编译C代码。编译器所做的是创建汇编程序代码,然后汇编到二进制机器代码。 ASM代码当然因CPU架构(例如ARM)而不同,因为指令集架构不同。
但是当Linux和Windows在同一个CPU上运行时,MOVE / ADD / ......之类的机器操作应该是相同的。虽然我知道有一些特定于操作系统的功能,比如打印到终端,但是这个功能可以由stdio.h的不同实现提供。而且,我可以创建一个非常基本的程序,只计算a + b而不打印任何东西,这样我就不需要任何特定于操作系统的代码。为什么我仍然需要为Linux和Windows编译而不是仅仅为我的Linux可执行文件添加.exe-Extension?
答案 0 :(得分:6)
尽管CPU是相同的,但仍存在许多差异:
snprintf
等函数,但在Windows snprintf
上可能会在头文件中实现为static inline
函数,该文件实际上从C运行时调用另一个函数。这对程序员来说是透明的,但会为可执行文件生成不同的导入列表。long
在Linux上为8字节,在Windows上为4字节。理论上可以解决此处列出的所有内容:可以编写自定义加载器以支持不同的可执行格式,如果整个程序使用相同的一组内容,则不同的约定和接口不会导致问题。这就是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)