不可靠;UPX不推荐压缩启用-fPIE/-pie或链接libstdc++/libc++的C++程序,因其无法正确处理动态重定位表、GOT/PLT、.eh_frame和TLS等现代特性,易致崩溃。

UPX 压缩 C++ 编译出的可执行文件是否可靠?
不推荐对绝大多数 C++ 程序(尤其是启用了 -fPIE、-pie 或链接了 libstdc++/libc++ 的程序)直接用 UPX 压缩。UPX 本质是运行时解压器 + 压缩代码段,它假设二进制结构“静态可重定位”,而现代 C++ 可执行文件普遍含动态重定位表(.rela.dyn)、GOT/PLT 表、C++ 异常表(.eh_frame)和 TLS 数据——UPX 默认不处理这些,强行压缩会导致启动失败或运行时崩溃。
哪些 C++ 可执行文件能安全 UPX?
仅限极简场景,满足全部以下条件:
- 纯 C 风格编写,未调用
std::string、std::vector、异常、RTTI - 编译时加
-static -nostdlib -no-pie -fno-exceptions -fno-rtti - 链接时只用
ld手动链接crt0.o和libc.a(不经过gcc驱动) - 目标平台为 x86_64/Linux,且 UPX 版本 ≥ 4.2.0(旧版对 PIE 支持更差)
示例最小可压缩入口:
int _start() {
__asm__ volatile ("mov $1, %rax; mov $1, %rdi; mov $msg, %rsi; mov $3, %rdx; syscall" :: "i"(SYS_write));
__asm__ volatile ("mov $60, %rax; mov $0, %rdi; syscall");
return 0;
}
char msg[] = "hi\n";
用 gcc -static -nostdlib -no-pie -fno-exceptions -fno-rtti -o tiny tiny.s 编译后,upx --best tiny 才大概率成功。
立即学习“C++免费学习笔记(深入)”;
为什么 upx --force 常常失败?
--force 不是万能开关,它只是跳过 UPX 的“安全检查”,但无法修复底层兼容性问题。常见报错及原因:
-
upx: tiny: NotCompressibleException→ 文件已无冗余或含 UPX 明确拒绝的段(如.eh_frame) -
Segmentation fault (core dumped)启动时 → 动态链接器找不到 PLT 入口,或 GOT 表被破坏 -
cannot execute binary file: Exec format error→ UPX 写入了非法 ELF 头或修改了e_entry指向错误地址 -
symbol lookup error: undefined symbol: __cxa_atexit→libstdc++.so动态依赖被破坏,UPX 未重写 .dynamic 段
UPX 对 C++ 运行时的符号解析能力非常有限,它不分析 C++ ABI,也不重写 .dynamic 中的 DT_NEEDED 条目。
替代方案:比 UPX 更实际的减小体积方法
与其冒险用 UPX,不如从编译链入手:
- 用
gcc -Os -s -flto -ffunction-sections -fdata-sections编译,链接时加-Wl,--gc-sections -static-libgcc -static-libstdc++ - 替换标准库:
musl-gcc静态链接比 glibc 小 5–10MB;或用libc+++compiler-rt替代libstdc++ - 剥离调试信息:
strip --strip-unneeded(不是strip -s) - 用
zlib-ng或lz4自定义加载器:自己实现 mmap + 解压 + 跳转,可控性远高于 UPX
真正需要高压缩比的嵌入式场景,往往得放弃 C++ 异常和 RTTI,并接受手写启动代码——这时候 UPX 才不是最麻烦的一环。


















