dnn*_*agy 3 c assembly linker compilation machine-code
假设,我有一个用C编写的程序,我有两台相同的计算机,一台运行Windows,另一台运行Linux.由于计算机是相同的,它们的处理器具有相同的指令集,因此编译后的机器代码应该相同.那么为什么我需要两次编译我的程序呢?假设,我不会调用任何与操作系统相关的功能,或者取决于实际操作系统的功能.
机器代码不依赖于OS,对于相同的CPU也是如此.
如果你做了OS不可知的机器代码,在目标CPU模式下(假设x86 32b),并将其加载到某些ROM内存中,那么它将可用,你可以在Windows和Linux中映射那部分ROM(通过完全不同的OS API来映射物理内存并赋予它可执行权限,并跳转到那里..并且ROM中的机器代码将以相同的方式运行.
那么为什么我需要两次编译我的程序呢?假设,我不会调用任何与操作系统相关的功能,或者取决于实际操作系统的功能.
你不必.但通常你需要一些入口点进入你的代码,通常最简单的方法是如何提供通用入口点是遵循OS定义的ABI(应用程序二进制接口),所以例如在32b窗口中你从堆栈中读取参数,并在64b中linux你在寄存器中接收参数(如果可能的话).如果你不调整你的程序序言代码以正确的方式选择参数,那么它将在"其他"操作系统中以错误的输入操作而不是为其编写.
但机器代码本身,CPU指令是相同的.
也就是说,在x86上由于历史向后兼容性,情况有点毛茸茸,所以CPU可以处于16b模式,32b [protected]模式(其中一对加上不同的设置)或64b模式.80386 CPU指令mov eax,1针对16b模式和32b模式具有不同的机器代码编码.
但只要您的目标是相同的CPU模式,相同指令的机器代码就会以相同的方式编译.您只需按照不同的ABI来编写源代码即可.
而且可执行文件......每种格式都不同,它甚至不是"按操作系统",再次由于历史原因,几乎所有x86操作系统都支持几种可执行文件格式,因此机器代码周围的元数据存储在文件中(待使用)在将机器代码加载到内存并将其设置为运行时,通过操作系统完全不同.
实际的例子是linux app wine,它可以执行Windows可执行文件,通过提供假的OS挂钩点来模拟Windows操作系统,并通过了解Windows可执行二进制文件,所以正确地将它们加载到内存中.这种Windows应用程序的机器代码是本机运行的,无需进一步修补.