基本上,我想知道x86-64操作系统如何运行为x86机器编译的代码。我知道第一次引入x64系统时,这不是任何一个功能。在那之后,他们设法做到了这一点。
请注意,我知道x86汇编语言是x86-64汇编语言的子集,而ISA的设计方式是它们可以支持向后兼容性。但令我困惑的是堆栈调用约定。这些约定因架构而异。例如,在x86中,为了备份帧指针,进程将其指向堆栈(RAM)的位置,并在完成后弹出。另一方面,在x86-64中,进程根本不需要更新帧指针,因为所有引用都是通过堆栈指针给出的。其次,在x86架构中,函数的参数在x86-64中由堆栈传递,寄存器用于此目的。
可能x86-64和x64体系结构的堆栈调用约定之间的这种差异可能不会影响程序堆栈的增长方式,只要不同时使用不同的约定,这主要是因为x32函数被其他函数调用x32和x64相同。但是,在某一点上,一个函数(可能是一个系统函数)将调用一个函数,其代码是为具有一些参数的x86-64机器编译的,此时,我很好奇OS(或其他一些控制单元)如何处理让这个功能起作用。
提前致谢。
答案 0 :(得分:3)
设计i386 / x86-64架构的部分方式是CS和其他段寄存器引用GDT中的条目。除了描述当前运行任务的操作模式和权限级别的基数和限制之外,GDT条目还有一些特殊位。
如果CS寄存器引用32位code segment,则处理器将以基本上与i386兼容模式运行。同样,64位代码需要64位代码段。
所以,把这一切放在一起。
当操作系统想要运行32位任务时,在任务切换到它期间,它会将一个值加载到CS中,该值指的是32位代码段。中断处理程序也有与之关联的段寄存器,因此当发生系统调用或发生中断时,处理程序将切换回OS的64位代码段(允许64位OS代码正确运行)和OS然后可以完成其工作并继续安排新任务。
作为关于召集会议的后续行动。 i386或x86-64 都不需要使用帧指针。该代码可以随意使用。实际上,许多编译器(gcc,clang,VS)提供了编译没有帧指针的32位代码的能力。 重要的是调用约定是一致实现的。如果所有代码都希望在栈上传递参数,那很好,但被调用的代码更符合这一点。同样,通过寄存器传递也很好,只需每个人都同意(至少在库接口级别,内部函数通常可以随意执行)。
除此之外,请记住,两者之间的差异并不是真正的问题,因为每个进程都有自己的私有内存视图。然而,一个副作用是32位应用程序无法加载64位dll,而64位应用程序无法加载32位dll,因为进程要么具有32位代码段,要么具有64位代码分割。它不可能都是。
答案 1 :(得分:1)
处理器处于传统模式,但需要当时执行的所有操作都是32位代码。此切换由操作系统处理。
Windows:它使用WoW64。 WoW64负责更改处理器模式,它还提供兼容的dll和注册表功能。
Linux:直到最近,Linux曾经(像windows一样)转而在传统模式下运行处理器,当它开始执行32位代码时,你需要安装所有的32位glibc库,如果它试图与它一起工作就会中断64位代码。现在已经实现了X32 ABI,这应该使一切运行得更顺畅,并允许32位应用程序访问x64功能,如增加号码。寄存器。 See this article on the x32 abi
PS:我对事情的细节不太确定,但它应该给你一个开始。
此外,这个答案与Evan Teran的回答相结合,可能会对所发生的一切进行粗略描绘。