这一直是十年来的主要障碍。据报道,这是不可能的。 论坛讨论提到了与设置和恢复 GS 相关的问题。 Wine HQ FAQ 仍然指的是 ABI 不兼容页面,它不是实时 wiki 页面,而是新闻存档链接。
Wine 2.0 宣布支持 macOS 64 位。但是……怎么办?这难道不是所有 macOS 黑客都应该知道的事情吗?对于任何 x86-64 黑客来说,也许有一些优雅(或肮脏)的技巧本身就很有趣。
在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 结构中最常访问的字段是“self”字段 (
%gs:0x30
) 和线程本地存储实现的字段 (
%gs:0x58
)。通常,如果应用程序需要访问其他字段,它们首先读取 self 字段,然后引用该字段。在 macOS 上,%gs:0x30
和
%gs:0x58
对应于线程本地存储区域的特定槽。它们属于苹果公司保留的部分(而不是应用程序使用)。我们发现其中一个插槽未被使用。另一个用于 C 库中的 ttyname()
函数。碰巧的是,Wine 从不调用该函数,并且也没有理由期望它使用的任何系统库会这样做。因此,Wine 只是在那些 %gs
相关位置上设置适当的值。因此,当 64 位 Windows 应用程序代码读取它们时,它会获得所需的内容。 Wine 分配的实际 TEB 位于其他地方(在堆分配的内存中),但应用程序在它们期望成为 TEB self 字段的位置找到 TEB 的地址,因此它们是这样找到的。
苹果公司慷慨地永久保留了这两个插槽,供 Wine 等用途。ttyname()
现在使用不同的插槽。
也就是说,如上所述,这个解决方案只是部分的。某些应用程序直接使用%gs
相对地址(偏移量不是
0x30
或 0x58
)来访问 TEB 的其他字段。当他们这样做时,他们会得到垃圾值和/或覆盖系统其他部分使用的值。因此,Wine 对 64 位 Windows 应用程序的支持在 macOS 上并不完整。某些此类应用程序会崩溃或出现异常行为。幸运的是,这种情况很少发生,因此在实践中不是什么大问题。作为参考,以下是实现此解决方案的提交:
https://gitlab.winehq.org/wine/wine/-/commit/7501942008f91a9a137fe598ce5ce7cb47de5522https://gitlab.winehq.org/wine/wine/-/commit/3d8efb238808a519902e047d8673237debb0f0a2