%gs
相对地址访问TEB。这是硬编码到应用程序代码中而不是在API函数后面。struct _pthread
的线程本地存储区域的基地址,这是Pthreads实现的内部实现细节。Mac应用程序很少硬编码%gs
相对访问,但有些应用程序和系统库会这样做。我们想出的解决方案只是一个部分解决方案。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
相对地址访问TEB的其他字段,偏移量不是0x30
或0x58
。当它们这样做时,它们会获得垃圾值和/或覆盖系统其他部分使用的值。因此,Wine对于macOS上的64位Windows应用程序的支持并不完整。一些这样的应用程序会崩溃或表现不当。幸运的是,它发生得不太频繁,在实践中不是很大的问题。
以下是实施此解决方案的提交记录:
http://source.winehq.org/git/wine.git/?a=commit;h=7501942008f91a9a137fe598ce5ce7cb47de5522 http://source.winehq.org/git/wine.git/?a=commit;h=3d8efb238808a519902e047d8673237debb0f0a2
fs
作为TLS基址。i386 Linux使用gs
基址,但是x86-64 Linux选择了FS,因为在x86-64中,gs
已经对于内核中的syscall
/ [swapgs
](http://felixcloutier.com/x86/SWAPGS.html)是特殊的,内核需要从系统调用入口点找到当前任务的内核栈。 - Peter Cordesarch_prctl(ARCH_SET_GS, ...)
提供了这样的帮助。从另一个线程“窃取”GS是行不通的。重要的是正在运行的线程上下文中的GS.base。一个线程的GS.base对其他线程不可见,对它们没有特殊意义。 - Ken Thomases