程序瘦身

剥离调试信息

程序发布时,总是会把调试信息从程序中移除,另存到一个文件中,一则是减少发布程序的大小,二则是保护信息。

一般的步骤如下(demo就是程序名):

  • objcopy --only-keep-debug demo demo.debuginfo,读取demo中的调试信息保存到demo.debuginfo文件中。

  • objcopy --strip-debug demo,从demo中移除一下调试信息。使用readelf -S查看前后的section,可以发现缺少了以下section(PS:这些section只有在编译时加了-g参数时才会有)。

>   [27] .debug_aranges    PROGBITS         0000000000000000  00001061
>        0000000000000030  0000000000000000           0     0     1
>   [28] .debug_info       PROGBITS         0000000000000000  00001091
>        00000000000000bb  0000000000000000           0     0     1
>   [29] .debug_abbrev     PROGBITS         0000000000000000  0000114c
>        0000000000000069  0000000000000000           0     0     1
>   [30] .debug_line       PROGBITS         0000000000000000  000011b5
>        0000000000000042  0000000000000000           0     0     1
>   [31] .debug_str        PROGBITS         0000000000000000  000011f7
  • objcopy --add-gnu-debuglink demo.debuginfo demo,在demo中增加一个叫做.gnu_debuglink的section,其中保存了保存调试信息文件的名字和CRC校验值。

剥离符号信息

为了更彻底地减小程序大小和保护信息,可以使用objcopy --strip-all demo,不止删除调试信息还删除符号表,此时用nm命令是无法获取符号信息的,对比objcopy --strip-debug demo后的程序,主要是多删了程序中的以下section。

>   [28] .symtab           SYMTAB           0000000000000000  00001170
>        00000000000005d0  0000000000000018          29    41     8
>   [29] .strtab           STRTAB           0000000000000000  00001740
>        0000000000000228  0000000000000000           0     0     1

gdb调试

说一下gdb是如何根据.gnu_debuglink查找调试信息文件的

For the “debug link” method, GDB looks up the named file in the directory of the executable file, then in a subdirectory of that directory named .debug, and finally under each one of the global debug directories, in a subdirectory whose name is identical to the leading directories of the executable’s absolute file name.

通过strace gdb a.out的输出得到以下信息验证了一下

open("/root/gdb/a.out.debug", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/root/gdb/.debug/a.out.debug", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/debug//root/gdb/a.out.debug", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/debug/root/gdb/a.out.debug", O_RDONLY) = -1 ENOENT (No such file or directory)
  • 程序所在目录(尝试过从在其他目录下启动gdb,仍然是在程序所在目录)
  • 程序所在目录的.debug目录
  • /usr/lib/debug/程序绝对路径
  • 不知道和上一种有什么区别

不论是只剥离了调试信息还是将调试信息和符号都剥离了,只要有调试信息文件,并将其放在上述任一目录下,就可以用gdb调试。

demo.debuginfo是一个ELF文件

[root@localhost ~]# file demo.debuginfo 
demo.debuginfo: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=3c390d31af9856f59d1817b5eeefce937dc0ef78, not stripped

通过readelf -S demo.debuginfo,可看到其包含了以下section

  [28] .debug_aranges    PROGBITS         0000000000000000  000002c5
       0000000000000030  0000000000000000           0     0     1
  [29] .debug_info       PROGBITS         0000000000000000  000002f5
       0000000000000091  0000000000000000           0     0     1
  [30] .debug_abbrev     PROGBITS         0000000000000000  00000386
       0000000000000042  0000000000000000           0     0     1
  [31] .debug_line       PROGBITS         0000000000000000  000003c8
       000000000000003a  0000000000000000           0     0     1
  [32] .debug_str        PROGBITS         0000000000000000  00000402
       00000000000000aa  0000000000000001  MS       0     0     1
  [33] .symtab           SYMTAB           0000000000000000  000004b0
       0000000000000678  0000000000000018          34    52     8
  [34] .strtab           STRTAB           0000000000000000  00000b28
       00000000000001c8  0000000000000000           0     0     1
  [35] .shstrtab         STRTAB           0000000000000000  00000cf0
       000000000000014c  0000000000000000           0     0     1

这些sesion说明通过objcopy --only-keep-debug命令生成的文件不止包含了调试信息,还包含了符号信息。

你可能感兴趣的:(程序瘦身)