0
点赞
收藏
分享

微信扫一扫

iOS强化 : 符号 Symbol

悲催博士僧 2021-09-19 阅读 86

前言 :
  • 之前接触过Bugly,在Bugly文档中心 这里接触了一些iOS符号表的内容,符号(Symbol)是日常开发中经常接触的一个概念,虽然日常开发中直接应用的场景比较少,但符号编译期和运行时都扮演了重要的角色。今天就来好好学习下符号 Symbol,并为后面学习动态库静态库学习做准备。

  • 参考:帅驼驼

目录 :
    1. 符号 Symbol的定义
    1. 符号表的种类
    1. 符号的实际探究
    1. 符号的扩展
  • 5 .符号的剥离Strip命令

一、 符号 Symbol的定义

  • 符号 Symbol
  • 符号表Symbol Table

符号表中存储符号的数据结构如下:

struct nlist_64 {  
   union {       
      uint32_t  n_strx; /* index into the string table */   
    } n_un;  
   uint8_t n_type;        /* type flag, see below */
   uint8_t n_sect;        /* p number or NO_SECT */    
   uint16_t n_desc;       /* see <mach-o/stab.h> */   
   uint64_t n_value;      /* value of this symbol (or stab offset) */
};

符号表 在Mach-O中的位置

通过两个Load Commands,描述Symbol Table的大小和位置,以及其他元数据

  • LC_SYMTAB :用来描述该文件的符号表。不论是静态链接器还是动态链接器在链接此文件时,都要使用该Load Command。调试器也可以使用该Load Command找到调试信息

  • LC_DYSYMTAB :描述动态链接器使用其他的Symbol Table信息,

struct symtab_command {
    // 共有属性。指明当前描述的加载命令,当前被设置为LC_SYMTAB
    uint32_t cmd ;
    // 共有属性。指明加载命令的大小,当前被设置为sizeof(symtab_command)
    uint32_t cmdsize;
    // 表示从文件开始到symbol table所在位置的偏移量。symbol table用[nlist]来表示
    uint32_t symoff;
    // 符号表内符号的数量
    uint32_t nsyms;
    // 表示从文件开始到string table所在位置的偏移量。
    uint32_t stroff;
    // 表示string table大小(以byteカ单位)
    uint32_t strsize;
};

二、符号表的种类

2.1 分类

按照模块区分:
  • 全局符号(Global Symbol) : 整个项目可见
  • 本地符号(Local Symbol) : 当前类可见
按照位置划分:
  • 外部符号 : 符号不在当前文件,需要ld或者dyld在链接的时候解决
  • 非外部符号 : 即当前文件内的符号
按照功能分:
Type 说明
f File
F Function
O Data
d Debug
ABS Absolute
COM Common
UND 未定义
按照符号种类划分:
Type 说明
U undefined(未定义)
A absolute(绝对符号)
T text section symbol__TEXT.__text
D data section symbol__DATA.__data
B bss section symbol__DATA.__bss
C common symbol(只能出现在MH_OBJECT类型的Mach-O⽂件中)
- debugger symbol table
S 除了上⾯所述的,存放在其他section的内容,例如未初始化的全局变量存放在(__DATA,__common)中
I indirect symbol(符号信息相同,代表同⼀符号)
u 动态共享库中的⼩写u表示⼀个未定义引⽤对同⼀库中另⼀个模块中私有外部符号

