deadcode strip - ShenYj/ShenYj.github.io GitHub Wiki

deadcode strip

简介

  • 死代码剥离, clang 在链接过程中deadcode strip默认就是生效的

  • dead_strip

    -dead_strip
    
    Remove functions and data that are unreachable by the entry point or exported symbols.

    动态库中使用 -mark_dead_strippable_dylib 参数

    -mark_dead_strippable_dylib
    
    Specifies that the dylib being built can be dead strip by any
    client.  That is, the dylib has no initialization side effects.  So
    if a client links against the dylib, but never uses any symbol from
    it, the linker can optimize away the use of the dylib.
    

    如果并没有使用到该动态库的符号信息,那么链接器将会自动优化该动态库。不会因为路径问题崩溃。 同时,也可以在 App 中使用 -dead_strip_dylibs 获得相同的功能

  • 区分于Other Linker Flags (OTHER_LDFLAGS), Other Linker Flags (OTHER_LDFLAGS)是仅限于静态库的

简单来讲,就是移除入口函数或者没有被导出符号使用到的函数或者代码。


探索

dead_strip与其他链接参数对比

  • 准备test.m文件

    • 定义了全局函数: global_function() 从符号角度讲是导出符号

    • 定义了静态函数: static_function() 从符号角度讲是本地符号

    • 没有使用global_function()全局函数

      #import <Foundation/Foundation.h>
      
      // 全局符号 导出符号
      void global_function() {
          
      }
      
      // 本地符号
      static void static_function() {
          
      }
      int main() {
          // global_function();
          NSLog(@"testApp ------");
          return 0;
      }
  • 脚本生成可执行文件, 并查看__TEXT, 对比-dead_strip作用

    • 加上-dead_strip

      SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk
      
      # 链接OCTest到test.m中生成.o文件
      clang -x objective-c \
      -target x86_64-apple-macos11.1 \
      -fobjc-arc \
      -isysroot $SYSROOT \
      -I./OCStaticLib \
      -c test.m \
      -o test.o
      
      # 将.o生成执行文件
      clang -target x86_64-apple-macos11.1 \
      -fobjc-arc \
      -isysroot $SYSROOT \
      -Xlinker -dead_strip \
      -L./OCStaticLib \
      -lOCTest \
      test.o -o test
      test:
      (__TEXT,__text) section
      _main:
      100003f50:	55	pushq	%rbp
      100003f51:	48 89 e5	movq	%rsp, %rbp
      100003f54:	48 83 ec 10	subq	$16, %rsp
      100003f58:	48 8d 05 a9 00 00 00	leaq	169(%rip), %rax ## Objc cfstring ref: @"testApp ------"
      100003f5f:	c7 45 fc 00 00 00 00	movl	$0, -4(%rbp)
      100003f66:	48 89 c7	movq	%rax, %rdi
      100003f69:	b0 00	movb	$0, %al
      100003f6b:	e8 08 00 00 00	callq	0x100003f78 ## symbol stub for: _NSLog
      100003f70:	31 c0	xorl	%eax, %eax
      100003f72:	48 83 c4 10	addq	$16, %rsp
      100003f76:	5d	popq	%rbp
      100003f77:	c3	retq
    • 不加-dead_strip

      SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk
      
      # 链接OCTest到test.m中生成.o文件
      clang -x objective-c \
      -target x86_64-apple-macos11.1 \
      -fobjc-arc \
      -isysroot $SYSROOT \
      -I./OCStaticLib \
      -c test.m \
      -o test.o
      
      # 将.o生成执行文件
      clang -target x86_64-apple-macos11.1 \
      -fobjc-arc \
      -isysroot $SYSROOT \
      -L./OCStaticLib \
      -lOCTest \
      test.o -o test
      test:
      (__TEXT,__text) section
      _global_function:
      100003f40:	55	pushq	%rbp
      100003f41:	48 89 e5	movq	%rsp, %rbp
      100003f44:	5d	popq	%rbp
      100003f45:	c3	retq
      100003f46:	66 2e 0f 1f 84 00 00 00 00 00	nopw	%cs:(%rax,%rax)
      _main:
      100003f50:	55	pushq	%rbp
      100003f51:	48 89 e5	movq	%rsp, %rbp
      100003f54:	48 83 ec 10	subq	$16, %rsp
      100003f58:	48 8d 05 a9 00 00 00	leaq	169(%rip), %rax ## Objc cfstring ref: @"testApp ------"
      100003f5f:	c7 45 fc 00 00 00 00	movl	$0, -4(%rbp)
      100003f66:	48 89 c7	movq	%rax, %rdi
      100003f69:	b0 00	movb	$0, %al
      100003f6b:	e8 08 00 00 00	callq	0x100003f78 ## symbol stub for: _NSLog
      100003f70:	31 c0	xorl	%eax, %eax
      100003f72:	48 83 c4 10	addq	$16, %rsp
      100003f76:	5d	popq	%rbp
      100003f77:	c3	retq

