调试符号:release需要剥离
- 文件通过汇编器生成目标文件时 会生成一个
DWARF格式的调试文件,它被放在machO文件中的DWARF段; - 在目标文件中只是一个
section段,不会跟符号表产生关系; - 而在链接过程中
DWARF段会被干掉并放到可执行文件的符号表中
编译链接过程
-
将代码尽可能的转成汇编语言
-
将符号归类——上例使用的
NSLog属于导入符号(存在别的machO文件中)它会在链接时才确定它的内存地址,因此需要暂存起来——放到重定位符号表中
符号表分类
- 全局变量-全局符号,静态变量 本地符号
- 二级命名空间&一级命名空间,链接器默认会采用二级命名空间,也就是除了记录符号之外,还会记录符号属于哪个machO的,比如记录NSLog属于Foundation
导入符号和导出符号
- 对于本machO文件来说,导入了
NSLog符号(导入符号) - 对于Foundation来说,它导出了
NSLog符号(导出符号)导出符号一定是全局符号:全局符号如果不想给别人用,那就不是导出符号了间接符号表用来保存外部符号,即导出符号(NSLog)
关键点:符号的理解:外面可以通过符号(NSLog)调用Foundition的NSLog方法,但是仅Foundition内部使用的符号是可以剥离的,因为外部不用。
以及:APP一般不希望别人用到APP的符号,所以APP可以strip所有本地和全局的符号,只保留间接符号表
- 平时在定义
全局符号/全局变量的时候,需要注意它在编译时会作为导出符号被别的空间/模块所使用 - 一个Objective-C对象的声明,会一个
导出符号(声明在.m也不耽误导出),所以可以指定对应符号不导出。减少包体积,(可以通过在Xcconfig文件中这么定义,就能指定对应的“导出符号”不导出——不但可以减少App体积,同时无法通过符号访问对应类会更加安全(OC类默认是导出的))
重新导出符号 (别的模块也想用NSLog)
- 需要重新导出——放到本文件的导出符号表中——外界可以使用这个符号
- 那么就需要用到链接器中的参数
-alias(起别名)会把间接符号表变成导出符号
Strip原理
strip本质:实际上在修改macho中的内容
动态库的关键点要留下导出符号供外部使用(Foundtion私有方法不导出,NSlog导出)
App关键点不需要供外部使用,但是需要保留外部导入的符号,比如要保留NSLog
静态库 只能剥离调试符号
静态库、目标文件:找到__DWARF段进行移除,只能剥离调试符号
动态库、可执行文件:遍历符号表->删除对应的符号,实质是留下导出符号给外部使用
就符号而言,App链接同等代码量的静态库和动态库,哪个包体积更小
静态库小:集成到主工程后,里面的全局符号,本地符号,导出符号,都可以被剥离。但动态库的导出符号不能被剥离。 再直白点:静态库自己的所有符号(除了导入符号NSLog),都在主工程符号表中,都可以被剥离。但是动态库的导出符号在主工程间接符号表中,不能被剥离.
1.静态库符号表都会放到主工程符号表中,app除了导入符号(NSLog),都会被剥离。 2.动态库符号表在主工程间接符号表中,动态库的导出符号不会被剥离
调试符号是什么
什么是符号1
什么是符号2
在iOS中,调试符号的格式为DWARF(Debug With Arbitrary Record Format),它记录了函数名、文件名、行数。
调试符号:包括行号信息的调试符号信息,行号信息中记录了函数和变量所对应的文件和文件行号。
总结:
调试符号和本地符号是可以脱去的,我们自己的App的Mach O文件中的间接符号表里面的符号是不能脱出的,里面存放的是系统动态库的导出符号,是需要在动态库中动态链接的。- APP一般不希望别人用到APP的符号,所以APP可以strip所有本地和全局的符号,只保留间接符号表