注:标记Type,⼩写代表本地符号(local symbol

三、符号的实际探究

3.1 可见性

有个很常见的case,就是你有1000个函数,但只有10个函数是公开的,希望最后生成的动态库里不包含其他990个函数的符号,这时候就可以用clang的attribute来实现:

//符号可被外部链接__attribute__((visibility("default")))//符号不会被放到Dynamic Symbol Table里,意味着不可以再被其他编译单元链接__attribute__((visibility("hidden")))

clang来提供了一个全局的开关,用来设置符号的默认可见性:

如果动态库的Target把这个开关打开,会发现动态库仍然能编译通过,但是App会报一堆链接错误,因为符号变成了hidden。

但这是一种常见的编译方式:让符号默认是Hidden的,即-fvisibility=hidden,然后手动为每个接口加上__attribute__((visibility("default")))

//头文件#define LH_EXPORT __attribute__((visibility("default")))LH_EXPORT void method_1(void);//实现文件LH_EXPORT void method_1(){    NSLog(@"1");}

举例 :

3.2 作用域

导入符号导出符号

  • 动态库因为不知道外面是如何使用的,所以最好的方式是所有头文件暴露出的符号全部导出来。从包大小的角度考虑,肯定是用到哪些符号,保留哪些符号对应的代码,ld提供了这样一个方案,通过exported_symbol来只保留特定的符号
#import "LGOneObject.h"

@interface LGOneObject : NSObject

- (void)testOneObject;

@end

@implementation LGOneObject

- (void)testOneObject {
    NSLog(@"testOneObject");
}

@end

3.3 Weak Symbol

Common Symbol
重新导出符号

四、符号的扩展

查看项目使用的三方库和符号等信息
# Path: /Users/zang/Library/Developer/Xcode/DerivedData/MachOAndSymbol-bdzlylfoorwnhggerxdmwocpeyad/Build/Products/Debug/MachOAndSymbol
# Arch: x86_64
# Object files:
[  0] linker synthesized
[  1] /Users/zang/Library/Developer/Xcode/DerivedData/MachOAndSymbol-bdzlylfoorwnhggerxdmwocpeyad/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/LGOneObject.o
[  2] /Users/zang/Library/Developer/Xcode/DerivedData/MachOAndSymbol-bdzlylfoorwnhggerxdmwocpeyad/Build/Intermediates.noindex/MachOAndSymbol.build/Debug/MachOAndSymbol.build/Objects-normal/x86_64/main.o
[  3] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk/System/Library/Frameworks//Foundation.framework/Foundation.tbd
# Sections:
# Address   Size        Segment Section
0x100003EF0 0x0000006F  __TEXT  __text
0x100003F60 0x00000006  __TEXT  __stubs
0x100003F68 0x0000001A  __TEXT  __stub_helper
0x100003F82 0x00000011  __TEXT  __cstring
0x100003F93 0x0000000C  __TEXT  __objc_classname
0x100003F9F 0x0000000E  __TEXT  __objc_methname
0x100003FAD 0x00000008  __TEXT  __objc_methtype
0x100003FB8 0x00000048  __TEXT  __unwind_info
0x100004000 0x00000008  __DATA_CONST    __got
0x100004008 0x00000040  __DATA_CONST    __cfstring
0x100004048 0x00000008  __DATA_CONST    __objc_classlist
0x100004050 0x00000008  __DATA_CONST    __objc_imageinfo
0x100008000 0x00000008  __DATA  __la_symbol_ptr
0x100008008 0x000000B0  __DATA  __objc_const
0x1000080B8 0x00000050  __DATA  __objc_data
0x100008108 0x00000010  __DATA  __data
0x100008118 0x00000004  __DATA  __bss
0x100008120 0x00000010  __DATA  __common
# Symbols:
# Address   Size        File  Name
0x100003EF0 0x00000027  [  1] -[LGOneObject testOneObject]
0x100003F20 0x0000003F  [  2] _main
0x100003F60 0x00000006  [  3] _NSLog
0x100003F68 0x00000010  [  0] helper helper
0x100003F78 0x0000000A  [  3] _NSLog
0x100003F82 0x0000000E  [  1] literal string: testOneObject
0x100003F90 0x00000003  [  2] literal string: %d
0x100003F93 0x0000000C  [  1] literal string: LGOneObject
0x100003F9F 0x0000000E  [  1] literal string: testOneObject
0x100003FAD 0x00000008  [  1] literal string: v16@0:8
0x100003FB8 0x00000048  [  0] compact unwind info
0x100004000 0x00000008  [  0] non-lazy-pointer-to-local: dyld_stub_binder
0x100004008 0x00000020  [  1] CFString
0x100004028 0x00000020  [  2] CFString
0x100004048 0x00000008  [  1] objc-cat-list
0x100004050 0x00000008  [  0] objc image info
0x100008000 0x00000008  [  3] _NSLog
0x100008008 0x00000048  [  1] __OBJC_METACLASS_RO_$_LGOneObject
0x100008050 0x00000020  [  1] __OBJC_$_INSTANCE_METHODS_LGOneObject
0x100008070 0x00000048  [  1] __OBJC_CLASS_RO_$_LGOneObject
0x1000080B8 0x00000028  [  1] _OBJC_METACLASS_$_LGOneObject
0x1000080E0 0x00000028  [  1] _OBJC_CLASS_$_LGOneObject
0x100008108 0x00000008  [  0] __dyld_private
0x100008110 0x00000004  [  2] _global_init_value
0x100008114 0x00000004  [  2] _static_init_value
0x100008118 0x00000004  [  2] _static_uninit_value
0x100008120 0x00000008  [  2] _global_uninit_value
0x100008128 0x00000008  [  2] _default_x

Section的名称与作用
名称 作用
TEXT.text 可执行的机器码
TEXT.cstring 去重后的C字符串
TEXT.const 初始化过的常量
TEXT.stubs 符号桩。lazybinding的表对 应项指针指向的地址的代码
TEXT.stub_ helper 辅助函数。当在lazybinding的表中没有找到对应项的指针表示的真正的符号地址的时候,指向这
TEXT.unwind_info 存储处理异常情况信息
TEXT.eh_frame 调试辅助信息
DATA.data 初始化过的可变的数据
DATA.nI_symbol_ptr lazy-binding的指针表,每个表中的指针指向一个在装载过程中,被动态链接器搜索完成的符号
DATA.Ia_symbol_ptr lazy-binding的指针表,每个表中的指针一开始指向stub_helper
DATA.const 没有初始化过的常量
DATA.mod_init_func 初始化函数,在main之前调用
DATA.mod_term_func 终止函数,在main返回之后调用
DATA.bss 没有初始化的静态变量
DATA.common 没有初始化过的符号声明(for example, int I;
Swift符号表
0000000100003f8a lw    O __TEXT,__swift5_typeref _symbolic _____ 14MachOAndSymbol012LGSwiftClassC0C
0000000100003f90 l     O __TEXT,__swift5_fieldmd _$s14MachOAndSymbol012LGSwiftClassC0CMF
0000000100008020 l     O __DATA,__objc_const __METACLASS_DATA__TtC14MachOAndSymbol18LGSwiftClassSymbol
0000000100008068 l     O __DATA,__objc_const __DATA__TtC14MachOAndSymbol18LGSwiftClassSymbol
00000001000080e8 l     O __DATA,__data _$s14MachOAndSymbol012LGSwiftClassC0CMf
0000000100003d90 g     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC0C09testSwiftC0yyF
0000000100003f78 g     O __TEXT,__const _$s14MachOAndSymbol012LGSwiftClassC0C09testSwiftC0yyFTq
0000000100003e10 g     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC0CACycfC
0000000100003f80 g     O __TEXT,__const _$s14MachOAndSymbol012LGSwiftClassC0CACycfCTq
0000000100003e40 g     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC0CACycfc
0000000100003e60 g     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC0CMa
00000001000080c0 g     O __DATA,__data _$s14MachOAndSymbol012LGSwiftClassC0CMm
0000000100003f44 g     O __TEXT,__const _$s14MachOAndSymbol012LGSwiftClassC0CMn
00000001000080f8 g     O __DATA,__data _$s14MachOAndSymbol012LGSwiftClassC0CN
0000000100003dd0 g     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC0CfD
0000000100003db0 g     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC0Cfd
0000000000000000         *UND* _OBJC_CLASS_$__TtCs12_SwiftObject
0000000000000000         *UND* _OBJC_METACLASS_$__TtCs12_SwiftObject

0000000100003d10 l     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLC09testSwiftC0yyF
0000000100003d30 l     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCfd
0000000100003d50 l     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCfD
0000000100003d90 l     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCMa
0000000100003db0 l     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCADycfC
0000000100003de0 l     F __TEXT,__text _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCADycfc
0000000100003f1c lw    O __TEXT,__const _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCMXX
0000000100003f44 l     O __TEXT,__const _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCMn
0000000100003f78 l     O __TEXT,__const _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLC09testSwiftC0yyFTq
0000000100003f80 l     O __TEXT,__const _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCADycfCTq
0000000100003f8a lw    O __TEXT,__swift5_typeref _symbolic _____ 14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLC
0000000100003f90 l     O __TEXT,__swift5_fieldmd _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCMF
0000000100008020 l     O __DATA,__objc_const __METACLASS_DATA__TtC14MachOAndSymbolP33_66093EBE10D00815F1A5CBD65FFF466118LGSwiftClassSymbol
0000000100008068 l     O __DATA,__objc_const __DATA__TtC14MachOAndSymbolP33_66093EBE10D00815F1A5CBD65FFF466118LGSwiftClassSymbol
00000001000080c0 l     O __DATA,__data _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCMm
00000001000080e8 l     O __DATA,__data _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCMf
00000001000080f8 l     O __DATA,__data _$s14MachOAndSymbol012LGSwiftClassC033_66093EBE10D00815F1A5CBD65FFF4661LLCN
0000000000000000         *UND* _OBJC_CLASS_$__TtCs12_SwiftObject
0000000000000000         *UND* _OBJC_METACLASS_$__TtCs12_SwiftObject

$(SRCROOT)$(PROJECT_DIR)的区别

五、 符号的剥离Strip命令

  • 符号表中有些符号是必须的,但是很多符号都是去掉的 , strip经常用来去除目标文件中的一些符号表、调试符号表信息,以减小程序的大小;
  • strip命令:移除或修改符号表中的符号。App 进行脱符号,可以将本地符号,全局符号全部脱去(All symbols),只留下间接符号表中的符号。
5.1 如何脱去调试符号
5.2 如何脱去All Symbols
  • 静态库进行脱符号,放置在重定位符号表中的符号不能脱去,能脱去的只要调试符号(Debugging Symbols)

调试符号:由汇编器生成.o文件时,会生成一个DWARF格式的调试信息,它会被放到__DWARF段,在链接是,会将__DWARF段放到符号表中,链接后所有的符号都放在符号表中

  • 动态库进行脱符号,只要不是全局符号都可以被干掉(Non-Global Symbols)

如何脱去Non-Global Symbols

链接一个静态库,静态库中的符号会合并到APP中,但不会存入间接符号表,然后进行APP脱符号时,可以体积缩小

链接一个动态库,动态库中的符号表会放到APP的间接符号表,然后进行APP脱符号时,间接符号表不能被脱去

5.3 Build Setting的Strip Style选择
  • Debugging Symbols
  • All Symbols
  • Non-Global Symbols
5.4 Strip执行的时机

编译完成执行脚本后 ,签名之前,所以这是后剥离符号 已经不起作用了

5.5 Strip剥离符号
  • -x : non_global
  • 无参数: 代表全部符号
  • -S : 剥离调试符号

给链接器传参 -S (去除调试符号)

举报

相关推荐

0 条评论