查看 Mach-O参考: 三、查看Mach-O文件的机器指令(__TEXT)
在没有使用global_function()全局函数情况下, 增加了-dead_strip参数后, 被优化掉了

  • 满足两个条件

    1. 没有被入口点使用
    2. 没有被导出符号使用

OC中的dead_strip

  1. 准备代码

    #import <Foundation/Foundation.h>
    #import "OCTest.h"
    
    int main() {
        OCTest *oc = [OCTest new];
        [oc test:nil];
        NSLog(@"testApp ------");
        return 0;
    }
  2. 脚本

    SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk
    
    # 链接OCTest到test.m中生成.o文件
    clang -x objective-c \
    -target x86_64-apple-macos11.1 \
    -fobjc-arc \
    -isysroot $SYSROOT \
    -I./OCStaticLib \
    -c test.m \
    -o test.o
    
    # 将.o生成执行文件
    clang -target x86_64-apple-macos11.1 \
    -fobjc-arc \
    -isysroot $SYSROOT \
    -Xlinker -dead_strip \
    -Xlinker -all_load \
    -L./OCStaticLib \
    -lOCTest \
    test.o -o test

    在链接过程中默认参数noall_load, 避免Other Linker Flags将代码剥离掉, 所以设置为all_load, 来观察dead_strip的作用效果

  3. 查看__TEXT

    test:
    (__TEXT,__text) section
    -[OCTest test:]:
    100003470:	55	pushq	%rbp
    100003471:	48 89 e5	movq	%rsp, %rbp
    100003474:	48 83 ec 20	subq	$32, %rsp
    100003478:	48 89 7d f8	movq	%rdi, -8(%rbp)
    10000347c:	48 89 75 f0	movq	%rsi, -16(%rbp)
    100003480:	48 c7 45 e8 00 00 00 00	movq	$0, -24(%rbp)
    100003488:	48 8d 7d e8	leaq	-24(%rbp), %rdi
    10000348c:	48 89 d6	movq	%rdx, %rsi
    10000348f:	e8 28 09 00 00	callq	0x100003dbc ## symbol stub for: _objc_storeStrong
    100003494:	48 8d 05 75 0b 00 00	leaq	2933(%rip), %rax ## Objc cfstring ref: @"__TestExample"
    10000349b:	48 89 c7	movq	%rax, %rdi
    10000349e:	b0 00	movb	$0, %al
    1000034a0:	e8 0b 09 00 00	callq	0x100003db0 ## symbol stub for: _NSLog
    1000034a5:	31 c9	xorl	%ecx, %ecx
    1000034a7:	89 ce	movl	%ecx, %esi
    1000034a9:	48 8d 7d e8	leaq	-24(%rbp), %rdi
    1000034ad:	e8 0a 09 00 00	callq	0x100003dbc ## symbol stub for: _objc_storeStrong
    1000034b2:	48 83 c4 20	addq	$32, %rsp
    1000034b6:	5d	popq	%rbp
    ...
    省略

OC中即便没有使用, 静态库中的符号也不会被剥离掉, 因为OC是动态语言

虽然 dead strip 不会干掉 oc中的未使用符号,但是 Other Linker Flags 默认可是 noall_load, 有可能被 noall_load给优化掉,这也是我们使用 framework 静态库时为何需要配置-ObjC

why_live

查看符号为何没有被 dead strip

在链接的时候添加 why_live参数

格式: -Xlinker -why_live -Xliner 符号

e.g.

# 将.o生成执行文件
    clang -target x86_64-apple-macos11.1 \
    -fobjc-arc \
    -isysroot $SYSROOT \
    -Xlinker -dead_strip \
    -Xlinker -all_load \
    -Xlinker -why_live -Xliner _global_function \
    -L./OCStaticLib \
    -lOCTest \
    test.o -o test

终端在执行完链接后就会显示该符号被哪个函数,哪个 .o所使用

_global_function from test.o
  _main from test.o
    _main from test.o
⚠️ **GitHub.com Fallback** ⚠️