符号与链接

328 阅读4分钟

调试符号:release需要剥离

  • 文件通过汇编器生成目标文件时 会生成一个DWARF格式的调试文件,它被放在machO文件中的DWARF段
  • 在目标文件中只是一个section段,不会跟符号表产生关系;
  • 而在链接过程中DWARF段会被干掉并放到可执行文件的符号表中

编译链接过程

  • 将代码尽可能的转成汇编语言

  • 将符号归类——上例使用的NSLog属于导入符号(存在别的machO文件中)它会在链接时才确定它的内存地址,因此需要暂存起来——放到重定位符号表

符号表分类

  1. 全局变量-全局符号,静态变量 本地符号
  2. 二级命名空间&一级命名空间,链接器默认会采用二级命名空间,也就是除了记录符号之外,还会记录符号属于哪个machO的,比如记录NSLog属于Foundation

导入符号和导出符号

  • 对于本machO文件来说,导入了NSLog符号(导入符号)
  • 对于Foundation来说,它导出了NSLog符号(导出符号) 导出符号一定是全局符号:全局符号如果不想给别人用,那就不是导出符号了 间接符号表用来保存外部符号,即导出符号(NSLog)

关键点:符号的理解:外面可以通过符号(NSLog)调用Foundition的NSLog方法,但是仅Foundition内部使用的符号是可以剥离的,因为外部不用。 以及:APP一般不希望别人用到APP的符号,所以APP可以strip所有本地和全局的符号,只保留间接符号表

  • 平时在定义全局符号/全局变量的时候,需要注意它在编译时会作为导出符号被别的空间/模块所使用
  • 一个Objective-C对象的声明,会一个导出符号(声明在.m也不耽误导出),所以可以指定对应符号不导出。减少包体积,(可以通过在Xcconfig文件中这么定义,就能指定对应的“导出符号”不导出——不但可以减少App体积,同时无法通过符号访问对应类会更加安全(OC类默认是导出的))

重新导出符号 (别的模块也想用NSLog)

  1. 需要重新导出——放到本文件的导出符号表中——外界可以使用这个符号
  2. 那么就需要用到链接器中的参数-alias(起别名)会把间接符号表变成导出符号

Strip原理

strip本质:实际上在修改macho中的内容

动态库的关键点要留下导出符号供外部使用(Foundtion私有方法不导出,NSlog导出)

App关键点不需要供外部使用,但是需要保留外部导入的符号,比如要保留NSLog

静态库 只能剥离调试符号

静态库目标文件:找到__DWARF段进行移除,只能剥离调试符号 动态库可执行文件:遍历符号表->删除对应的符号,实质是留下导出符号给外部使用

就符号而言,App链接同等代码量的静态库和动态库,哪个包体积更小

静态库小:集成到主工程后,里面的全局符号,本地符号,导出符号,都可以被剥离。但动态库的导出符号不能被剥离。 再直白点:静态库自己的所有符号(除了导入符号NSLog),都在主工程符号表中,都可以被剥离。但是动态库的导出符号在主工程间接符号表中,不能被剥离.

1.静态库符号表都会放到主工程符号表中,app除了导入符号(NSLog),都会被剥离。 2.动态库符号表在主工程间接符号表中,动态库的导出符号不会被剥离

调试符号是什么

什么是符号1 什么是符号2iOS中,调试符号的格式为DWARF(Debug With Arbitrary Record Format),它记录了函数名、文件名、行数

调试符号:包括行号信息的调试符号信息,行号信息中记录了函数和变量所对应的文件和文件行号

总结:

  • 调试符号本地符号是可以脱去的,我们自己的App的Mach O文件中的间接符号表里面的符号是不能脱出的,里面存放的是系统动态库的导出符号,是需要在动态库中动态链接的。
  • APP一般不希望别人用到APP的符号,所以APP可以strip所有本地和全局的符号,只保留间接符号表

参考链接