减少 golang 二进制文件大小操作

 更新时间:2020年12月17日 10:31:00   作者:疯疯癫癫  
这篇文章主要介绍了减少 golang 二进制文件大小操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

环境:

$ go version
go version go1.11.2 linux/amd64

$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609

一. Go VS C 二进制

hello.go

package main
import "fmt"
func main() {
 fmt.Println("hello world")
}

hello.c

#include <stdio.h>
int main() {
 printf("hello world\n");
 return 0;
}
$ go build -o hello hello.go
$ go build -ldflags "-s -w" -o hello2 hello.go
$ gcc hello.c
$ ls -l
-rwxrwxr-x 1 zengxl zengxl 1902849 11月 27 15:40 hello
-rwxrwxr-x 1 zengxl zengxl 1353824 11月 27 15:43 hello2
-rwxrwxr-x 1 zengxl zengxl 8600 11月 27 15:44 a.out

golang 连接的参数:

$ go tool link -h

usage: link [options] main.o
-s disable symbol table  # 去掉符号表
-w disable DWARF generation # 去掉调试信息

ELF

先来看下 C 的:

$ readelf -h a.out 
ELF 头:
 Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
 类别:        ELF64
 数据:        2 补码,小端序 (little endian)
 版本:        1 (current)
 OS/ABI:       UNIX - System V
 ABI 版本:       0
 类型:        EXEC (可执行文件)
 系统架构:       Advanced Micro Devices X86-64
 版本:        0x1
 入口点地址:    0x400430
 程序头起点:   64 (bytes into file)
 Start of section headers:   6616 (bytes into file)
 标志:    0x0
 本头的大小:  64 (字节)
 程序头大小:  56 (字节)
 Number of program headers:   9
 节头大小:   64 (字节)
 节头数量:   31
 字符串表索引节头: 28
$ readelf -d a.out 

Dynamic section at offset 0xe28 contains 24 entries:
 标记  类型       名称/值
 0x0000000000000001 (NEEDED)    共享库:[libc.so.6]
 0x000000000000000c (INIT)    0x4003c8
 0x000000000000000d (FINI)    0x4005b4
 0x0000000000000019 (INIT_ARRAY)   0x600e10
 0x000000000000001b (INIT_ARRAYSZ)  8 (bytes)
 0x000000000000001a (FINI_ARRAY)   0x600e18
 0x000000000000001c (FINI_ARRAYSZ)  8 (bytes)
 0x000000006ffffef5 (GNU_HASH)   0x400298
 0x0000000000000005 (STRTAB)    0x400318
 0x0000000000000006 (SYMTAB)    0x4002b8
 0x000000000000000a (STRSZ)    61 (bytes)
 0x000000000000000b (SYMENT)    24 (bytes)
 0x0000000000000015 (DEBUG)    0x0
 0x0000000000000003 (PLTGOT)    0x601000
 0x0000000000000002 (PLTRELSZ)   48 (bytes)
 0x0000000000000014 (PLTREL)    RELA
 0x0000000000000017 (JMPREL)    0x400398
 0x0000000000000007 (RELA)    0x400380
 0x0000000000000008 (RELASZ)    24 (bytes)
 0x0000000000000009 (RELAENT)   24 (bytes)
 0x000000006ffffffe (VERNEED)   0x400360
 0x000000006fffffff (VERNEEDNUM)   1
 0x000000006ffffff0 (VERSYM)    0x400356
 0x0000000000000000 (NULL)    0x0

再来看下 go 的:

$ readelf -h hello
ELF 头:
 Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
 类别:        ELF64
 数据:        2 补码,小端序 (little endian)
 版本:        1 (current)
 OS/ABI:       UNIX - System V
 ABI 版本:       0
 类型:        EXEC (可执行文件)
 系统架构:       Advanced Micro Devices X86-64
 版本:        0x1
 入口点地址:    0x451fa0
 程序头起点:   64 (bytes into file)
 Start of section headers:   456 (bytes into file)
 标志:    0x0
 本头的大小:  64 (字节)
 程序头大小:  56 (字节)
 Number of program headers:   7
 节头大小:   64 (字节)
 节头数量:   13
 字符串表索引节头: 3

$ readelf -d hello

There is no dynamic section in this file.

The linker in the gc toolchain creates statically-linked binaries by default. All Go binaries therefore include the Go runtime, along with the run-time type information necessary to support dynamic type checks, reflection, and even panic-time stack traces.

