Android NDK产生不合理的大二进制文件,如何优化.so大小?

Ale*_*hen 7 android android-ndk

我注意到Android NDK(在我的情况下是r6b)产生了不合理的大结果.so文件.例如,在我的情况下,我有大约150-200行C++代码(6个本机方法和3个C++最简单的类),这个本机代码生成60kb(!). so,启用异常和RTTI或12kb .so,禁用异常和RTTI.只是为了检查我已经编译了包含在NDK包中的hello-jni示例,并从此示例获得10kb .so用于单行本机方法.

在我看来,对于移动平台而言,这在某种程度上是不合理的开销(在我的桌面上,通过大小代码产生的可比性小约10-15倍.so).

  1. 我应该知道减少二进制文件大小的技巧吗?
  2. 为什么只有C代码有这样的开销?
  3. 为什么有启用异常和RTTI的C++代码会有更大的开销?

更新#1:来自NDK的hello-jni示例的readelf输出

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0xc18
  Start of program headers:          52 (bytes into file)
  Start of section headers:          9344 (bytes into file)
  Flags:                             0x5000002, has entry point, Version5 EABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         5
  Size of section headers:           40 (bytes)
  Number of section headers:         19
  Section header string table index: 18

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .hash             HASH            000000d4 0000d4 0001a4 04   A  2   0  4
  [ 2] .dynsym           DYNSYM          00000278 000278 000420 10   A  3   3  4
  [ 3] .dynstr           STRTAB          00000698 000698 0004aa 00   A  0   0  1
  [ 4] .rel.dyn          REL             00000b44 000b44 000048 08   A  2   0  4
  [ 5] .rel.plt          REL             00000b8c 000b8c 000030 08   A  2   6  4
  [ 6] .plt              PROGBITS        00000bbc 000bbc 00005c 04  AX  0   0  4
  [ 7] .text             PROGBITS        00000c18 000c18 001518 00  AX  0   0  4
  [ 8] .rodata           PROGBITS        00002130 002130 000014 01 AMS  0   0  4
  [ 9] .ARM.extab        PROGBITS        00002144 002144 000024 00   A  0   0  4
  [10] .ARM.exidx        ARM_EXIDX       00002168 002168 0000e0 00  AL  7   0  4
  [11] .init_array       INIT_ARRAY      00003248 002248 000008 00  WA  0   0  1
  [12] .fini_array       FINI_ARRAY      00003250 002250 00000c 00  WA  0   0  1
  [13] .dynamic          DYNAMIC         0000325c 00225c 0000e8 08  WA  3   0  4
  [14] .got              PROGBITS        00003344 002344 000040 04  WA  0   0  4
  [15] .bss              NOBITS          00003390 002384 000010 00  WA  0   0 16
  [16] .comment          PROGBITS        00000000 002384 000036 00      0   0  1
  [17] .ARM.attributes   ARM_ATTRIBUTES  00000000 0023ba 000029 00      0   0  1
  [18] .shstrtab         STRTAB          00000000 0023e3 00009b 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  EXIDX          0x002168 0x00002168 0x00002168 0x000e0 0x000e0 R   0x4
  LOAD           0x000000 0x00000000 0x00000000 0x02248 0x02248 R E 0x1000
  LOAD           0x002248 0x00003248 0x00003248 0x0013c 0x00158 RW  0x1000
  DYNAMIC        0x00225c 0x0000325c 0x0000325c 0x000e8 0x000e8 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

 Section to Segment mapping:
  Segment Sections...
   00     .ARM.exidx 
   01     .hash .dynsym .dynstr .rel.dyn .rel.plt .plt .text .rodata .ARM.extab .ARM.exidx 
   02     .init_array .fini_array .dynamic .got .bss 
   03     .dynamic 
   04     

