macos - Wine64 是如何应对 macOS 的?

标签 macos assembly x86-64 wine

十年来,这一直是一个主要障碍。这是reported as impossibleForum talks referred to issues related to setting and restoring GSWine HQ FAQ仍然指ABI incompatibility page这不是实时维基页面,而是新闻存档链接。

Wine 2.0 announced macOS 64-bit support 。但是……怎么办?这难道不是所有 macOS 黑客都应该知道的事情吗?对于任何 x86-64 黑客来说,也许有一些优雅(或肮脏)的技巧本身就很有趣。

最佳答案

主要障碍是操作系统控制下的 CPU 维护的 GS 段基地址 (GS.base) 发生冲突。

在 64 位 Windows 上,GS.base 用于保存每个线程的线程环境 block (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 的地址,因此它们是这样找到的。

Apple 自此慷慨地永久保留了这两个插槽,供 Wine 等用途使用。 ttyname() 现在使用不同的插槽。

也就是说,如上所述,这个解决方案只是部分的。某些应用程序直接使用 %gs 相对地址(位于 0x300x58 以外的偏移量)访问 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

关于macos - Wine64 是如何应对 macOS 的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53244454/

相关文章:

objective-c - 如何从 cocoa 的 super View 中删除imageview?

macos - 如何在 NSWindow 中显示工作 TableView

c - 了解二进制炸弹第二阶段的汇编代码

c - 如何将.text段以外的段中的执行代码放到.text段的中间

c - 汇编:Intel x86-64 汇编中的 CMOVB 指令

python - 安装 Caffe 时遇到问题

macos - SpriteKit Node.intersectsNode() 方法在奇怪的情况下不检测交叉点

assembly - ASM : operand type mismatch for `cmp'

assembly - 减法后 SBB RCX、RCX 的进位标志的使用

assembly - 汇编程序给出错误 :/a.:无法执行二进制文件:Exec 格式错误