可以在x86和ARM上同时运行OS内核的构建吗?

时间:2012-08-02 23:36:37

标签: x86 kernel arm cpu instruction-set

我的意思是:这个版本(包括x86和ARM架构驱动程序)可以在x86计算机上运行,​​并且可以在其他ARM设备上运行。

我现在知道,没有这样的CPU支持这两个指令集。但从理论上讲,它会实现吗?上电时,CPU可以检查程序所在的指令集?

5 个答案:

答案 0 :(得分:4)

有可能。

除了戴夫和其他海报的答案之外,我写了一个python脚本,它将生成将在x86和ARM上运行的代码技巧,它将采用不同的路径,具体取决于启动的内容。

我不熟悉x86,请原谅我,如果这不起作用。

import sys
import struct
import math

armClobberReg = 0
armShift = 31

if (armClobberReg>15):
    sys.stderr.write("Error! ARM clobber register is invalid\n")
    sys.exit(-1)
if (armClobberReg == 15):
    sys.stderr.write("Warning: r15 will be clobbered on ARM\n")
if (armShift & 1 != 1 or armShift > 31):
    sys.stderr.write("Warning! ARM shift is invalid. Using 31 instead\n")
    armShift = 31

jmpOffset = (armClobberReg<<4)|(armShift>>1)
jmpAndEqNopInstruction = struct.pack("<BBBBI",0xE9, jmpOffset,0,0,0xE1A00000)
armNoOp = struct.pack("<I",0xE1A00000)
x86NoOp = struct.pack("c","\x90")

asmOut = jmpAndEqNopInstruction

asmArmTxtOut = "{0:08x}: andeq r{1}, r0, r9, ror #{2}\n".format(0, armClobberReg, armShift)
asmArmTxtOut+= "{0:08x}: nop\n".format(4)

asmx86TxtOut = "{0:08x}: jmp {1:x}\n".format(0, jmpOffset)
asmx86TxtOut+= "          ... (ARM instructions)\n"

i = math.floor((jmpOffset + 5)/4) - 2
armPc = 8
while i>0:
    asmOut += armNoOp
    asmArmTxtOut+= "{0:08x}: nop <replace with your arm instructions>\n".format(armPc)
    armPc+=4
    i-=1

asmOut = asmOut.ljust(jmpOffset + 5, chr(0xff))
asmOut += x86NoOp

asmx86TxtOut += "{0:08x}: nop <replace with your x86 instructions>\n".format(jmpOffset + 5)
asmArmTxtOut += "          ... (x86 instructions)\n"


sys.stderr.write("x86 disassembly: \n"+asmx86TxtOut+"\n")
sys.stderr.write("ARM disassembly: \n"+asmArmTxtOut+"\n")

sys.stderr.write("ARM code length limited to {0} instructions\n".format(int(math.floor((jmpOffset + 5)/4) - 2)))

sys.stdout.write(asmOut)
sys.stderr.write("Wrote opcodes to stdout\n\n")

在ARM上,第一条和第二条指令被解释为andeqnop指令,而在x86上,它被解释为jmp指令。

  • ARM反汇编:

    ARM disassembly result

  • x86反汇编:

    x86 disassembly result

您可以将自己的操作码追加到相应的内核中。

答案 1 :(得分:2)

让我们假设它可以完成。需要做什么?

好吧,你需要整个内核编译两次,一次使用x86,一次使用ARM操作码(汇编后的汇编程序)。那么,我们所需要的只是一个小程序,它可以查询我们所在的CPU,然后分支到x86版本或ARM版本。

哎呀,有一个引导捆绑问题。您要使用哪两个操作码来确定要使用的版本? ARM或x86 - 记住它需要在两者上运行。

可能可能。也许分支指令的编码是ARM上的nop或其他东西。所以现在我可能能够让x86和ARM的第一条指令不同 - 其中一条分支短距离我现在知道它是x86和从那里跳到我的x86内核。另一个不会接受分支,然后会转到下面的代码,然后分支到ARM版本(反之亦然)。

这将是一个很棒的代码技巧。

但你为什么要那样做呢?你没有使用内存的一半内核(也许你可以将它交换到磁盘)。而且你也可以从一开始就编译正确的目标。 (另外,我不确定是否有任何工具可以让你编译两个内核并将它们放在一个图像中,但是如果你攻击自己的链接器就可以完成。)

答案 2 :(得分:1)

我不这么认为,有可能在两个指令集中编写内核,并且有一个特殊的启动代码,在两个架构上执行不同的操作,从而为架构启动适当的内核。

答案 3 :(得分:1)

这主要是引导加载程序中的支持问题,以及操作系统在加载后执行的操作。这不仅在理论上是可行的,版本10.6.x-10.7.x的OSX内核(/mach_kernel)也可以作为通用的i386 / x86_64二进制文件:

$ file /Volumes/KernelDebugKit/mach_kernel
/Volumes/KernelDebugKit/mach_kernel: Mach-O universal binary with 2 architectures
/Volumes/KernelDebugKit/mach_kernel (for architecture x86_64):  Mach-O 64-bit executable x86_64
/Volumes/KernelDebugKit/mach_kernel (for architecture i386):    Mach-O executable i386

10.5.x内核甚至作为i386 / PowerPC通用二进制文件出现:

$file /Volumes/KernelDebugKit/mach_kernel
/Volumes/KernelDebugKit/mach_kernel: Mach-O universal binary with 2 architectures
/Volumes/KernelDebugKit/mach_kernel (for architecture i386):    Mach-O executable i386
/Volumes/KernelDebugKit/mach_kernel (for architecture ppc): Mach-O executable ppc

引导加载程序(在OSX的情况下,Apple的EFI固件实现(x86)或OpenFirmware(ppc))将需要支持“胖”二进制格式,并能够决定并运行正确的格式。当然,一旦内核被加载,它需要以兼容的格式提供操作系统其余部分的整个支持基础结构,以便做任何有用的事情。

请注意,旧版本的OSX甚至附带了“Rosetta”,这是一个运行时二进制翻译系统,用于在x86 / x86-64 CPU上运行PowerPC二进制文件。

要明确的是,内核的x86和ppc版本存储在同一个文件中完全不相关。

答案 4 :(得分:0)

我认为这不会成真。我的理由是: - 编译程序的两个版本更容易,在安装过程中,它可以决定是在ARM还是x86平台上。

  • 如果您正在查看32位命令。使用了很多它们,您需要将指令集加倍,这会降低CPU的效率。如果你运气不好,32Bit指令集将满足你的需求,所以你必须改为33Bit,这将是非常尴尬的。

  • 我真的不明白你为什么要这样做。这只会导致效率低下