可执行文件压缩

前言

最近看Rust相关东西的时候看到一篇关于压缩可执行文件的文章。压缩可执行文件对嵌入式开发特别有用,但是延伸一下用来减少我们游戏行业里预编译的工具二进制包大小和Android/iOS的库也是蛮有用的。

原文见这里: https://jamesmunns.com/blog/tinyrocket/

基本流程

  1. Release编译,移除调试符号文件,开启最小化size优化(-Oz)
  2. 使用LLVM的全量LTO
  3. 使用xargo重新编译标准库(std)和核心库(core)(这个C/C++不容易模仿,而且编译选项十分难搞)
  4. 移除jemalloc(服务器程序还是留着比较好,内置的malloc实现一般碎片比较厉害。虽然C/C++默认也不是jemalloc,很多项目为了新能还是会用它)
  5. 移除panic的详情信息(这个仅适用于Rust
  6. strip(由GNU的binutils提供),参考命令: strip [二进制]
  7. UPX进一步压缩加壳

尝试改造优化

然后尝试使用上面的流程改造我们的 gmtools-cli 。原先我是直接开LTO+Release编译的,编出的文件大小为4.4MB(4520728字节)。

  1. Release编译只要构建命令用 cargo build --release 就可以了,开size优化需要加个配置选项 ``` [profile.release] opt-level = “z”

[profile.dev] opt-level = “z”

2. LTO加几个配置选项就行了

[profile.release] lto = true codegen-units = 1 incremental = false

[profile.dev] lto = true codegen-units = 1 incremental = false

3. 重新编译标准库(std)和核心库(core)比较麻烦,而且我本地的环境报```could not find native static library `c`, perhaps an -L flag is missing?```。原文里自己编译这两个库反而体积变大了,我就先忽略这个了
4. 这个要改源码和配置文件
首先是 **Cargo.toml** 里要增加:

[features] system-alloc = []

然后代码增加:
```rust
#![feature(global_allocator)]
#![feature(allocator_api)]
// When the `system-alloc` feature is used, use the System Allocator
#[cfg(feature = "system-alloc")]
mod allocator {
    use std::heap::System;

    #[global_allocator]
    pub static mut THE_ALLOC: System = System;
}

// When the `system-alloc` feature is not used, do nothing,
// retaining the default functionality (using jemalloc)
#[cfg(not(feature = "system-alloc"))]
mod allocator {
    #[allow(dead_code)]
    pub static THE_ALLOC: () = ();
}

#[allow(unused_imports)]
use allocator::THE_ALLOC;

最后构建命令加 --features system-alloc

  1. 这个就是移除调试信息,把 [profile.release] 的配置 panic = “abort” 就可以了 ``` [profile.release] panic = “abort”

[profile.dev] panic = “abort” ```

  1. 直接执行 strip 二进制 即可
  2. 参考命令 upx --ultra-brute 二进制

最后执行完,成果很惊人。压缩完后的大小是274K(280264字节)。

来个更直观的对比。

对比项

压缩前

压缩后

编译选项

release,opt-level=3,lto=true,codegen-units=3,panic=“unwind”

release,opt-level=“z”,lto=true,codegen-units=1,panic=“abort”,strip

原始编译结果

4.4MB(4520728字节)

2.1MB(2187784字节) – 减少51.6%

仅执行strip

4.4MB(4520728字节)

844K(863312字节) – 减少80.9%

执行strip和upx

4.4MB(4520728字节)

274K(280264字节) – 减少93.8%

其他C/C++的压缩

其实上面效果最大的是Release编译移除调试符号、strip和upx,这三项都可以直接用再C/C++项目里的。唯一不同的就是可以编译的时候保留调试符号,然后用 objcopy 来代替 strip 把调试符号导出来并且移除了。

关于UPX和WSL和Android

UPX的原理是压缩代码,然后加入一些初始化函数再运行时解压,以前被一些病毒拿来做加壳处理,所以可能有些杀毒软件会报。其实不用UPXstrip也有不错的压缩率了。

在WSL环境下,现在的版本不支持UPX压缩后的可执行程序,会报 exec format error ,但是马上要发布的春季更新后就支持了。 这里有个Issue说这个问题的 https://github.com/Microsoft/WSL/issues/330

Android下用UPX看到说需要几个小patch(我没试,这里只是记录一下):

  • UPX需要二进制文件大于40K,如果不够大可以加个全局变量搞大这个.so。
  • 在native代码中需要声明 extern "C" {void _init(void){}} 函数,用于在编译时生成 _init 段。(UPX要求二进制文件必须存在init段,但是android的.so可能没有)
    • 或者也可以自定义初始化代码, extern "C" {void my_init(void){}} ,然后编译时在 Android.mk 里加入 LOCAL_LDFLAGS += -Wl,-init=my_init 。来指定自己的初始化加载函数

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3n1gmsmrgq2ok

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我叫刘半仙

手写一个简化版Tomcat

      Tomcat作为Web服务器深受市场欢迎,有必要对其进行深入的研究。在工作中,我们经常会把写好的代码打包放在Tomcat里并启动,然后在浏览器里就能...

3935
来自专栏信安之路

一个病毒样本分析的全过程

SHA1: 3f738735bb0c5c95792c21d618eca8c0d5624717

1740
来自专栏逆向技术

远程线程注入

一丶远程线程注入的讲解 远程线程注入的原理,我会写一个远程线程开发的例子 我们总共需要几步 /*1.查找窗口,获取窗口句柄*/ /*2.根据...

25010
来自专栏增长技术

查看历史--Git日志

如果用--stat选项使用git log,它会显示在每个提交(commit)中哪些文件被修改了,这些文件分别添加或删除了多少行内容。

1645
来自专栏不止是前端

Node下RabbitMQ的使用

47919
来自专栏linux驱动个人学习

Linux下进程的创建过程分析(_do_fork do_fork详解)--Linux进程的管理与调度(八)

Unix标准的复制进程的系统调用时fork(即分叉),但是Linux,BSD等操作系统并不止实现这一个,确切的说linux实现了三个,fork,vfork,cl...

1172
来自专栏零基础使用Django2.0.1打造在线教育网站

零基础使用Django2.0.1打造在线教育网站(五):简易留言簿交互实现

努力与运动兼备~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

5258
来自专栏SDNLAB

基于OpenDaylight和OVSDB搭建VxLAN网络

1 简介 本文主要介绍基于OpenDaylight子项目OVSDB中的southbound组件来搭建VxLAN网络,包括初始环境搭建和southbound Re...

3397
来自专栏用户2442861的专栏

java数据库操作 (附带数据库连接池的代码)

本文来自:曹胜欢博客专栏。转载请注明出处:http://blog.csdn.net/csh624366188

2732
来自专栏Google Dart

微信小程序之支付详解(填坑) 原

首先,你采用什么语言选择对应的sdk,记住:微信sdk默认签名是HMACSHA256,因为小程序只支持MD5,故你这里即使获取了prepay_id,在小程序发起...

1213

扫码关注云+社区

领取腾讯云代金券