A simple C “hello, world” program compiled and linked statically using gcc on Linux is around 750 kB, including an implementation of printf. An equivalent Go program using fmt.Printf weighs a couple of megabytes, but that includes more powerful run-time support and type and debugging information.

所以,为什么 go 二进制比 C 大很多就比较明显了。

golang 静态编译,不依赖动态库。

二. 如何减小 go 二进制文件大小

2.1. -ldflags

上面已经提到了过了。

$ go build -ldflags "-s -w" xxx.go

2.2. UPX

https://github.com/upx/upx

Commands:
 -1  compress faster     -9 compress better
 -d  decompress      -l list compressed file
 -t  test compressed file    -V display version number
 -h  give more help     -L display software license
Options:
 -q  be quiet       -v be verbose
 -oFILE write output to 'FILE'
 -f  force compression of suspicious files
 -k  keep backup files
file.. executables to (de)compress

Compression tuning options:
 --brute    try all available compression methods & filters [slow]
 --ultra-brute  try even more compression variants [very slow]

$ upx --brute binaryfile

IDA 逆向分析简单看下:

https://www.hex-rays.com/products/ida/support/download.shtml

下面是支持 Go 的 IDA helper

https://github.com/sibears/IDAGolangHelper

原始的 go 二进制文件:

可以看到 go 的一些函数名。

去掉符号表和调试信息的 go 二进制文件:

已经看不到函数名信息,只有类似 sub_47BF70 这样。

经过 upx 压缩的 go 二进制文件:

信息已经比较少了,入口点也发生了变化。

2.3. 压缩结果对比

$ go build -o hello hello.go
$ go build -ldflags "-s -w" -o hello-strip hello.go
$ upx --brute hello
$ ll -h
-rwxr-xr-x 1 aland aland 1.9M Dec 6 13:06 hello
-rwxr-xr-x 1 aland aland 809K Dec 6 13:07 hello-upx
-rwxr-xr-x 1 aland aland 1.3M Dec 6 13:06 hello-strip

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

相关文章

  • Golang通道channel的源码分析

    Golang通道channel的源码分析

    channel(通道),顾名思义,是一种通道,一种用于并发环境中数据传递的通道。channel是golang中标志性的概念之一,很好很强大!本文将从源码带大家了解一下channel的使用,希望对大家有所帮助
    2022-12-12
  • 8种超简单的Golang生成随机字符串方式分享

    8种超简单的Golang生成随机字符串方式分享

    这篇文章主要为大家详细介绍了8种超简单的Golang生成随机字符串方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-01-01
  • vscode上搭建go开发环境详细完整过程

    vscode上搭建go开发环境详细完整过程

    这篇文章主要给大家介绍了关于vscode上搭建go开发环境的详细完整过程,Go语言或将成为新的主力开发语言,Go是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言,所以我们有必要学习并掌握它,需要的朋友可以参考下
    2023-10-10
  • 使用Go语言解决Scan空格结束输入问题

    使用Go语言解决Scan空格结束输入问题

    这篇文章主要为大家介绍了使用Go语言来解决Scan空格结束输入问题,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-11-11
  • go slice 扩容实现原理源码解析

    go slice 扩容实现原理源码解析

    这篇文章主要为大家介绍了go slice 扩容实现原理源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • Golang实现深拷贝reflect原理示例探究

    Golang实现深拷贝reflect原理示例探究

    这篇文章主要为大家介绍了Golang实现reflect深拷贝原理示例探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Go io/fs.FileMode文件系统基本操作和权限管理深入理解

    Go io/fs.FileMode文件系统基本操作和权限管理深入理解

    这篇文章主要为大家介绍了Go io/fs.FileMode文件系统基本操作和权限管理深入理解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Go语言中的Struct结构体

    Go语言中的Struct结构体

    这篇文章介绍了Go语言中的Struct结构体,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Go语言的管道Channel用法实例

    Go语言的管道Channel用法实例

    这篇文章主要介绍了Go语言的管道Channel用法,实例分析了Go语言中管道的原理与使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • Go语言实现控制台输入&生成随机数详解

    Go语言实现控制台输入&生成随机数详解

    这篇文章主要介绍了Go语言如何实现控制台输入&生成随机数,文中通过示例代码介绍的非常详细,对大家的学习有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05

最新评论