strip eu-strip debuginfo

Posted by XP on March 10, 2020

strip, eu-strip, objcopy, debuginfo

elf(可执行和可链接格式–Executable and Linkable Format)文件由ELF Header、Sections、Section Header Table 和Program Header Table组成,其中section,又包括代码段(.text), 数据段(.data),只读数据段(.rodata), .bss, 注释信息段(.comment), 堆栈提示段(.note.GNU-stack)等等.

查看efl文件,可以用到file,readelf,objdump,nm等工具。 写个文件测试下:

#include <stdio.h>

int g_value = 1;
int g_value_uninit;
const int g_const_value = 10;

void fun(int age)
{
    printf("age = %d\n",age);
}

int main()
{
    int value = 1;
    static int s_value = 1;
    char *name = "Win!xp!";
    fun(value);

    return 0;
}

编译生成可执行文件:

$ gcc -g hello.c -o hello

使用file,查看hello信息:

$ file hello

hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, 
BuildID[sha1]=61469bbc6f06707b5c145ac3ba6d79892423e58f, not stripped

readelf可以查看更多elf文件的信息,比如文件头,段表等

$ readelf -h hello

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400430
  Start of program headers:          64 (bytes into file)
  Start of section headers:          7824 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         36
  Section header string table index: 33

段表(Section Header Table)保存了efl中段的基本属性信息,比如每个段的段名,长度,在文件中的偏移,读写权限等。 编译器、链接器和装载器都是依据段表来定位和访问各个段的属性。可以使用readelf -S 查看段表信息:

$ readelf -S -W hello

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        0000000000400238 000238 00001c 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            0000000000400254 000254 000020 00   A  0   0  4
  [ 3] .note.gnu.build-id NOTE            0000000000400274 000274 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        0000000000400298 000298 00001c 00   A  5   0  8
  [ 5] .dynsym           DYNSYM          00000000004002b8 0002b8 000060 18   A  6   1  8
  [ 6] .dynstr           STRTAB          0000000000400318 000318 00003f 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          0000000000400358 000358 000008 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         0000000000400360 000360 000020 00   A  6   1  8
  [ 9] .rela.dyn         RELA            0000000000400380 000380 000018 18   A  5   0  8
  [10] .rela.plt         RELA            0000000000400398 000398 000030 18  AI  5  24  8
  [11] .init             PROGBITS        00000000004003c8 0003c8 00001a 00  AX  0   0  4
  [12] .plt              PROGBITS        00000000004003f0 0003f0 000030 10  AX  0   0 16
  [13] .plt.got          PROGBITS        0000000000400420 000420 000008 00  AX  0   0  8
  [14] .text             PROGBITS        0000000000400430 000430 0001b2 00  AX  0   0 16
  [15] .fini             PROGBITS        00000000004005e4 0005e4 000009 00  AX  0   0  4
  [16] .rodata           PROGBITS        00000000004005f0 0005f0 00001a 00   A  0   0  4
  [17] .eh_frame_hdr     PROGBITS        000000000040060c 00060c 00003c 00   A  0   0  4
  [18] .eh_frame         PROGBITS        0000000000400648 000648 000114 00   A  0   0  8
  [19] .init_array       INIT_ARRAY      0000000000600e10 000e10 000008 00  WA  0   0  8
  [20] .fini_array       FINI_ARRAY      0000000000600e18 000e18 000008 00  WA  0   0  8
  [21] .jcr              PROGBITS        0000000000600e20 000e20 000008 00  WA  0   0  8
  [22] .dynamic          DYNAMIC         0000000000600e28 000e28 0001d0 10  WA  6   0  8
  [23] .got              PROGBITS        0000000000600ff8 000ff8 000008 08  WA  0   0  8
  [24] .got.plt          PROGBITS        0000000000601000 001000 000028 08  WA  0   0  8
  [25] .data             PROGBITS        0000000000601028 001028 000018 00  WA  0   0  8
  [26] .bss              NOBITS          0000000000601040 001040 000008 00  WA  0   0  4
  [27] .comment          PROGBITS        0000000000000000 001040 000035 01  MS  0   0  1
  [28] .debug_aranges    PROGBITS        0000000000000000 001075 000030 00      0   0  1
  [29] .debug_info       PROGBITS        0000000000000000 0010a5 00013d 00      0   0  1
  [30] .debug_abbrev     PROGBITS        0000000000000000 0011e2 00009d 00      0   0  1
  [31] .debug_line       PROGBITS        0000000000000000 00127f 000044 00      0   0  1
  [32] .debug_str        PROGBITS        0000000000000000 0012c3 0000fd 01  MS  0   0  1
  [33] .shstrtab         STRTAB          0000000000000000 001d44 00014c 00      0   0  1
  [34] .symtab           SYMTAB          0000000000000000 0013c0 000738 18     35  53  8
  [35] .strtab           STRTAB          0000000000000000 001af8 00024c 00      0   0  1

