ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

AnyPS5的TLS移植全解:PS5线程本地存储如何在重链接后正确重定位

2026/10/7 8:32:11 拓冰建站 浏览量
AnyPS5的TLS移植全解:PS5线程本地存储如何在重链接后正确重定位 AnyPS5的TLS移植全解PS5线程本地存储如何在重链接后正确重定位【免费下载链接】AnyPS5Tool for automatic PS5 executables porting to Linux and Windows项目地址: https://gitcode.com/GitHub_Trending/an/AnyPS5AnyPS5 是一款自动将 PS5 可执行文件移植到 Linux 和 Windows 的工具它通过重链接器relinker把 PS5 的 ELF 直接转换为目标系统的原生格式无需模拟或额外的运行时进程。其中最难啃的骨头之一就是 TLSThread Local Storage线程本地存储——同一个变量每个线程看到的值不同。本文将带你完整看懂 AnyPS5 如何在重链接之后把 PS5 程序的 TLS 正确重定位到 Linux 和 Windows 两种截然不同的平台上。一、什么是 TLS为什么移植它会这么难先用一句话解释 TLS程序里有一类变量每个线程都拥有自己独立的一份互不干扰。比如每个线程各自记录的渲染状态、每线程日志缓冲区等都属于 TLS。在 x86-64 架构上访问 TLS 通常借助特殊的段前缀Linux 的fs:、Windows 的gs:配合重定位来完成。问题来了ELFPS5 模块的格式用PT_TLS程序头段加 TLS 重定位类型DTPMOD / DTPOFF / TPOFF来描述线程本地存储PEWindows 格式则用 TLS 数据目录、线程索引、回调表来组织访问 TLS 的指令形态完全不同。也就是说PS5 程序里的 TLS 访问代码原封不动搬到 Windows 上根本无法工作。AnyPS5 的重链接器必须读懂源模块的 TLS再在输出模块里重建一套等价机制。这正是 core/relinker 的核心职责之一。二、第一步从 ELF 中识别并校验 TLS 段一切从读取输入模块开始。重链接器的GuestImageReader会逐条扫描程序头类型 7 的头即PT_TLS段会检查它是否唯一、FileSize ≤ MemorySize、对齐是 2 的幂对符号表里每个STT_TLS类型 6符号校验其偏移与大小确实落在 TLS 段内越界直接报错对每条 TLS 重定位Linux 的 16/17/18 类型确认要么无符号且模块确实没有 TLS 段要么符号必须是 TLS 符号否则抛出Invalid guest TLS relocation。这套严格校验的意义在于与其等到游戏跑起来才崩溃不如在转换阶段就给出精确定位的错误信息。相关逻辑见 GuestImageReader.cpp 和 TLS 符号与重定位校验。三、Linux 目标保留 ELF 语义交给平台动态链接器移植到 Linux 时策略最省力——输出还是 ELFTLS 机制天然兼容。AnyPS5 在构建 Guest 模块时做了一个关键判断每个模块默认 UsePlatformTlsResolver 真 除非该模块集合中已有游戏导出了自己的 TLS 解析符号 NID vNe1w4diLCs。翻译过来就是默认走平台 TLS 解析器——让 Linux 动态链接器用标准的PT_TLS 重定位流程为每个模块的每个线程分配 TLS 块DTPMOD/DTPOFF 重定位由宿主直接解析如果游戏自己实现了 TLS 解析导出了对应符号则尊重游戏逻辑把 TLS 解析交还给 Guest 代码避免两套机制打架。这一行判断位于 GuestModuleBuilder.cpp随后随GuestRuntime传给 GuestModuleWriter 写出 Linux 版本。另外模块之间还有依赖排序拓扑排序源码位置保证带 TLS 的模块加载顺序确定、不出现循环依赖。四、Windows 目标把gs:指令改写成PE TLS 访问Windows 端则是重头戏全部由 WindowsTlsBuilder.cpp 完成。它的工作可以拆成四步1. 扫描 TLS 指令。用 x86 指令解码器逐条解码可执行段找出所有带gs:段前缀的内存访问。只放行两种形态mov reg, gs:[disp32]TLS 加载和mov gs:[0x28], imm32写入栈保护Cookie其余一律报错。2. 组装 PE TLS 目录。新建一个.gtls段内部布局完全对齐 Windows TLS 结构字段说明偏移 0TLS 模板起始地址偏移 8模板结束地址偏移 16线程索引每个模块加载后拿到唯一值偏移 24TLS 回调表偏移 48生成的存根代码地址TLS 回调入口模板本身由 WindowsTlsTemplateBuilder 从 ELF 的PT_TLS段生成对齐位、回调地址都会写入重定位表保证加载器在任意基址下都能修正。3. 生成取指针存根。Windows 线程要拿到 TLS 基址得走两步先读线程索引再从 TEB 的0x30处取出该模块的 TLS 块。AnyPS5 为每个原始 TLS 访问点生成一小段存根代码放入.gtcode段用mov eax, [index]; mov rax, gs:[rax0x30]等指令完成解析并妥善保存/恢复现场寄存器。4. 原位补丁跳转。最后把原gs:指令整条覆盖为jmp其余字节填充nop跳到对应存根——原始代码的调用者无感知TLS 访问却已在 Windows 语义下正确重定位。此外回调入口还处理了ProcessAttach/ProcessDetach回调参数 1/2在进程首次加载时为每个线程初始化 TLS 块。一个值得注意的细节Windows 上跨模块的 TLS 导入必须找到对应的 Guest TLS 导出否则直接报错 Windows guest TLS import requires a guest TLS export——Windows 加载器无法像 Linux 那样事后动态解析 Guest 之间的符号所以这一步只能在转换期完成。五、怎么验证 TLS 移植是对的项目自带一套针对 TLS 的测试脚本全部位于 core/relinker/relinker/tests/test_guest_tls.py端到端测试。构造两个带 TLS 的 Guest 模块重链接后加载断言两个模块的线程索引互不相同first ! second并检查输出的 PE 里 TLS 数据目录索引 9正确存在test_empty_tls.py游戏链接器有时会输出一个空的PT_TLS占位段测试确保它不会在 Windows 侧生成多余的 TLS 目录test_tls_function_coverage.py、test_tls_diagnostics.py覆盖 TLS 函数调用路径与错误诊断信息的质量。这套转换期校验 加载期验证的双保险是 AnyPS5 处理这类易错重定位的通用思路。六、小结TLS 移植的完整链路把全文串起来AnyPS5 处理 TLS 的链路非常清晰识别——GuestImageReader 从 ELF 中找出PT_TLS段、TLS 符号与重定位并严格校验决策——GuestModuleBuilder 决定用平台解析器还是游戏自带解析器重建——Linux 侧保留 ELF TLS 语义Windows 侧由 WindowsTlsBuilder 生成 PE TLS 目录 解析存根并把gs:指令原位改写为跳转验证——测试脚本确认输出模块的 TLS 索引唯一、目录结构正确。理解了这条链路你也就理解了重链接移植中最隐蔽的一类问题是如何被系统性解决的。想继续阅读项目文档入口使用指南、构建说明、兼容性列表。【免费下载链接】AnyPS5Tool for automatic PS5 executables porting to Linux and Windows项目地址: https://gitcode.com/GitHub_Trending/an/AnyPS5创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考