这是十年来的主要障碍。是reported as impossible。 Forum talks referred to issues related to setting and restoring GS。 Wine HQ FAQ仍指ABI incompatibility page,它不是实时Wiki页面,而是新闻存档链接。
Wine 2.0 announced macOS 64-bit support。但是……怎么了?是不是所有macOS黑客都应该知道的东西?对于任何x86-64黑客来说,也许都是一些有趣的优雅(或肮脏)技巧。
答案 0 :(得分:6)
主要障碍是与CPU在操作系统控制下维护的GS段基地址(GS.base)冲突。
在64位Windows上,GS.base用于保存每个线程的线程环境块(TEB)结构的地址。 Windows应用程序希望使用%gs
相对地址访问TEB。这是硬编码到应用程序代码中,而不是在API函数后面。
在macOS上,GS.base用于保存线程struct _pthread
的线程本地存储区域的基础,该区域是Pthreads实现的内部实现细节。对于Mac应用程序而言,将%gs
相对访问进行硬编码嵌入到其中并不常见,但是某些系统库确实这样做。
在Linux上,GS.base可用于64位应用程序以用于其自身目的。因此,Wine只需使用操作系统提供的机制对其进行设置。 Wine在macOS上无法做到这一点。操作系统不仅不提供任何机制来执行此操作,而且如果Wine可以,它将破坏系统库。 (这也会给上下文切换上的内核带来潜在的问题,并且/或者内核可能无法还原Wine可能设置的任何值。)
我们发现的解决方案只是部分解决方案。 TEB结构中最常访问的字段是“自身”字段(%gs:0x30
)和用于线程本地存储实现的字段(%gs:0x58
)。通常,如果应用程序需要访问其他字段,则它们会先读取self字段,然后再引用该字段。
在macOS上,%gs:0x30
和%gs:0x58
对应于线程本地存储区的特定插槽。它们是Apple保留的一部分(而不是应用程序使用的部分)。我们发现这些插槽之一未使用。另一个用于C库中的ttyname()
函数。碰巧,Wine从不调用该函数,也没有理由指望它用来执行此操作的任何系统库。
因此,Wine只是在那些%gs
相对位置上拨出适当的值。因此,当64位Windows应用程序代码读取它们时,它将得到所需的内容。 Wine分配的实际TEB位于其他位置(在堆分配的内存中),但是应用程序在他们期望是TEB self字段的位置找到了TEB的地址,因此他们以这种方式找到了它。
此后,Apple一直将这两个插槽永久保留用于Wine的用途。 ttyname()
现在使用另一个插槽。
如上所述,该解决方案仅是部分解决方案。某些应用程序使用%gs
相对地址以0x30
或0x58
以外的偏移量直接访问TEB的其他字段。当他们这样做时,他们会得到垃圾值和/或覆盖系统其他部分使用的值。因此,Wine对64位Windows应用程序的支持在macOS上并不完整。某些此类应用程序将崩溃或行为异常。幸运的是,这种情况很少发生,因此在实践中并不是什么大问题。
作为参考,以下是实现此解决方案的提交:
http://source.winehq.org/git/wine.git/?a=commit;h=7501942008f91a9a137fe598ce5ce7cb47de5522 http://source.winehq.org/git/wine.git/?a=commit;h=3d8efb238808a519902e047d8673237debb0f0a2