section

段名 说明
.data 保存已经初始化的全局变量和静态变量
.rodata Read only Data, 保存只读数据,比如字符串常量,全局const变量
.comment 存放编译器版本信息,比如:GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
.debug 调试信息
.strtab 字符串表,存储ELF文件中用到的各种字符串
.symtab 符号表,存储ELF文件用到的所有符号
.shstrtab Section String Table,段表字符串表,保存所有段名
.bss 存放所有未初始化的全局变量和静态变量
.text 代码段
.init 程序初始化代码段
.fini 程序终结代码段

更多信息可以参考Executable and Linkable Format (ELF)

查看段信息:

readelf -p .comment hello

String dump of section '.comment':
  [     0]  GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609

readelf -p .strtab hello

String dump of section '.strtab':
  [     1]  crtstuff.c
  [     c]  __JCR_LIST__
  [    19]  deregister_tm_clones
  [    2e]  __do_global_dtors_aux
  [    44]  completed.7594
  [    53]  __do_global_dtors_aux_fini_array_entry
  [    7a]  frame_dummy
  [    86]  __frame_dummy_init_array_entry
  [    a5]  hello.c
  [    ad]  s_value.2292
  [    ba]  __FRAME_END__
  [    c8]  __JCR_END__
  [    d4]  __init_array_end
  [    e5]  _DYNAMIC
  [    ee]  __init_array_start
  [   101]  __GNU_EH_FRAME_HDR
  [   114]  _GLOBAL_OFFSET_TABLE_
  [   12a]  __libc_csu_fini
  [   13a]  g_value
  [   142]  _ITM_deregisterTMCloneTable
  [   15e]  _edata
  [   165]  fun
  [   169]  printf@@GLIBC_2.2.5
  [   17d]  __libc_start_main@@GLIBC_2.2.5
  [   19c]  __data_start
  [   1a9]  __gmon_start__
  [   1b8]  __dso_handle
  [   1c5]  _IO_stdin_used
  [   1d4]  __libc_csu_init
  [   1e4]  g_const_value
  [   1f2]  __bss_start
  [   1fe]  main
  [   203]  _Jv_RegisterClasses
  [   217]  __TMC_END__
  [   223]  _ITM_registerTMCloneTable
  [   23d]  g_value_uninit

symtab信息可以使用nm查看:
nm hello

0000000000601040 B __bss_start
0000000000601040 b completed.7594
0000000000601028 D __data_start
0000000000601028 W data_start
0000000000400460 t deregister_tm_clones
00000000004004e0 t __do_global_dtors_aux
0000000000600e18 t __do_global_dtors_aux_fini_array_entry
0000000000601030 D __dso_handle
0000000000600e28 d _DYNAMIC
0000000000601040 D _edata
0000000000601048 B _end
00000000004005e4 T _fini
0000000000400500 t frame_dummy
0000000000600e10 t __frame_dummy_init_array_entry
0000000000400758 r __FRAME_END__
0000000000400526 T fun
00000000004005f4 R g_const_value
0000000000601000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
000000000040060c r __GNU_EH_FRAME_HDR
0000000000601038 D g_value
0000000000601044 B g_value_uninit
00000000004003c8 T _init
0000000000600e18 t __init_array_end
0000000000600e10 t __init_array_start
00000000004005f0 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
                 w _Jv_RegisterClasses
00000000004005e0 T __libc_csu_fini
0000000000400570 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
0000000000400548 T main
                 U printf@@GLIBC_2.2.5
00000000004004a0 t register_tm_clones
0000000000400430 T _start
000000000060103c d s_value.2292
0000000000601040 D __TMC_END__

strip

