- 逆向工程
- 图形学
【免费下载链接】AnyPS5
Tool for automatic PS5 executables porting to Linux and Windows
本文基于 AnyPS5 仓库中的官方技术债文档 TechnicalDebt.md,完整梳理该 PS5 可执行文件移植工具当前的三类已知债务:构建环境限制、"静默桩"(silently do-nothing 的导出函数)、未知函数签名与语义,以及功能性缺口。读完本文,你能准确判断 AnyPS5 中哪些系统库行为是"验证过的实现"、哪些是"有依据的假设"、哪些是"会静默返回成功但不产生效果"的占位代码,并在调试游戏兼容性问题时快速定位到对应的源码文件。
项目背景:一条硬性契约
AnyPS5 的定位见 README.md:它包含一个 relinker,把 PS5 可执行文件转换为目标系统(Linux/Windows)的原生格式,并实现一组系统 prx 库供动态链接,不做模拟、不引入额外运行时进程。架构总览见 ARCHITECTURE.md:relinker 按 NID 读取导入、过滤未使用的 NID、构建 SysV 动态段;构建期 nid_patcher 再把每个导出重命名为其 NID。
整个项目的核心契约是 TechnicalDebt.md 开宗明义写下的:
项目中每个函数在每一阶段要么精确地做它该做的事,要么抛异常。(README 中亦有对应表述:不支持或意料之外的状态严格抛出
std::runtime_error,what()打印到 stderr 后进程终止。)
但契约存在例外,技术债文档按四个小节把例外全部登记在案:Build(构建限制)、Silent stubs(静默桩)、Unknown function info(未知函数信息)和Functional(功能性缺口)。下面逐节展开。
构建债务:Windows 工具链的硬约束
文档 Build 小节记录了两条债务:
- Windows 构建只支持特定版本的 MinGW:MinGW-w64 GCC 15.2.0(WinLibs 构建
winlibs-gcc15,线程/异常模型为x86_64-ucrt-posix-seh)。BUILD.md 给出了更精确的版本号:release15.2.0posix-14.0.0-ucrt-r7,并要求配置 CMake 前把其mingw64/bin加入PATH。 - Windows 上编译出的 prx 库要求三个运行时 DLL 就近存放:
libgcc_s_seh-1.dll、libstdc++-6.dll、libwinpthread-1.dll。文档明确说明不能把这些依赖静态链接——静态化会导致符号冲突,因此产物旁边必须带齐这三个 DLL。
这条债务的实际影响是:在 Windows 上发布或分发转换结果时,运行目录布局要包含这三个 DLL;而 Linux 构建路径(GCC/G++/binutils + CMake 3.22.1+ + Ninja + C++20,详见 BUILD.md)没有这类限制。
静默桩:返回成功但不产生效果的导出
Silent stubs 小节登记了所有"违反契约"的例外——这些函数既不抛异常,也没有完整实现真实效果,而是返回成功或一个固定的"空路径"结果。按领域分组如下(每一项对应的源文件链接均引自 TechnicalDebt.md)。
对话框族:状态机照转,界面没有
- libSceSaveDataDialog.native:仅登记为静默桩。从源码看,它维护一个静态
g_status状态机(SAVE_DATA_DIALOG_STATUS_NONE/INITIALIZED/FINISHED),sceSaveDataDialogGetResult直接填充RESULT_OK和BUTTON_ID_OK,没有任何 UI。 - libSceMsgDialog.native:
sceMsgDialogOpen在无 UI 的情况下直接以按钮 1 结束,因此sceMsgDialogClose返回NOT_RUNNING;sceMsgDialogInitialize之前的调用结果遵循 libSceMsgDialog 的语义。源码可以印证:sceMsgDialogOpen直接把状态置为COMMON_DIALOG_STATUS_FINISHED(常量定义在 Export.cpp,RUNNING=2、FINISHED=3),result->button_id = BUTTON_ID_OK(即 1),NOT_RUNNING错误码为0x80B8000B。 - libSceCommonDialog:仅登记为静默桩。
- libSceErrorDialog:错误对话框运行了状态机但不显示任何内容,传入
sceErrorDialogOpen的错误码只会被记录日志。 - libSceLoginDialog:运行公共对话框状态机但不显示内容,并报告用户已取消。
- libScePlayerInvitationDialog(在 Functional 节登记):模拟对话框完成但不发邀请,
scePlayerInvitationDialogGetResult报告USER_CANCELED;40 字节的结果布局取自 SharpProspero 的互操作定义,未在标题上验证。 - libSceCdlgPlayerReview:
scePlayerReviewDialogOpen立即完成,结果报告用户取消,行为与sceWebBrowserDialogOpen相同。
头显、外设:只实现"无设备"路径
- libSceHmd:只实现头显未连接的路径——初始化成功、设备查询报告
NotDetected、打开设备返回DeviceDisconnected;头显支持、追踪、渲染及额外 HMD 导出均未实现,SDK 级 ABI 兼容性与游戏内行为未验证。 - libSceHmd2:没有 PS VR2 运行时——
sceHmd2Initialize直接失败,其余导出(包括 libSceVrTracker2 的所有导出)全部抛异常。源码确认了失败码:SCE_HMD2_ERROR_UNSUPPORTED_FEATURE(0x81110016)在 Export.cpp 定义并在 初始化路径 返回。文档同时说明:PPSA01317 在初始化失败时会跳过整个 VR 初始化流程,因此这一桩不阻断该标题。 - libSceMbus:只实现无设备路径——初始化/终止成功、无设备事件、设备查询返回零条目。
- libSceBluetoothHid:只实现无设备路径——初始化、回调注册、设备注册成功,回调因无设备连接永不调用;需要已连接设备的调用抛异常。
- libSceIme(Functional 节):键盘开着时
sceImeKeyboardGetInfo对每个 id 返回0x80bc0023(无资源 id),因为 IME 键盘从不报告已连接设备;sceImeKeyboardSetMode校验模式位但无效果。
音频、视频、网络:成功但无声/无流/不出网
- libSceAudio3d:移植后不产生声音。对象可以保留,但库没有 bed 导出或
sceAudio3dObjectSetAttributes来给对象配音频,因此sceAudio3dPortPush只是按每帧granularity个采样(48 kHz)给队列节拍;sceAudio3dPortSetAttribute接受 late reverb level 与 downmix spread 两个属性并忽略它们。 - libSceTextToSpeech2:没有语音引擎——
sceTextToSpeech2Initialize失败(源码返回内核的EOPNOTSUPP,0x8002002D,见 Export.cpp),其余导出抛异常;PPSA01317 在初始化失败时跳过旁白设置。 - libSceAvPlayer:
sceAvPlayerSetLogCallback接受的回调永不调用(播放器不产生日志消息);sceAvPlayerSetAvailableBandwidth无效果,因为它管辖 HLS 源,而sceAvPlayerAddSource未实现。 - libSceHttp2:没有请求真正到网络,
sceHttp2SetMinSslVersion没有可限制的 TLS 连接,对任意id返回成功(sceHttp2SslEnableOption同理;prosper 对未知 id 返回无效 id 错误)。 - libSceHttp:无请求出网,
sceHttpSetResponseHeaderMaxSize没有可限制的响应头、sceHttpRedirectCacheFlush没有可遗忘的重定向;sceHttpsUnloadCert像sceHttpsLoadCert一样返回成功,尽管后者并不保存证书。 - sceVideoOutOpen:校验 open 参数中 VideoOut 服务线程的优先级与 CPU 亲和性,但不应用它们——端口 present/vblank 线程是宿主线程,guest 的优先级与亲和性到不了宿主调度。从 Output.cpp 可见校验逻辑:
setPriority==1时检查priority落在VIDEO_OUT_SERVICE_THREAD_PRIORITY_HIGHEST..LOWEST区间,affinity非 0 且是VIDEO_OUT_SERVICE_THREAD_AFFINITY_ALL的子集,而函数体并不把二者写入宿主线程。 - libSceAudioPropagation:只实现无声学传播路径——系统把 16 字节头保存在标题的 CPU 内存(非 GPU 内存)中,rooms/portals/sources/materials 是被跟踪的句柄,属性会被校验但无效果,不请求光线,源不报告音频路径;射线结果、路径计算与音频路径只接受空值,否则抛异常;
sceAudioPropagationSourceRender按给定大小向各源输出缓冲区写静音(清零),没有 dry 信号。遮挡、反射、混响缺失,游戏内行为未验证。 - libSceNpCommerce:PS Store 图标显示/隐藏调用与
sceNpCommerceSetPsStoreIconLayout什么都不做。 - libSceSystemService:
sceSystemServicePowerTick、sceSystemServiceReportAbnormalTermination、sceSystemServiceDisableMusicPlayer、sceSystemServiceReenableMusicPlayer返回成功但不做实事——宿主既没有自动关机定时器可重置,也没有系统崩溃上报器可通知,更没有系统音乐播放器可暂停/恢复。 - libSceNpTrophy2:
sceNpTrophy2RegisterUnlockCallback接受的回调永不调用(永远没有奖杯解锁),sceNpTrophy2UnregisterUnlockCallback只返回成功。 - ulobjmgr:不注册任何对象——
_sceUlobjmgrRegisterObject恒定发放 id 0,_sceUlobjmgrUnregisterObject不释放任何东西(与 shadPS4 的做法一致)。
着色器重编译器的 barycentric 缺口
- 在缺少
VK_KHR_fragment_shader_barycentric的硬件上,着色器重编译器不加载 barycentric VGPR:v_interp_p1_f32被丢弃,v_interp_p2_f32改读 Vulkan 插值的属性,因此任何把 barycentric 用于v_interp之外的像素着色器都会得到错误的值。源码印证:InstructionTranslator.cpp 中只有在options.fragmentShaderBarycentricEnabled为真时才把BaryCoordSmooth/BaryCoordNoPerspective内建绑定到像素输入 VGPR;AttributeInstructions.cpp 则对"直通输入却用v_interp_p1/p2读取"的情况直接抛异常。 - sceAvPlayerSetTrickSpeed(libSceAvPlayer):负速把时钟倒着走但不送帧;再次设置正向速度后,播放从回退后的时间点恢复。
Unknown function info:假设的签名与未验证的语义
这一节是清单中最长的部分,逐条登记"能跑但依据不足"的导出。它们的共同模式值得先说清楚,这也是理解每条条目的钥匙:
- 签名来源分几档:aerolib 的 NID 列表(只有函数名,无参数)、标题调用点(PPSA 编号标识的游戏,如 PPSA01317/PPSA12544/PPSA14632/PPSA23566)、跨项目参考实现(shadPS4、KytyPS5、SharpProspero、ampr_emu、OpenAGC、prosper、RPCS3/RPCSX、Mesa、Orbital、fpPS4、etaHEN 等)。
- 验证等级显式标注:"not confirmed on a title / on hardware"(未在标题/硬件上确认)、"unverified"(未验证)反复出现,凡只靠单一参考实现且该实现本身是猜测的,条目会写清"只有 X 有函数体"。
- 拿不准就抛:错误码未知时宁可抛异常也不伪造返回值(如
sceAudioPropagationSourceGetAudioPath、sceHttpSetRequestStatusCallback的调用时机)。
代表性条目:AMPR/AMM/APR 子系统
libkernel 的 Apr 实现 是假设密度最高的一块,文档对 AMPR(异步内存管道)相关导出逐条标注了依据:
- AMPR 计数器访问:
WaitOnCounter_04_00、WriteCounter_04_00、ConstructNop、ConstructMarker的签名与检查取自 ampr_emu 重写(该参考把计数器命令直接交给主机核,不体现效果)。计数器按每个 32 位建模:8 字节访问跨 n(低)与 n+1(高)两个计数器,2/1 字节访问按偏移选半个/一个字节;等待按访问宽度比较(含符号与回绕比较),AND 掩码作用于两侧,原子写在访问范围内回绕。ConstructNop的 type 未被记录。 - AMM map / map direct / unmap:签名与保护掩码(CPU、GPU、AMPR、ACP 读写位)取自 ampr_emu;映射器模型取自 PS5PCEM:
sceAmprAmmGiveDirectMemoryusage 1 把分配的直接内存交给普通 map 取页的池,usage 0 只分配。AMM 虚拟地址范围是 guest 竞技场中首次使用时预留的 32 GiB 区间与 32 GiB 多映射区间(不是主机的范围),范围外映射抛异常;地址、大小与直接偏移必须 16 KiB 对齐;内存类型与 GPU 掩码被忽略;AMPR/ACP 访问按 CPU 访问映射;未映射页退回池并保持保留;提交时先运行完缓冲再返回,提交结果恒 0,失败命令抛异常。 - AMM remap / multimap / 保护变更:签名与保护/掩码检查取自 ampr_emu,效果是从函数名推断的,未在标题上确认。remap 把完整映射范围的每页搬到新地址并保留旧范围;multimap 在第二地址映射同一批页,池页在最后一次映射解除后回到池;对自己的源范围 multimap 抛异常;对未完整映射范围的命令抛异常。
- AMM PRT 范围:签名、检查及其顺序取自 ampr_emu;效果同样从名字推断。无支撑的 PRT 页是带 GPU 读权限的填零页(CPU 读看到零而非缺页,GPU 写会缺页而非被丢弃)。
- APR gather/scatter 读:签名、参数检查与读游标取自 ampr_emu,未在任何标题上确认;gather 读该文件到新偏移并写到下一个目的,scatter 在同一文件继续写到新目的;与 ampr_emu 一致,
sceAmprCommandBufferReset保留该状态;缓冲内未读先 gather/scatter 时抛异常而非返回SCE_AMPR_ERROR_APR_INVALIDGATHERSCATTERSTATE。
代表性条目:单函数级别的假设
- sceHmd2Initialize:主机 PS VR2 不可用时主控机返回什么错误未知;实现借用 libSceHmd 的
UNSUPPORTED_FEATURE(0x81110016)。PPSA01317 传 16 字节全零指针,只测结果非零——所以该假设足够该标题使用。 - sceMbus / libSceDeviceService:签名取自 PPSA01317 的调用:
sceDeviceServiceInitialize(3, 0)、轮询sceDeviceServiceGetEventState(1),bit 0/1 置位时再查询,sceDeviceServiceQueryDeviceInfo_(0x7001, 0, 0, infos, 1, &count, &unknown, 0x70),负结果视为错误、count为条目数。主机无设备:事件状态 0,查询返回 0 且count0。 - sceAppContentDownloadDataGetAvailableSpaceKb:
param.json声明downloadDataSize0 的标题得到 0 KB 与 OK;无下载数据区的主机行为未验证(也可能返回错误)。KytyPS5 不特判,shadPS4 桩为 1048576 KB。 - scePadOpenExt:只处理特殊端口(type 2),且因主机没有特殊手柄而返回
DEVICE_NOT_CONNECTED(0x80920007);主控机是否先开句柄再报断连未知。PPSA01317 传 16 字节参数按 vendor/product id 命名设备(0x0eb7:0x0e04),负结果即跳过用户;其他端口类型抛异常。 - s_setkill(着色器重编译器):对任意立即数解码为
s_endpgm——在 RDNA2(gfx1035)硬件实测,其前的 store 可见、其后的指令不执行;它设置的 KILL 状态位与s_endpgm的可观察差异未验证。 - sceRtcParseDateTime:接受的格式被假定为 ISO 8601 子集
YYYY-MM-DDTHH:MM:SS[.ffffff](T/t/空格分隔符、可选小数秒)加 RFC 3339 时区后缀(Z或±HH:MM),外加 RFC 2822 形态与 asctime 形态(shadPS4 按固定位置解析);星期名不与日期核对,无时区的串按 UTC,形态之外的输入抛异常而非返回解析错误——全部未经硬件验证。 - sceVideoOutRegisterBuffers2:buffer option 8(STRICT_COLORIMETRY)被当作 option 0 呈现,存储值不变,主控机对此做什么未知,只接受 0 与 8。DCC 缓冲(category 1):
dcc_control按 CB_DCC_CONTROL 块布局解释且只接受 bit 0x10026c;dcc_cb_register_clear_color作为清屏 texel,只呈现 32 位值。 - sceVideoOutIsOutputSupported:输出模式编码未知——除默认模式外一律报告不支持(0),
sceVideoOutConfigureOutput返回VIDEO_OUT_ERROR_UNAVAILABLE_OUTPUT_MODE(而不是UNSUPPORTED_OUTPUT_MODE)。PPSA12544 探测0xd000000a,支持则选 7680 像素,否则 3840。 - sceAudio3dObjectReserve:对象 id、
max_objects限制与保留/取消的检查遵循 shadPS4(PS4,唯一有函数体的参考):id 每端口从 1 递增,跳过 0、0xFFFFFFFF 与已用 id,失败保留写 0xFFFFFFFF。 - sceKernelGetModuleInfoFromAddr:0x1A8 字节信息布局遵循 shadPS4 重写;
flags语义未知、只接受 2;id 是sceKernelLoadStartModule句柄或同区间的稳定 id;名称是去掉.guest.prx的宿主文件名;超过 4 个加载段的镜像(转换后可执行文件有 7 个)只报前 4 个;tls_offset为 0、ref_count为 1(宿主加载器两者都不暴露)。Windows 上未实现。 - sceUserServiceGetNpAccountId:无绑定 PSN 账户的用户假定账户 id 为 0 且成功;libSceNpManager 的
sceNpGetAccountIdA对同一问题回答SCE_NP_ERROR_SIGNED_OUT。同文件的sceUserServiceGetUserColor假定默认头像色是蓝(0)。 - sce::Json::Parser::parse:溢出 double 的数字(如
1e309)抛异常——主控机是拒绝文档还是存无穷大未知。 - sceSaveDataTransferringMountPs4 / sceSaveDataDirNameSearchPs4:参数假定为
sceSaveDataTransferringMount与sceSaveDataDirNameSearch的对应参数(KytyPS5 把两个 NID 都绑到 PS5 函数,prosper 在标题上捕获到相同的结果布局)。因为没有 PS4 存档区,mount 返回NOT_FOUND,search 报告零命中。 - NGS2 一族(libSceNgs2.native):mastering voice gain 参数 id
0x30000004取自 PPSA22520、布局取自 shadPS4 的OrbisNgs2MasteringVoiceGainParam,无参考给出单位与范围;2 声道 mastering voice 渲染进 6/8 声道缓冲时假定左右进前两通道、其余静默(PPSA21402 的真实用例);sampler filter 参数0x1000000a只遵循 KytyPS5,voice 在最后一块后继续播放滤波器尾部直到历史归零(1e-20 以下清零)。 - 未知名称的 NID:文档还登记了一串只有 NID 串、名称与签名都未知的导出,例如 libSceNpPartner001 的
7CxI50-xlCk、pMxXhNozUX8(PPSA23566 导入),libScePsml_debug 的0GAw7SmkwII等 9 个,libSceVideoOut 的kP2L8t3j-aM与LibwuIonIBw,libSceAgc 的 ShaderFusion/InterpolantMapping/PacketInfo/DcbFlow/DcbState 若干文件 中的fd5Bp5tGTgo、dolOmWH+huQ、dbOlWdppb4o、V++UgBtQhn0、zARR5aCmkoY、qj7QZpgr9Uw、gQkqkLttcpw、vieBRwlh1Lw等,以及 libSceAjm.native 中 libSceAjmWVorbis 的Z4HDpe1ZEa4、oXShHcqMcX0与 libc 的BnMAMrsfVWo。它们大多以APS5_EXPORT("<nid>", func)形式按 NID 直接绑定(参见 ARCHITECTURE.md 对APS5_EXPORT的说明)。 - 无实现的批量导入:文档末尾成组登记了"被某标题导入、声明无参数"的函数族(AudioIn、Net、Ssl、SystemService、Vdecsw、Ajm、AjmWVorbis、Http2 等),例如 libSceVdecsw 的整组
sceVdecsw*导出、libSceVoice 的sceVoiceSetMuteFlag、libSceCoredump 的sceCoredumpAttach*等,签名均为 unknown。
功能性缺口(Functional):实现存在但模型不完整
Functional 节记录的是"实现了,但主机侧模型与主机存在可观察差异"的行为,按子系统归纳:
内核与进程
- sceNetSendmsg / sceNetRecvmsg:把散集列表拷过单个宿主缓冲,只接受
sceNetSend/sceNetRecv接受的标志;发送控制数据抛异常;接收永远不返回控制数据(msg_controllen0),因为没有支持排入控制数据的套接字选项。 - sceKernelInstallExceptionHandler:记录 handler 后,宿主缺页仍会结束进程——只有
sceKernelRaiseException主动引发的信号会被投递。Unity 的 PS5Util 模块安装 SIGUSR1 handler,读取uc_mcontext.mc_rsp(上下文偏移 0xf8),并向其他线程发 SIGUSR1 以停住它们做 GC。相关限制链(同一文件):sceKernelRaiseException仅 Windows 投递、Linux 上抛异常;handler 的ucontext按 FreeBSD amd64 布局构造(16 字节 sigmask、mcontext在 0x40、mc_rsp在 0xf8),除 PS5Util 读的字段外布局未验证;不查询目标线程的信号掩码;Windows 上只保存/恢复CONTEXT_FULL | CONTEXT_FLOATING_POINT,handler 或入口用 AVX 时 YMM 高半部不保留;通过 APC 到达阻塞在可中断TimedWait的线程,而其他任何阻塞点(含APS5_COARSE_TIMED_WAITS下所有等待与模拟器内部宿主等待)会被重定向、只在等待返回后执行 handler。 - Thread cancellation:未建模——
scePthreadCancel抛异常,因此永远不会有待处理的取消请求,scePthreadTestcancel/pthread_testcancel无动作返回;scePthreadSetcancelstate/scePthreadSetcanceltype设置的取消状态与类型只存储不使用。 - libSceUlt 队列:用预分配的宿主存储替代传入的 guest 工作区;原有大小公式与 512 字节对象布局未验证;等待队列池线程上限与等待者优先级未实现;终结时以
ULT_ERROR_STATE唤醒阻塞的队列调用者。补齐的sceUltQueuePop、sceUltQueueTryPush、sceUltQueueDestroy、sceUltQueueDataResourcePoolDestroy签名是从现有 push/pop 与对象 API 推断的,队列销毁假定以ULT_ERROR_BUSY拒绝阻塞调用者、池耗尽返回ULT_ERROR_AGAIN;非空队列/数据池选项参数因布局未知而抛异常。 - 追加内容(libSceAppContent):不安装不挂载——
sceAppContentAddcontMount对每个 entitlement label 答NOT_FOUND,sceAppContentGetAddcontInfo答DRM_NO_ENTITLEMENT,sceAppContentGetAddcontInfoList报告 0 条。
AGC 驱动:命令包执行的保守边界
- COND_EXEC在同队前序命令完成后才读条件;缺少
PFP_SYNC_ME时,主机图形的 PFP 会提前于 ME 读取,竞态标题会在这里看到更晚的值。 - COND_EXEC 范围内的 flip(CommandValidation.cpp)抛异常:flip 在提交缓冲时随视频输出预留,主机如何撤回被跳过的 flip 未知。COND_EXEC 范围必须整包持有并结束在自己的命令缓冲内;范围内的链式
INDIRECT_BUFFER或REWIND抛异常。 - COND_INDIRECT_BUFFER(
sceAgcCbBranch,Submission.cpp)只支持恒真比较函数;带比较或谓词包抛异常。mode 1 与 2 执行第一个缓冲,假定为 AMD PM4 包的 if-then 与 if-then-else 模式。sceAgcCbBranch 不检查恒真分支的比较地址或空缓冲的地址——PPSA14632 传了未初始化的比较地址与 0 dword 的 null else 缓冲。 - PA_CL_CLIP_CNTL的
DX_LINEAR_ATTR_CLIP_ENA(bit 24)清零被当作置位绘制(Vulkan 的NoPerspective裁剪),清零位在主机的差异无文档。 - **DCC 显示缓冲**只从均匀未压缩或 fast-clear key 呈现;其他 key 与跨待处理镜像的 register-clear key 抛异常。key 按每 256 字节 1 字节读取(驱动模型),不是主机布局。
- 用户数据寄存器:标题从未写入的
SPI_SHADER_USER_DATA_*/COMPUTE_USER_DATA_*寄存器在该 stage 的 RSRC2 计数覆盖它时读作 0(与 Kyty 的零化UserSgprInfo、SharpEmu 的缺寄存器读 0、AMD PAL/Mesa 的初始化一致);主机的值未确认。 - SET_PREDICATION:布尔谓词遵循 Mesa 使用的 AMD PM4 编码——操作 3 读 64 位、操作 4 读 32 位,bit 8 在值非零(clear 时为全零)时执行被谓词化的包,bit 12 提示被忽略;地址低 4 位须清零。查询谓词(Z-pass、原始计数)、被谓词化的 COND_EXEC、谓词化命令缓冲链与 flip 均抛异常。
- 资源注册:注册恒失败于
RESOURCE_REGISTRATION_UNAVAILABLE,因此 owner/resource 查询、sceAgcDriverSetResourceUserData、sceAgcDriverFindResourcesPublic、sceAgcDriverUnregisterAllResourcesForOwner不读参数即返回同一错误(参数列表仿 libSceGnmDriver 对应物,未验证);sceAgcDriverGetResourceRegistrationMaxNameLength写 0xfc 返回 0。 - 着色器注册:任意地址都接受着色器头——PPSA26344 传过偏移 4 字节与偏移 1 字节的头(越出 8 字节边界);主机是否拒绝非对齐未知。
着色器重编译器:数值与访存近似
- MIMG
tfe与lwe(RdnaImageOpDecoder.cpp):数据之后从不写状态 VGPR。硬件上仅当取 texel 命中部分驻留纹理的未映射页、或lwe在 sample/gather 且 LOD 低于 T# 的MIN_LOD_WARN时才写;这里纹理内存恒驻留,lwe在 sample/gather/image_get_lod上抛异常。 - 非归一化 S# 坐标(GuestSamplerResource.cpp):
FORCE_UNNORMALIZED用 VulkanunnormalizedCoordinates采样器,故 S# 的 LOD 范围、LOD bias 与 mip 过滤不生效——只有单层视图时才是精确的。重编译器侧(DescriptorBindingBuilder.cpp)只接受直接寻址、且仅用于无偏移/无比较/无导数/无_a的显式 LODimage_sample,且限于 mip 0 的单层 1D/2D 视图。min/max 归约(FILTER_MODE 1/2)用 Vulkan 的 min/max 归约(与 RADV 编程相同的SQ_IMG_FILTER_MODE值),在 gfx1035 实测而非主机:只归约非零权重 texel,权重取 8 位 subtexel 网格取整后。 - 镜像原子与位宽访问:32_SINT/32_FLOAT 表面的镜像原子通过 R32_UINT 存储视图作用于原始 dword,假定其浮点结果与 32_UINT 表面实测一致;64 位镜像原子需要
VK_EXT_shader_image_int64类特性并作用于 32_32 UINT/SINT/FLOAT 表面。 - LDS 64 位原子(SpirvMemoryInstructions.cpp):两个 dword 在 guest LDS 之后存储的 workgroup 锁下读写,因为 LDS 是没有 64 位原子的 32 位数组——它们只彼此原子,与并发 32 位访问无排序;64 位 GDS 原子抛异常。
ds_wrxchg2*交换指令(SharedMemoryInstructions.cpp):翻译为两次独立的 32/64 位原子交换;RDNA2 硬件(gfx1035 实测)保证同一 wave 或不同 wave 的地址重叠时,所有 lane 的第一次交换先于任何 lane 的第二次——重叠场景下结果可能与硬件不同。offset0 == offset1抛异常,而硬件上是按序两次交换。- sRGB 与转换格式:8_SRGB/8_8_SRGB 在设备不能采样 R8_SRGB/R8G8_SRGB 时,load 返回 bf16 精度、四舍六入五成双的 sRGB EOTF(gfx1035 实测,PS5 的 gfx1013 未测);能采样该格式的设备用自己的解码(如 NVIDIA 的 R8_SRGB 在 256 个码值中 29 个偏 1 个 bf16 步)。转换 unorm 图像(10_11_11_UNORM 等)的采样经 R32_UINT 视图进行,
OpFDiv允许至多 2.5 ULP 偏差,部分驱动不位精确;StoreTexel对双通道格式从 DST_SEL 为 Y 的数据槽写通道 1,而 gfx1035 对 X,Y,Z,W 的 DST_SEL 是从 W 槽写。 - 浮点近似(FloatInstructions.cpp):
v_rcp/v_rsq/v_sqrt/v_log/v_exp/v_sin/v_cos(f32 与 f16)用驱动近似而非主机近似,低位可能不同,只有 NaN/无效/零/无穷及 sin/cos 的精确零点按位挑选;v_fma_f64仅在规约输入下精确融合,次正规输入退化为独立乘加(两次舍入);v_fma_legacy_f32(VOP3 0x140)假定是融合的,未实测——LLVM 把该编码解码为v_mad_legacy_f32,且实测v_mac_legacy_f32(VOP2 0x06)先舍入乘积。 - MODE 寄存器被忽略(ScalarInstructions.cpp):
s_setreg_b32的写入(含浮点舍入/非规格化控制)无效果,s_getreg_b32读 MODE 恒报四舍六入五成双;输出修饰符mul:2/mul:4/div:2按 IEEE 关、f32 次正规 flush(LLVM 图形默认)建模。 - lane 读取语义:宿主 subgroup 窄于 32 lane 时
threadBit读到的是低位 lane 的 EXEC 位;v_readlane_b32与 fetch-inactive 的v_permlane16_b32/v_permlanex16_b32对宿主 subgroup 不持有的 lane 读到未定义数据,而主机读该 lane 的 VGPR。 buffer_load_dwordx2(SpirvMemoryInstructions.cpp):硬件上是单次 64 位访问,不会看到buffer_atomic_swap_x2的一半;只有 8 字节对齐、在界内、glc、且程序具备 64 位存储视图时,才用一次 64 位原子 load 读取,其余 dwordx2 load 是两次 dword load,可能与并发的 64 位写撕裂。
Relinker 侧的已知不完美
--to-intel路径:不降低 RDPRU/MCOMMIT——指令匹配器 直接让重链失败;RIP 相对操作的 SHA-1/SHA-256 指令同样失败重链。指令重写器 的变长路径未被转换器使用:替换不调整 VEX/0F38/0F3A RIP 相对操作数、数据到代码引用(重定位、FDE、跳转表)与段大小,因此每次替换保持指令长度。- VRSQRTPS/VRCPPS 替换:
--to-intel把近似 VEX.128 寄存器形式换成正确舍入的 1/sqrt(x) 与 1/x(AMD 近似表不公开):Intel 对 1/sqrt(1.0) 的近似是 0x3F7FF000,两次牛顿迭代收敛到 0.99999994 而非 1.0,重归一化单位四元数在 PPSA21564 中会变成 NaN 轴(主机不出现);精化结果现在可达精确值,未精化的低位仍可能与主机不同。每个调用点付出线外桩的代价(两次跳转、红区下溢、SQRTPS/DIVPS);256 位、标量、legacy 与内存形式保留原指令,PPSA21564 有 5 个调用点因跳板后无可移动指令而保留原指令。 - 合成测试覆盖:Linux ELF patcher 中
--to-intelstub 的布置位置只有合成测试覆盖;--to-intel的 guest 模块 trampoline 也只有合成 relinker 测试,Linux/Windows 上都没有标题验证过。SSE4a 陷阱模拟在 Windows 上被--to-intel取代,保留到重链标题不带它验证通过为止。Windows PE writer生成的可执行文件在启动时会打开主机——对可玩性不便。 - 着色器重编译时机(Recompiler.cpp):当前发生在转换到 Vulkan 前一刻(带缓存),应移入 relinker 阶段;为此 shader/recompiler 完全独立于 libs/prx 编写(与 BUILD.md 的说明一致:该逻辑是输入数据的纯函数,设计上可集成进任何项目)。
音频、字体与外设输入
- AudioOut2 上下文(AudioOut2Context.cpp):SDL 设备下,grain 的端口缓冲在下次 push 时读取(至少晚 100 微秒),混音在一个 40 ms 的垫层之后播放(队列水位不反映它)。时机参照一个"push 后填缓冲、两次 push 后复用、下一次 push 可能仍写在写中"的标题;标题停止 push 前的最后一个 grain 永远不会被读取或播放。
sceAudioOut2Set3DLatency与sceAudioOut2MasteringInit/SetParam无效果:没有 3D 渲染或 mastering 阶段。sceAudioOut2PortCreate的data_format按 bits 8-11 读声道数(只接受 1/2/6/8/12)、bits 0-6 读采样类型(0 float、1 int16),bit 7 与端口 flags 不解码,bits 12-31 抛异常;12 声道假定按 L R C LFE Ls Rs Lb Rb Ltf Rtf Ltb Rtb 折叠为立体声,无标题或 SDK 头确认声道顺序。 - libSceAudiodec:24 位 PCM 字长(
iBwPcm0)抛异常(布局未知);ATRAC9 解码只有配置与错误测试覆盖,因为没有 ATRAC9 编码器可造 fixture。 - libSceFont:
sceFontOpenFontSet只打开系统字体集的主文件——日语/中文集中的韩文、泰文、阿拉伯文等来自主机其他文件(欧洲集中的阿拉伯文)的字符会被报告为不支持字形;主机文件名沿用 PS4 固件命名,PS5 独有 JG2 集(0x1A......)文件名未知而借用 SSTJpPro 文件;主机文件缺失时加载开放许可的替代字体(Noto Sans、Noto Sans Mono、Noto Sans Thai、Noto Sans CJK),度量不同,文本宽度/行高/换行与主机不同。系统字体 face 由 FreeType 在宿主内存加载(标题的字体内存不够每个 CJK face 约 1 MiB)。字体书写行(WritingLine.cpp)遵循 KytyPS5:run 从左到右逐行推进、无间距;sceFontWritingLineGetOrderingSpace仍抛异常(KytyPS5 的值是占位)。 - libSceKeyboard:
sceKeyboardGetKey2Char转译 101 键(美)布局与 106 键(日)字母数字层,遵循 JIS X 0201——Yen(0x89)与 Ro(0x87)无 Shift 时返回\(0x5C),是否应返回 U+00A5 未验证;Kana LED(bit 4,HID 位置)置位时 106 键布局抛异常(主机返回的假名未知);Ctrl/Alt 不改变字符。
如何把这份清单当作工程工具
从文档的组织方式可以推断出 AnyPS5 维护技术债的工作方法,读清单时建议按以下习惯使用:
- 每条条目都带源码锚点:
Silent stubs与Unknown function info的每一行都链接到具体实现文件(如 core/libs/prx/libkernel/Apr/src/Apr.cpp),定位问题先查清单、再读锚点文件即可。 - 区分三级证据:实测("measured on RDNA2 (gfx1035)"、"PPSA12544 probes..."、"captured by prosper")> 单一参考实现("follows shadPS4/KytyPS5/ampr_emu")> 名字推断("inferred from the names, not confirmed on a title")。凡标注后两者的行为,在关键路径上应按未验证对待。
- 抛异常即边界:清单反复出现"throws instead of returning an error"——错误码未知的导出选择抛
std::runtime_error(与 README.md 的严格异常契约一致),这对调试是好事:静默错误集中在Silent stubs一节里,可穷举。 - 验证手段在仓库内:功能性行为的回归依赖 core/libs/tests(如 GuestHttp、GuestRtc、GuestAudio3dPort、GuestAvPlayer 等)与 core/relinker/tests(如
test_guest_module_directories.py、Amd64OnlyWindowsTests.cpp);文档中"synthetic test only"的表述正是指这些合成测试尚无真实标题覆盖。 - 清单随代码增长:
Unknown function info中"由 PPSAxxxxx 导入、声明无参数"的成组条目会随新标题出现而增加,README 也说明库统计的分母是"项目已知函数"而非全部 PS5 系统函数——阅读时以仓库当前版本为准。
这份清单的价值不在于"项目有多少问题",而在于它把"实现、假设、猜测"的边界精确到单个导出函数,是评估 AnyPS5 兼容性问题归属(是已实现的缺陷,还是登记在案的已知缺口)的第一手依据。
- 逆向工程
- 图形学
【免费下载链接】AnyPS5
Tool for automatic PS5 executables porting to Linux and Windows
相关推荐
k3d 代码库健康审计:技术债、已知缺陷与性能瓶颈全景分析
k3d 代码库健康审计:技术债、已知缺陷与性能瓶颈全景分析 导读 :本文基于 k3d 官方仓库的《Codebase Concerns》审计文档( .planni
云原生容器编排tsParticles 代码库健康度审计:技术债、已知缺陷与性能瓶颈深度解析
tsParticles 代码库健康度审计:技术债、已知缺陷与性能瓶颈深度解析 导读 :本文以 tsParticles 仓库内维护的审计文档 .planning/
前端Starward项目静默启动功能的技术解析
Starward项目静默启动功能的技术解析 在游戏启动器领域,Starward项目提供了一个实用的静默启动功能,这个功能对于希望实现后台启动或计划任务自动运行的
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考