diff --git a/CHANGELOG.md b/CHANGELOG.md index 26e6aea..6bda67e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ All notable changes to **PS5 Web File Manager** are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +> Release artifact for v1.9.1: +> `web-file-mgr-v1.9.1.elf` — size 870 488 bytes (~850 KiB) +> sha256 `24392aff6ddcca4dc0ea969cce356bd693ac52efe8a117d61ee1c814aa43cd07` +> ELF class 64, little-endian, e_machine `0x003e` (x86_64-sie-ps5) +> +> Built on the 7z-complete tree: LZMA SDK decode subset + self-written codec +> chain, 7zAES, and ZIP/RAR/7z volume support. Build-system-only delta vs the +> first v1.9.1 artifact (1 017 864 B): `src/demangle_stub.c` keeps libc++abi's +> Itanium name demangler (105 KiB, only reachable from the uncaught-exception +> path) out of the link, and `-Wl,--icf=all` folds identical functions. +> −15.8% overall with no change to functionality or decompression throughput. +> See `docs/SIZE-OPTIMIZATION.md`. +> > Release artifact for v1.9: > `web-file-mgr.elf` — size 919 440 bytes (~897 KiB) > sha256 `bb8f17e9addc6a9984f611503ca01b51f8984b773d353630da1f25bd1a28a997` diff --git a/HANDOVER.md b/HANDOVER.md index 47e1ddf..32e3f74 100644 --- a/HANDOVER.md +++ b/HANDOVER.md @@ -15,7 +15,7 @@ | 解压引擎 | ZIP / RAR / 7z × 单卷/分卷(6 组合)+ 7zAES / RAR 加密 | | 主机测试 | **ZIP 108 + RAR 27 + 7z 28 = 163 checks,0 失败**(MinGW gcc 16.2.0) | | PS5 构建 | ✅ WSL prospero-clang 18.1.8,一键脚本可复现 | -| ELF 产物 | `web-file-mgr-v1.9.1.elf` · 1,017,864 B · sha256 `05952ac05fb937e8758846cbd8d495a427670e3cfb7f4020d42d4c6fe8c21631` · e_machine=0x003e | +| ELF 产物 | `web-file-mgr-v1.9.1.elf` · 870,488 B · sha256 `24392aff6ddcca4dc0ea969cce356bd693ac52efe8a117d61ee1c814aa43cd07` · e_machine=0x003e(2026-09-20 瘦身后;瘦身前 1,017,864 B,见 `docs/SIZE-OPTIMIZATION.md`) | | GitHub | `main` 已推到 `1fa2f09`;`0d036a7` 待推;`v1.9.1` tag 待重打 | | 唯一功能缺口 | 7z `-mhe=on`(加密头) | diff --git a/Makefile b/Makefile index 666e8d2..cc50ed4 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ HOST_PKG_CONFIG ?= pkg-config # and you can tell at a glance which ELF is on the USB stick. BIN := web-file-mgr-$(VERSION_TAG).elf LINUX_BIN := web-file-mgr-linux-$(VERSION_TAG) -COMMON_SRCS := src/main.c src/websrv.c src/filemgr.c src/file_response.c src/task.c src/upload.c src/download.c src/text.c src/list.c src/space.c src/version.c src/fs_util.c src/json_util.c src/path_util.c src/asset.c src/mime.c src/notify.c src/pkg_installer.c src/pkg_info.c src/extract.c src/zip_extract.c src/rar_extract.c src/zipx_volume.c src/zipx_volstream.c src/zipx_common.c src/sevenz_extract.c src/sevenz_chain.c src/sevenz_volstream.c src/sevenz_mt.c +COMMON_SRCS := src/main.c src/websrv.c src/filemgr.c src/file_response.c src/task.c src/upload.c src/download.c src/text.c src/list.c src/space.c src/version.c src/fs_util.c src/json_util.c src/path_util.c src/asset.c src/mime.c src/notify.c src/pkg_installer.c src/pkg_info.c src/extract.c src/zip_extract.c src/rar_extract.c src/zipx_volume.c src/zipx_volstream.c src/zipx_common.c src/sevenz_extract.c src/sevenz_chain.c src/sevenz_volstream.c src/sevenz_mt.c src/demangle_stub.c PS5_SRCS := $(COMMON_SRCS) src/app_installer.c src/cpu_support_stub.c LINUX_SRCS := $(COMMON_SRCS) BASE_ASSETS := $(filter-out %.dds,$(wildcard assets/*)) @@ -123,7 +123,11 @@ LINUX_TP_OBJS := $(patsubst %.c,linux-obj/%.o,$(THIRD_PARTY_C_SRCS)) \ CFLAGS := -Oz -fno-asynchronous-unwind-tables -fno-unwind-tables -Wall -Werror -ffunction-sections -fdata-sections -Isrc -Ithird_party/minizip-ng/include -Ithird_party/unrar7 -Ithird_party/7z -DVERSION_TAG=\"$(VERSION_TAG)\" -DTITLE_ID=\"$(TITLE_ID)\" CFLAGS += `$(PKG_CONFIG) libmicrohttpd --cflags` -LDFLAGS := -Wl,--gc-sections +# --icf=all: fold byte-identical functions. LLD-only (GNU ld's --icf is +# incomplete), so it stays on the PS5 line -- the linux target never uses +# LDFLAGS. Paired with src/demangle_stub.c this takes the ELF from ~1010 to +# ~850 KiB; see docs/SIZE-OPTIMIZATION.md. +LDFLAGS := -Wl,--gc-sections -Wl,--icf=all LDADD := `$(PKG_CONFIG) libmicrohttpd --libs` LDADD += -lSceIpmi -lSceAppInstUtil -lSceUserService LINUX_CFLAGS := -O2 -flto -Wall -Werror -Isrc -Ithird_party/minizip-ng/include -Ithird_party/unrar7 -Ithird_party/7z -DVERSION_TAG=\"$(VERSION_TAG)\" -DTITLE_ID=\"$(TITLE_ID)\" diff --git a/docs/FORUM-POST-v1.9.1.md b/docs/FORUM-POST-v1.9.1.md new file mode 100644 index 0000000..8e7b020 --- /dev/null +++ b/docs/FORUM-POST-v1.9.1.md @@ -0,0 +1,131 @@ +# PS5 网页文件管理器 v1.9.1(自编译版)发布 + 与上个版本对比 + 使用简介 + +> 这是我自己维护的一个分支版本,基于 owendswang 的 `ps5-web-file-manager` 二次开发。本文讲三件事:**它和上游原版差在哪、我这个版本强在哪、怎么用**。 + +--- + +## 一、它是什么 + +一个在已越狱 PS5 上跑的 HTTP 文件管理器(单文件 ELF 载荷)。局域网内任意浏览器(含 PS5 自带浏览器)打开 `http://:8888/` 就能管理外接 USB 和内置存储:浏览、改权限、上传、下载、原地编辑文本、装/预览 PKG、看图,以及**解压 ZIP / RAR / 7z**。 + +- 版本:**v1.9.1** +- 标题 ID:`FMGR88888` +- 许可证:GPLv3+ +- 目标平台:`x86_64-sie-ps5`(Zen 2,不是 ARM) + +--- + +## 二、和上游原版(owendswang v1.8)对比 + +先说结论:**不是同一条路线,各有胜负手。** + +| 维度 | 上游 owendswang v1.8 | 我的 v1.9.1 | +|---|---|---| +| 一句话定位 | 把 7-Zip 本体做成**外部 helper 进程**,靠 IPC 调用 | **自研 / vendor 解码库,全部内嵌同一进程** | +| 支持的压缩格式 | **30 种**(zip/7z/rar/tar/gz/xz/zst/bz2/cab/arj…) | **3 种**:ZIP / RAR / 7z | +| 部署方式 | **两个文件**,helper 必须放 `/data/wfm/` 指定路径 | **单个 ELF,零外部依赖** | +| 防压缩炸弹(zip bomb) | ❌ 无 | ✅ 压缩比上限 + 1 GiB 下限豁免 | +| 磁盘写满保护 | ❌ 无 | ✅ 解压前按实际剩余空间 `statvfs` 预检 | +| 路径穿越防护 | ❌ 无(交给 7-Zip) | ✅ 有专项测试 | +| 解压中断留残留 | ⚠️ 可能留半成品 | ✅ staging 隔离,失败即清 | +| 解压任务跨重启恢复 | ✅ helper 独立进程,重启不丢 | ❌ 暂无 | +| 内存隔离 | ✅ 独立进程 | ❌ 与主程序共享地址空间 | +| 错误信息详细度 | 中等 | ✅ 含条目名 / errno / 字节数 | +| 解压核心正确性 | 7-Zip 本体(20 年验证) | 自研 7z 链 + 成熟 vendor 库 | + +### 上游原版强在哪 +- **格式多**:30 种,常见游戏包/备份/Mod 里 `.tar.gz`、`.xz`、`.zst`、`.bz2` 都能直接解。 +- **任务恢复**:helper 是独立进程,主程序被系统杀掉或浏览器重开,大包解压不丢。 +- **内存隔离**:解压峰值不影响主文件服务。 + +### 我的版本强在哪 +- **安全护栏齐全**:压缩炸弹、写满磁盘、路径穿越、中断残留——这四项上游一个都没有,而我这边都有实现和测试(测试矩阵 163 项检查,0 失败)。说白了,**一个恶意压缩包不会把你的内置存储搞崩**。 +- **单文件部署**:丢一个 ELF 就行,不用记第二个文件该放哪;helper 丢了功能全废的事在我这不存在。 +- **7z 引擎是硬啃出来的**:上游靠 7-Zip 本体"白嫖",我这边是自己解析 7z folder + 拉式 codec 链,原生支持 BCJ2 反汇编后处理和多 coder 组合,还顺手做了多线程 LZMA2 解码(约 1.37×)和汇编 LZMA 解码器(约 1.26×)。 +- **RAR 用官方 UnRAR 7.20.1**:能解 WinRAR 6.x/7.x 写的 RAR5「v6」归档和多卷 RAR——上游原版的旧引擎在这类文件上会报"归档损坏"。 + +### 我不回避的短板 +- **格式覆盖只有 3 种**,这是最明显的弱项。`.tar.gz`、`.xz`、`.zst`、`.bz2` 你现在还得在 PC 上先解开。这是我接下来增量要补的方向(tar+zlib 已有、xz/lzma 复用 LZMA SDK、bz2/zst 可 vendor 单文件解码器),但**不打算照抄上游的 helper 路线**——那样会丢掉上面那些安全护栏和单文件部署优势。 +- **任务跨重启恢复**和**内存隔离**暂时没有(和"单进程内嵌"的架构取舍有关)。 + +> 一句话:**上游赢在"格式广度 + 进程架构",我赢在"安全 + 部署 + 错误质量"。** + +--- + +## 三、v1.9.1 我做了哪些具体改进 + +- **7z 解压引擎**:自研解码子集 + 拉式 codec 链(`sevenz_chain.c`),支持 LZMA2 / LZMA / BCJ2,覆盖 SDK `SzArEx` 装不下的 5-coder 文件夹。 +- **分卷(多卷)支持**:三种格式都支持分卷,但命名约定不同(引擎按文件名自动识别,打开首个分卷即可): + - **ZIP 分卷**:① 经典多磁盘 `name.z01 … name.zNN … name.zip`(索引目录固定在最后一个 `.zip`);② 7-Zip 字节分割 `name.zip.001 / .002 / …`;③ WinRAR 卷 `name.part1.zip … name.partN.zip`。最多 512 卷。 + - **7z 分卷**:7-Zip 字节分割 `name.7z.001 / .002 / …`,各分卷需等大,打开首个即可。最多 512 卷。 + - **RAR 分卷**:标准多卷 `name.part1.rar / .part2.rar / …`(unrar 自动按名合并)。**注意**:用 7-Zip 切出来的 `name.rar.001` 这种命名**暂不支持**,引擎会提示你先把分卷改名成 `.partN.rar` 再解。 +- **性能三项**(纯解码提速,不影响功能): + - 汇编 LZMA 解码器 ≈ **1.26×** + - 纯 LZMA2 多线程解码(8 线程)≈ **1.37×** + - 移除 ZIP 逐条目 fsync,减少写盘开销 +- **RAR 升级到官方 UnRAR 7.20.1**:RAR5「v6」+ 多卷可用(v1.8 时代在 WinRAR 6/7 文件上报"归档损坏"的问题已消失)。 +- **中英双语界面** + 项目主页右上角可切换语言说明。 + +### 已知缺口(诚实列出) +- 带密码的 ZIP / RAR / 7z:**拒绝解压**(引擎有解密能力,但密码输入 UI/API 还没接,临时先挡掉)。 +- 7z `-mhe=on` **加密头**:暂不支持(需要自研头解析器)。这是 7z 侧唯一已知缺口。 + +--- + +## 四、使用简介(三步上手) + +### 1. 把 ELF 发到 PS5 +PS5 上先运行一个 ELF 加载器(端口 `9021` 常见),然后在 PC 上: + +```sh +# 把 PS5_IP 换成你主机实际 IP +nc -q0 9021 < web-file-mgr-v1.9.1.elf +``` + +PS5 屏幕会弹通知,显示实际监听端口(默认 `8888`)。首次运行还会在主屏 Media 分类装一个「PS5 Web File Manager」快捷方式。 + +### 2. 浏览器打开 +同一局域网下,任意设备浏览器打开: + +``` +http://:8888/ +``` + +PS5 自带浏览器也能开。 + +### 3. 日常操作 +- **浏览/管理**:列文件、排序、改权限、复制/移动/重命名/删除、原地编辑文本(≤1 MiB 的 txt/json/js/c/h…)。 +- **上传下载**:单文件或文件夹树上传;文件夹/多选以 `.tar` 流式下载。 +- **解压**:在文件列表里点 ZIP / RAR / 7z 的「解压」按钮即可。大档案(>480 GiB)会弹确认提示,确认后用更宽松的限额解压。 +- **冲突策略**:同名文件默认拒绝覆盖;需要时可选覆盖或合并。 + +--- + +## 五、下载与校验 + +> 请在 GitHub Release 页面下载:`https://github.com/lishersong/ps5-web-file-manager/releases/tag/v1.9.1` + +发布文件:`web-file-mgr-v1.9.1.elf` + +| 项目 | 值 | +|---|---| +| 大小 | 870,488 字节(约 850 KiB) | +| sha256 | `24392aff6ddcca4dc0ea969cce356bd693ac52efe8a117d61ee1c814aa43cd07` | +| 文件类型 | ELF 64-bit LSB,x86-64(e_machine `0x003e`,即 PS5 目标三元组) | + +下载后建议先核对 sha256 再发到主机: + +```sh +sha256sum web-file-mgr-v1.9.1.elf +# 应等于 24392aff6ddcca4dc0ea969cce356bd693ac52efe8a117d61ee1c814aa43cd07 +``` + +--- + +## 六、免责声明 + +非官方自制软件,仅在已越狱 PS5 上运行。使用风险自负——作者不对损坏、数据丢失、账号处罚或保修影响负责。请勿再分发 Sony 专有内容。依 GPLv3+,本分支修改后的源码已公开在上面的仓库。 + +--- + +*想继续补 `.tar.gz` / `.xz` 等格式、或接上密码解压 UI 的,欢迎在仓库提 issue。* diff --git a/docs/SIZE-OPTIMIZATION.md b/docs/SIZE-OPTIMIZATION.md new file mode 100644 index 0000000..002935e --- /dev/null +++ b/docs/SIZE-OPTIMIZATION.md @@ -0,0 +1,204 @@ +# ELF 瘦身可行性分析 + +> 2026-09-20 · 环境:WSL Ubuntu-22.04 + `/opt/ps5-payload-sdk` + LLD 18.1.8 +> 基线产物 `web-file-mgr-v1.9.1.elf` = **1,034,328 B** +> 复现脚本:`.build/_sizeprobe.sh`、`.build/_probe3.sh`、`.build/_slimtest.sh`、`.build/_slimtest2.sh`、`.build/_modsize.sh` + +## 结论 + +> ✅ **4.1 + 4.2 已落地(2026-09-20)** — `src/demangle_stub.c` 已加入 `COMMON_SRCS`, +> `LDFLAGS` 已加 `-Wl,--icf=all`。 +> +> 产物:**870,488 B** · sha256 `24392aff6ddcca4dc0ea969cce356bd693ac52efe8a117d61ee1c814aa43cd07` · e_machine `0x003e` +> +> 落地后复核:`__cxa_demangle` 本体 11 B、`itanium_demangle` 符号 0、 +> `__cxa_throw` / `_Unwind_Resume` 等异常符号齐全、`sevenz_extract` / `rar_extract` / +> `zipx_extract` / `MHD_start_daemon_va` 全部存在。 +> section 变化:`.text` 637,616 → 538,336、`.rela.dyn` 54,816 → 25,800、 +> `.eh_frame` 58,904 → 43,972、`.rodata` 162,016 → 153,664。 +> +> 4.3(RELR)与 4.4 未启用 —— 待真机验证 / 权衡后再决定。 + +**能瘦,而且有一个"白捡"的 15.8%。** + +| 方案 | 结果 | 降幅 | 风险 | +|---|---:|---:|---| +| 瘦身前 | 1,034,328 B | — | — | +| **+ `__cxa_demangle` 桩** | **886,872 B** | **−147 KB** | 极低 | +| **+ ICF 代码折叠(当前产物)** | **870,488 B** | **−164 KB (−15.8%)** | 极低 | +| 再 + RELR 重定位压缩 | 854,176 B | −180 KB (−17.4%) | 需真机验证 | +| 第三方改 `-Oz`(单列) | 969,504 B | −65 KB | 可能降速 | + +前两项**不损失任何功能,也不影响解压速度** —— 去掉的是一段永远不会被执行的代码。 + +--- + +## 一、现状构成 + +数据源:`size -A` / `nm --size-sort --print-size` / 未 strip 重链接。 + +### section 级 + +| section | 大小 | 备注 | +|---|---:|---| +| `.text` | 637,616 | 代码主体 | +| `.rodata` | 162,016 | 前端资源(gzip)+ 字符串常量 | +| `.eh_frame` + `.eh_frame_hdr` | 71,444 | **C++ 异常展开表** | +| `.gcc_except_table` | 8,500 | **C++ 异常处理器表** | +| `.rela.dyn` | 54,816 | 2,119 × `R_X86_64_RELATIVE` + 165 × `GLOB_DAT` | +| `.data.rel.ro` | 20,192 | 含指针的只读数据 | +| `.dynsym` + `.dynstr` + `.gnu.hash` | 23,863 | 动态符号表(PIE 必需) | +| `.text$LZMADECOPT` | 4,719 | LZMA 汇编解码器(提速 1.26×,保留) | +| `.bss` | 56,416 | **不占文件体积** | + +### 模块级(按目标文件归属,text+data) + +| 模块 | 文件数 | text | data | +|---|---:|---:|---:| +| unrar7(RAR 引擎) | 48 | 314,528 | 658 | +| libc++ / libc++abi / PS5 运行时 | — | ~161,900 | 20,738 | +| **C++ 异常机制** | — | **151,288** | — | +| zlib | 8 | 65,211 | 336 | +| 7z SDK + 自研链 | 30 | 85,406 | 56 | +| minizip-ng | 8 | 39,382 | 384 | +| 自有代码 `src/` | 14 | 60,653 | 472 | +| libmicrohttpd | — | 44,647 | — | +| 前端资源(gzip 后) | 13 | 40,278 | 104 | + +--- + +## 二、最大的单一发现:151 KB 的 C++ 异常机制 + +`nm` 统计出 **607 个 `itanium_demangle::*` 符号,合计 105,431 B** —— 这是 libc++abi 的 +C++ 名字还原器(`__cxa_demangle`),单独一块就占了整个 ELF 的 **10.2%,比 zlib 整个库还大**。 + +它是怎么被拉进来的: + +1. `third_party/unrar7/dll.cpp` 用了 `catch (RAR_EXIT)` / `catch (std::bad_alloc&)` + (`unpack.cpp` / `model.cpp` 里也有 `throw std::bad_alloc()`) +2. 只要 C++ 异常运行时存在,libc++abi 的 `__cxa_throw` 链路就会引用 `__cxa_demangle` + (用于打印未捕获异常的类型名) +3. 链接器于是把整个 `cxa_demangle.cpp` 拉进来 —— 一个深度内联的模板解析器, + 展开成 607 个函数 + +连带被拖进来的还有 `libunwind`(21,953 B,栈回溯)和异常胶水(23,904 B), +以及散落在每个 C++ 目标文件里的 `.eh_frame`(58,904 B)/ `.gcc_except_table`(8,500 B)。 + +**但这个 demangler 只在「未捕获异常」的诊断路径上才会被调用。** +我们的 unrar7 走 DLL 模式,所有异常都在 `dll.cpp` 内部被 catch 掉, +程序逻辑永远走不到那条路径。 + +--- + +## 三、实测(同一 WSL、同一份源码、同一个链接器) + +| # | 变更 | 结果 | 差值 | +|---|---|---:|---:| +| E0 | 重新链接(校验基线) | 1,034,328 | 0 | +| E1 | `-Wl,--icf=all` | 1,017,944 | −16,384 | +| E2 | 注入 `__cxa_demangle` 桩 | 886,872 | **−147,456** | +| E3 | 桩 + `--icf=all` | 870,488 | **−163,840** | +| E4 | `-Wl,-z,pack-relative-relocs` | 985,248 | −49,080 | +| E5 | `-Wl,-z,noseparate-code` | 1,034,328 | 0(无效) | +| E7 | 桩 + ICF + RELR | 854,176 | −180,152 | +| E8 | 第三方全部改 `-Oz` | 969,504 | −64,824 | + +> E4 单独能省 49 KB,但与 ICF 组合后只剩 16 KB —— ICF 已经合并掉了一批重定位。 + +--- + +## 四、落地方案 + +### 4.1 立即可用:`__cxa_demangle` 桩(−147 KB) + +新增 `src/demangle_stub.c`: + +```c +/* 只提供 __cxa_demangle 的桩,让 libc++abi 里 105 KB 的名字还原器 + * 不被链接进来。该函数只在打印「未捕获异常的类型名」时被调用; + * 返回 NULL 时调用方退回打印 mangled 名,不影响任何业务流程。 */ +#include + +char *__cxa_demangle(const char *mangled, char *buf, size_t *len, int *status) +{ + (void)mangled; (void)buf; (void)len; + if (status) *status = -1; + return NULL; +} +``` + +Makefile 里把它加进 `COMMON_SRCS`(PS5 与 Linux 两条链路都受益): + +```make +COMMON_SRCS := src/main.c src/websrv.c ... src/sevenz_mt.c src/demangle_stub.c +``` + +**原理**:链接器解析 `__cxa_demangle` 引用时,命令行上的 `.o` 优先于归档成员, +所以 `libc++abi.a` 里的 `cxa_demangle.o` 压根不会被取出。 + +**安全性(已实测验证)**: + +| 检查项 | 结果 | +|---|---| +| `__cxa_demangle` 本体大小 | **14 B**(我们的桩) | +| `itanium_demangle::*` 符号残留 | **0** | +| `__cxa_throw` | 存在 | +| `__cxa_begin_catch` / `__cxa_end_catch` | 存在 | +| `_Unwind_Resume` / `__gxx_personality_v0` | 存在 | + +**唯一的行为变化**:万一真的出现未捕获异常,`std::terminate` 打印的是 mangled 名 +而不是可读名。解压逻辑、错误码、进度上报、HTTP 服务一概不受影响。 + +### 4.2 立即可用:ICF 代码折叠(−16 KB) + +```make +LDFLAGS := -Wl,--gc-sections -Wl,--icf=all +``` + +lld 的 identical code folding,合并字节完全相同的函数。工具链已确认为 LLVM LLD 18。 +建议只加在 PS5 的 `LDFLAGS`,不动 Linux 链路(GNU ld 的 `--icf` 支持不完整)。 + +### 4.3 需真机验证:RELR 重定位压缩(−16 KB) + +```make +LDFLAGS += -Wl,-z,pack-relative-relocs +``` + +把 2,119 条 `R_X86_64_RELATIVE`(24 B/条)压成 RELR 位图格式(8 B/条)。 + +**风险**:需要 PS5 的 ELF 加载器认得 `.relr.dyn`。如果加载器只处理 `.rela.dyn`, +重定位根本不会执行 —— 表现是启动即崩。**先在一台机器上验证再推广。** + +### 4.4 不建议作为默认项 + +| 项 | 收益 | 为什么不默认开 | +|---|---:|---| +| 第三方改 `-Oz` | −65 KB | 作用于 LZMA / Deflate / RAR 的热循环,解压速度有下降风险。要用先跑 `tests/bench_driver.py` 对比 | +| 关掉 PPMd(`-DZ7_PPMD_SUPPORT`) | −10 KB | PPMd 压缩的 7z 就解不开了 —— 违背"功能完整" | +| 去掉 zlib `deflate`(只留 inflate) | −18 KB | `mz_strm_zlib_write` 引用了它,需要桩或改库,收益/风险不划算 | + +--- + +## 五、还能挖的(未实测,仅估算) + +| 项 | 预估 | 代价 | +|---|---:|---| +| unrar7 去掉 C++ 异常(`throw`/`catch` 改错误码 + `-fno-exceptions -fno-rtti`) | −100~110 KB | 改 vendored 代码,需回归 163 checks。可回收 `.eh_frame` 59 KB + `.gcc_except_table` 8.5 KB + libunwind 22 KB + 异常胶水 | +| LTO(`-flto=thin`) | −30~60 KB | 全量重编,第三方 `.o` 需统一编译选项;有一定概率反而提速 | +| 前端资源改 LZMA 压缩(复用已有解码器,替代 gzip) | ~−10 KB | 改 `gen-asset-module.py` + `asset.c` | + +理论极限在 700 KB 上下(−32%),但边际成本递增:4.1 + 4.2 用 20 行代码换 164 KB, +而再往下 100 KB 要动 vendored 源码或验证加载器行为。 + +--- + +## 六、推荐执行顺序 + +1. ~~落 4.1 + 4.2 → 构建~~ ✅ **已完成(2026-09-20)**,产物 870,488 B +2. 跑 163 checks(`tests/run-tests.sh` + `tests/run-sevenz-tests.sh`)确认无回归 +3. PS5 真机跑一轮 ZIP / RAR / 7z(含分卷)解压,确认行为不变 +4. 真机验证 4.3(RELR)后再决定是否加入 +5. 有需要再评估第五节的三项 + +> 本次改动只动链接期(新增一个 TU + 一个 lld 参数),未触碰任何解压逻辑, +> 因此 163 checks 的预期是"逐条不变"。 diff --git a/src/demangle_stub.c b/src/demangle_stub.c new file mode 100644 index 0000000..7ea6ec4 --- /dev/null +++ b/src/demangle_stub.c @@ -0,0 +1,31 @@ +/* Stub for the C++ name demangler (__cxa_demangle). + * + * unrar7 is compiled with C++ exceptions enabled -- dll.cpp catches + * RAR_EXIT and std::bad_alloc, unpack.cpp/model.cpp throw bad_alloc -- so + * the runtime's __cxa_throw chain holds a reference to __cxa_demangle. That + * one reference drags the whole Itanium demangler TU into the link: 607 + * symbols, ~105 KiB, over 10% of the final ELF (see docs/SIZE-OPTIMIZATION.md). + * + * __cxa_demangle is only ever reached on the uncaught-exception diagnostic + * path (std::terminate printing the exception's type name). Every unrar + * exception is caught inside dll.cpp, so that path is unreachable here. + * Defining the symbol in our own TU keeps cxa_demangle.o out of the archive + * pull -- the linker resolves against ours and never opens the member. + * + * Returning NULL is the documented "demangle failed" result; the caller + * falls back to printing the mangled name. Exception handling itself + * (__cxa_throw / __cxa_begin_catch / _Unwind_Resume / __gxx_personality_v0) + * is untouched. Applies to both the PS5 and the host/linux builds. */ +#include + +char *__cxa_demangle(const char *mangled, char *buf, size_t *len, int *status) { + (void)mangled; + (void)buf; + (void)len; + + if(status) { + *status = -1; + } + + return 0; +}