实际发布的软件中,不会包含调试信息,否则安装包会很大,并且实际运行时,不需要这些调试信息。比如打包发布的rpm, 会将调试信息,符号表信息等放入到debuginfo中,如果发成了core dump再安装对应的debuginfo rpm,进行调试。对ELF进行瘦身,有很多工具可以用,strip,eu-strip,objcopy. 上面的hello文件,使用file查看时,可以看到not stripped.

eu-strip

eu-strip在elfutils工具集中,elfutils包含了一系列读取,修改,创建elf文件的工具,包括:

  • eu-ld (a linker)
  • eu-nm (for listing symbols from object files)
  • eu-size (for listing the section sizes of an object or archive file)
  • eu-strip (for discarding symbols)
  • eu-readelf (to see the raw ELF file structures)
  • eu-elflint (to check for well-formed ELF files)

安装eu-strip

sudo apt-get install elfutils

eu-strip说明

 Output selection:
  -f FILE                    Extract the removed sections into FILE
  -F FILE                    Embed name FILE instead of -f argument
  -o, --output=FILE          Place stripped output into FILE

 Output options:
  -g, -d, -S, --strip-debug  Remove all debugging symbols
  -p, --preserve-dates       Copy modified/access timestamps to the output
      --permissive           Relax a few rules to handle slightly broken ELF
                             files
      --reloc-debug-sections Resolve all trivial relocations between debug
                             sections if the removed sections are placed in a
                             debug file (only relevant for ET_REL files,
                             operation is not reversable, needs -f)
      --remove-comment       Remove .comment section
      --strip-sections       Remove section headers (not recommended)

使用时,发现–remove-comment选项,并非只是去除.comment段,而是会去除.debug, .comment, .strtab, .symtab.

$ eu-strip –remove-comment hello $ readelf -S -W hello

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        0000000000400238 000238 00001c 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            0000000000400254 000254 000020 00   A  0   0  4
  [ 3] .note.gnu.build-id NOTE            0000000000400274 000274 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        0000000000400298 000298 00001c 00   A  5   0  8
  [ 5] .dynsym           DYNSYM          00000000004002b8 0002b8 000060 18   A  6   1  8
  [ 6] .dynstr           STRTAB          0000000000400318 000318 00003f 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          0000000000400358 000358 000008 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         0000000000400360 000360 000020 00   A  6   1  8
  [ 9] .rela.dyn         RELA            0000000000400380 000380 000018 18   A  5   0  8
  [10] .rela.plt         RELA            0000000000400398 000398 000030 18  AI  5  24  8
  [11] .init             PROGBITS        00000000004003c8 0003c8 00001a 00  AX  0   0  4
  [12] .plt              PROGBITS        00000000004003f0 0003f0 000030 10  AX  0   0 16
  [13] .plt.got          PROGBITS        0000000000400420 000420 000008 00  AX  0   0  8
  [14] .text             PROGBITS        0000000000400430 000430 0001b2 00  AX  0   0 16
  [15] .fini             PROGBITS        00000000004005e4 0005e4 000009 00  AX  0   0  4
  [16] .rodata           PROGBITS        00000000004005f0 0005f0 00001a 00   A  0   0  4
  [17] .eh_frame_hdr     PROGBITS        000000000040060c 00060c 00003c 00   A  0   0  4
  [18] .eh_frame         PROGBITS        0000000000400648 000648 000114 00   A  0   0  8
  [19] .init_array       INIT_ARRAY      0000000000600e10 000e10 000008 00  WA  0   0  8
  [20] .fini_array       FINI_ARRAY      0000000000600e18 000e18 000008 00  WA  0   0  8
  [21] .jcr              PROGBITS        0000000000600e20 000e20 000008 00  WA  0   0  8
  [22] .dynamic          DYNAMIC         0000000000600e28 000e28 0001d0 10  WA  6   0  8
  [23] .got              PROGBITS        0000000000600ff8 000ff8 000008 08  WA  0   0  8
  [24] .got.plt          PROGBITS        0000000000601000 001000 000028 08  WA  0   0  8
  [25] .data             PROGBITS        0000000000601028 001028 000018 00  WA  0   0  8
  [26] .bss              NOBITS          0000000000601040 001040 000008 00  WA  0   0  4
  [27] .shstrtab         STRTAB          0000000000000000 001040 0000f3 00      0   0

objcopy

Linux Objcopy Command Examples to Copy and Translate Object Files

参考文献