Dynamic section at offset 0x225c contains 25 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so]
 0x00000001 (NEEDED)                     Shared library: [libm.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
 0x00000001 (NEEDED)                     Shared library: [libdl.so]
 0x0000000e (SONAME)                     Library soname: [libhello-jni.so]
 0x00000010 (SYMBOLIC)                   0x0
 0x00000019 (INIT_ARRAY)                 0x3248
 0x0000001b (INIT_ARRAYSZ)               8 (bytes)
 0x0000001a (FINI_ARRAY)                 0x3250
 0x0000001c (FINI_ARRAYSZ)               12 (bytes)
 0x00000004 (HASH)                       0xd4
 0x00000005 (STRTAB)                     0x698
 0x00000006 (SYMTAB)                     0x278
 0x0000000a (STRSZ)                      1194 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000003 (PLTGOT)                     0x3344
 0x00000002 (PLTRELSZ)                   48 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0xb8c
 0x00000011 (REL)                        0xb44
 0x00000012 (RELSZ)                      72 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x00000016 (TEXTREL)                    0x0
 0x6ffffffa (RELCOUNT)                   7
 0x00000000 (NULL)                       0x0

Relocation section '.rel.dyn' at offset 0xb44 contains 9 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000c24  00000017 R_ARM_RELATIVE   
00003254  00000017 R_ARM_RELATIVE   
00003368  00000017 R_ARM_RELATIVE   
0000336c  00000017 R_ARM_RELATIVE   
00003374  00000017 R_ARM_RELATIVE   
00003378  00000017 R_ARM_RELATIVE   
00003380  00000017 R_ARM_RELATIVE   
00003370  00001015 R_ARM_GLOB_DAT    00000000   __cxa_call_unexpected
0000337c  00003215 R_ARM_GLOB_DAT    00000000   __gnu_Unwind_Find_exid

Relocation section '.rel.plt' at offset 0xb8c contains 6 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00003350  00000d16 R_ARM_JUMP_SLOT   00000000   __cxa_begin_cleanup
00003354  00001216 R_ARM_JUMP_SLOT   00000000   memcpy
00003358  00001416 R_ARM_JUMP_SLOT   00000000   __cxa_finalize
0000335c  00001f16 R_ARM_JUMP_SLOT   00000000   abort
00003360  00002a16 R_ARM_JUMP_SLOT   00000000   __cxa_type_match
00003364  00003216 R_ARM_JUMP_SLOT   00000000   __gnu_Unwind_Find_exid

There are no unwind sections in this file.

Symbol table '.dynsym' contains 66 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000c18     0 SECTION LOCAL  DEFAULT    7 
     2: 00003390     0 SECTION LOCAL  DEFAULT   15 
     3: 00001c64    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_ForcedUnwind
     4: 00001668   164 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_RaiseExcepti
     5: 00001b20     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_VFP
     6: 00001c40    36 FUNC    GLOBAL DEFAULT    7 _Unwind_Resume_or_Rethrow
     7: 00002248     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_end
     8: 000011c0     8 FUNC    GLOBAL DEFAULT    7 __aeabi_unwind_cpp_pr0
     9: 00001d4c    44 FUNC    GLOBAL DEFAULT    7 _Unwind_GetRegionStart
    10: 00001c40    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_Resume_or_Rethr
    11: 000033a0     0 NOTYPE  GLOBAL DEFAULT  ABS _bss_end__
    12: 00001c88    36 FUNC    GLOBAL DEFAULT    7 _Unwind_Backtrace
    13: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_begin_cleanup
    14: 00001b04    20 FUNC    GLOBAL DEFAULT    7 __restore_core_regs
    15: 00001b40     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_VFP_D_1
    16: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_call_unexpected
    17: 00000cf0     8 FUNC    GLOBAL DEFAULT    7 _Unwind_GetCFA
    18: 00000000     0 FUNC    GLOBAL DEFAULT  UND memcpy
    19: 00000c8c    76 FUNC    GLOBAL DEFAULT    7 _Unwind_VRS_Set
    20: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_finalize
    21: 00003250     0 NOTYPE  GLOBAL DEFAULT   12 __FINI_ARRAY__
    22: 00003384     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start__
    23: 00001404   212 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Backtrace
    24: 00003390     4 OBJECT  GLOBAL DEFAULT   15 __dso_handle
    25: 00001b30     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_VFP_D
    26: 00001798   876 FUNC    GLOBAL DEFAULT    7 _Unwind_VRS_Pop
    27: 000011b0     8 FUNC    WEAK   DEFAULT    7 __aeabi_unwind_cpp_pr2
    28: 00001c88    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_Backtrace
    29: 00002168     0 NOTYPE  GLOBAL DEFAULT  ABS __exidx_start
    30: 00001bf8    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_RaiseException
    31: 00000000     0 FUNC    GLOBAL DEFAULT  UND abort
    32: 00001c1c    36 FUNC    GLOBAL DEFAULT    7 ___Unwind_Resume
    33: 00001b48     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_WMMX
    34: 00001b18     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_VFP
    35: 00001c1c    36 FUNC    GLOBAL DEFAULT    7 _Unwind_Resume
    36: 00000cfc    32 FUNC    GLOBAL DEFAULT    7 _Unwind_DeleteException
    37: 00000cf8     4 FUNC    GLOBAL DEFAULT    7 _Unwind_Complete
    38: 000033a0     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_end__
    39: 00003248     0 NOTYPE  GLOBAL DEFAULT   11 __INIT_ARRAY__
    40: 00001d78   888 FUNC    GLOBAL DEFAULT    7 __gnu_unwind_execute
    41: 00001b28     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_VFP_
    42: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __cxa_type_match
    43: 0000172c   108 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Resume
    44: 00001b38     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_VFP_
    45: 00001bf8    36 FUNC    GLOBAL DEFAULT    7 _Unwind_RaiseException
    46: 00003384     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    47: 000033a0     0 NOTYPE  GLOBAL DEFAULT  ABS __end__
    48: 000015f4    28 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_ForcedUnwind
    49: 0000170c    32 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Resume_or_Re
    50: 00000000     0 FUNC    WEAK   DEFAULT  UND __gnu_Unwind_Find_exidx
    51: 00001b04    20 FUNC    GLOBAL DEFAULT    7 restore_core_regs
    52: 00001be4     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_WMMXC
    53: 00001d04     8 FUNC    GLOBAL DEFAULT    7 _Unwind_GetTextRelBase
    54: 00000c29    24 FUNC    GLOBAL DEFAULT    7 Java_com_example_hellojni
    55: 00001d14    56 FUNC    GLOBAL DEFAULT    7 _Unwind_GetLanguageSpecif
    56: 00000c40    76 FUNC    GLOBAL DEFAULT    7 _Unwind_VRS_Get
    57: 00001bd0     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Restore_WMMX
    58: 000020f0    64 FUNC    GLOBAL DEFAULT    7 __gnu_unwind_frame
    59: 00001c64    36 FUNC    GLOBAL DEFAULT    7 _Unwind_ForcedUnwind
    60: 00003384     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    61: 000033a0     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    62: 00001b8c     0 FUNC    GLOBAL DEFAULT    7 __gnu_Unwind_Save_WMMXD
    63: 000011b8     8 FUNC    WEAK   DEFAULT    7 __aeabi_unwind_cpp_pr1
    64: 00001d0c     8 FUNC    GLOBAL DEFAULT    7 _Unwind_GetDataRelBase
    65: 00003384     0 NOTYPE  GLOBAL DEFAULT   14 __data_start

Histogram for bucket list length (total of 37 buckets):
 Length  Number     % of total  Coverage
      0  5          ( 13.5%)
      1  14         ( 37.8%)     22.2%
      2  9          ( 24.3%)     50.8%
      3  6          ( 16.2%)     79.4%
      4  2          (  5.4%)     92.1%
      5  1          (  2.7%)    100.0%

No version information found in this file.
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "5TE"
  Tag_CPU_arch: v5TE
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align8_needed: Yes
  Tag_ABI_align8_preserved: Yes, except leaf SP
  Tag_ABI_enum_size: int
Run Code Online (Sandbox Code Playgroud)

您可能会看到与@Joel F提供的区别,特别是有关堆栈展开的内容(对于C++异常?)

更新#2

问题在于NDK r6b中包含的工具链,特别是它是关于链接器的.感谢@Joel F关于以前NDK发布的胶水.我在NDK r6b旁边安装了NDK r5c并比较了结果.编译器通过两个工具链生成相同的目标文件,但在链接后结果不同.

Joe*_*l F 4

编辑 3 我能够使用 NDK r6b 重现 10KB hello-jni 二进制文件。我在这里发现了一个可怕的黑客行为。基本上将这一行放入您的文件之一中:

char __aeabi_unwind_cpp_pr0[0];
Run Code Online (Sandbox Code Playgroud)

但是你的代码将缺乏异常处理(我认为这是重点-fno-exceptions......)

无论如何,这使 libhello-jni.so 对我来说减少到了 2228 字节。仍然比 r5c 大,但比 10KB 小很多。

编辑2 是的,您的 readelf 输出中似乎有很多与 C++ 相关的开销。也许他们在 r5c 和 r6b 之间做了一些改变?r5c的hello-jni.c中没有C++代码。

我有 160 行 C 代码,NDK r5c 将其缩减为 3.8KB .so。请尝试以下操作来查看造成大小的原因:

/path/to/ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/<platform>/bin/arm-linux-androideabi-readelf -a libmylib.so
Run Code Online (Sandbox Code Playgroud)

编辑 我使用 NDK r5c 构建了 hello-jni 示例,生成的libhello-jni.so文件为 1588 字节。

构建命令:

ndk-build V=1
Run Code Online (Sandbox Code Playgroud)

构建输出: http: //pastebin.com/AdRDVbnF(显然SO对行长度或其他东西有限制)。

输出来自readelf -a libhello-jni.so

ELF 标头:
  魔术:7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  等级:ELF32
  数据:2 的补码,小端
  版本:1(当前)
  操作系统/ABI:UNIX - 系统 V
  ABI 版本:0
  类型:DYN(共享目标文件)
  机器:ARM
  版本:0x1
  入口点地址:0x2dc
  程序头的开始:52(文件中的字节)
  节头开始:1108(文件中的字节)
  标志:0x5000002,有入口点,版本 5 EABI
  该标头的大小:52(字节)
  程序头大小:32(字节)
  程序头数量:5
  节头大小:40(字节)
  节标题数量:12
  节头字符串表索引:11

节标题:
  [编号] 名称 类型 地址 关闭尺寸 ES Flg Lk Inf Al
  [0] 空 00000000 000000 000000 00 0 0 0
  [ 1] .hash 哈希 000000d4 0000d4 00004c 04 A 2 0 4
  [2].dynsym DYNSYM 00000120 000120 0000e0 10 A 3 2 4
  [3] .dynstr STRTAB 00000200 000200 0000db 00 A 0 0 1
  [4] .text PROGBITS 000002dc 0002dc 00002c 00 AX 0 0 4
  [5] .rodata PROGBITS 00000308 000308 000014 00 A 0 0 4
  [6].ARM.exidx ARM_EXIDX 0000031c 00031c 000008 00 AL 4 0 4
  [7].动态动态00001324 000324 000088 08 WA 3 0 4
  [8].得到PROGBITS 000013ac 0003ac 00000c 04 WA 0 0 4
  [ 9] .comment PROGBITS 00000000 0003b8 000012 00 0 0 1
  [10].ARM.attributes ARM_ATTRIBUTES 00000000 0003ca 000029 00 0 0 1
  [11].shstrtab STRTAB 00000000 0003f3 000061 00 0 0 1
标志的关键:
  W(写入)、A(分配)、X(执行)、M(合并)、S(字符串)
  I(信息)、L(链接顺序)、G(组)、x(未知)
  O(需要额外的操作系统处理)o(特定于操作系统)、p(特定于处理器)

该文件中没有节组。

程序标题:
  类型 偏移 VirtAddr PhysAddr FileSiz MemSiz Flg 对齐
  EXIDX 0x00031c 0x0000031c 0x0000031c 0x00008 0x00008 R 0x4
  加载 0x000000 0x00000000 0x00000000 0x00324 0x00324 重新 0x1000
  加载 0x000324 0x00001324 0x00001324 0x00094 0x00094 读写 0x1000
  动态 0x000324 0x00001324 0x00001324 0x00088 0x00088 读写 0x4
  GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 读写 0x4

 节到段的映射:
  分段部分...
   00.ARM.exidx
   01 .hash .dynsym .dynstr .text .rodata .ARM.exidx
   02.动态.got
   03.动态
   04     

偏移量 0x324 处的动态部分包含 12 个条目:
  标签类型名称/值
 0x00000001(需要)共享库:[libc.so]
 0x00000001(需要)共享库:[libstdc++.so]
 0x00000001(需要)共享库:[libm.so]
 0x00000001(需要)共享库:[libdl.so]
 0x0000000e (SONAME) 库soname: [libhello-jni.so]
 0x00000010(符号)0x0
 0x00000004(哈希)0xd4
 0x00000005(STRTAB)0x200
 0x00000006(SYMTAB)0x120
 0x0000000a(STRSZ)219(字节)
 0x0000000b(SYMENT)16(字节)
 0x00000000(空)0x0

此文件中没有重定位。

该文件中没有展开部分。

符号表“.dynsym”包含 14 个条目:
   Num:值大小类型绑定 Vis Ndx 名称
     0: 00000000 0 无类型本地默认值
     1: 000002dc 0 部分本地默认值 4
     2: 00000324 0 NOTYPE 全局默认 ABS __exidx_end
     3: 00000000 0 FUNC 全局默认值和 __aeabi_unwind_cpp_pr0
     4: 000013b8 0 NOTYPE 全局默认 ABS _bss_end__
     5: 000013b8 0 NOTYPE 全局默认 ABS __bss_start__
     6: 0000031c 0 NOTYPE 全局默认 ABS __exidx_start
     7: 000013b8 0 NOTYPE 全局默认 ABS __bss_end__
     8: 000013b8 0 NOTYPE 全局默认 ABS __bss_start
     9: 000013b8 0 NOTYPE 全局默认 ABS __end__
    10:000002dd 44 FUNC 全局默认值 4 Java_com_example_hellojni
    11: 000013b8 0 NOTYPE 全局默认 ABS _edata
    12: 000013b8 0 NOTYPE 全局默认 ABS _end
    13: 000013b8 0 NOTYPE 全局默认 8 __data_start

桶列表长度直方图(总共 3 个桶):
 长度 数量 占总覆盖率的百分比
      0 0 (0.0%)
      1 0 ( 0.0%) 0.0%
      2 1 ( 33.3%) 16.7%
      3 0 (0.0%) 16.7%
      4 1 ( 33.3%) 50.0%
      5 0 (0.0%) 50.0%
      6 1 ( 33.3%) 100.0%

在此文件中找不到版本信息。
属性部分:aeabi
文件属性
  Tag_CPU_name:“5TE”
  Tag_CPU_arch:v5TE
  Tag_THUMB_ISA_use:Thumb-1
  Tag_ABI_PCS_wchar_t:4
  Tag_ABI_FP_denormal:需要
  Tag_ABI_FP_exceptions:需要
  Tag_ABI_FP_number_model:IEEE 754
  Tag_ABI_align8_needed:是
  Tag_ABI_align8_preserved:是,除了叶 SP
  Tag_ABI_enum_size:整数
  Tag_ABI_optimization_goals:积极的调试