Xcode中和symbols有关的几个设置

其实被这个问题困扰了好久,不过秉承着三分钟热度的新年新气象,还是要多弄懂一点(⊙_⊙)ゞ

Symbols是什么东西呢?虽然我对它没有深入的了解,但是大概知道它的作用。摘抄《深入理解计算机系统》里的一些描述:

一个典型的ELF可重定位目标文件包含下面几个节:
... ...
.symtab:一个符号表,它存放在程序中定义和引用的函数和全局变量信息。一些程序员错误地认为必须通过-g选项来编译程序才能得到符号表信息。实际上,每个可重定位目标文件在.symtab中都有一张符号表。然而,和编译器中的符号表不同,.symtab符号表不包含局部变量的条目。
... ...
.debug:一个调试符号表,其条目是程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的C源文件。只有以-g选项调用编译驱动程序时才会得到这张表。
... ...

为了构造可执行文件,链接器必须完成两个主要任务:

  • 符号解析(symbol resolution)。目标文件定义和引用符号。符号解析的目的是将每个符号引用刚好和一个符号定义联系起来。
  • 重定位(relocation)。编译器和汇编器生成从地址0开始的代码和数据节。链接器通过把每个符号定义与一个存储器位置联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器位置,从而重定位这些节。

Objective-C有一些自己的生成符号的规则,比如文档中有提到:

The dynamic nature of Objective-C complicates things slightly. Because the code that implements a method is not determined until the method is actually called, Objective-C does not define linker symbols for methods. Linker symbols are only defined for classes.

Objective-C不会为方法定义链接符号,只会为类定义链接符号。

可以在终端中用nm命令查看一个可重定位文件或可执行文件的符号表,其中加上-a参数可以显示包括调试符号在内的所有符号。

合理的选择与symbols有关的设置选项,可以缩减app的大小,一定程度上能阻碍与源代码有关的信息被攻击者获得。Xcode的build setting中,有不少与symbols有关,现在我来依次试验这几个设置选项,了解一下它们的具体作用。

刚开始的时候,我使用Xcode7.2.1新建了一个工程,以下试验均在run和DEBUG模式下进行。


Generate Debug Symbols [GCC_GENERATE_DEBUGGING_SYMBOLS]



在Xcode7.2.1中,Generate Debug Symbols这个设置在DEBUG和RELEASE下均默认为YES

官方文档对这个设置的说明:

Enables or disables generation of debug symbols. When debug symbols are enabled, the level of detail can be controlled by the build 'Level of Debug Symbols' setting.

调试符号是在编译时生成的。在Xcode中查看构建过程,可以发现,当Generate Debug Symbols选项设置为YES时,每个源文件在编译成.o文件时,编译参数多了-g-gmodules两项。但链接等其他的过程没有变化。

Clang文档对-g的描述是:

Generate complete debug info.

Generate Debug Symbols设置为YES时,编译产生的.o文件会大一些,当然最终生成的可执行文件也大一些。

Generate Debug Symbols设置为NO的时候,在Xcode中设置的断点不会中断。但是在程序中打印[NSThread callStackSymbols],依然可以看到类名和方法名,比如:

** 0   XSQSymbolsDemo                      0x00000001000667f4 -[ViewController viewDidLoad] + 100**

在程序崩溃时,也可以得到带有类名和方法名的函数调用栈


现在把Generate Debug Symbols设置回YES,开始试验下一个设置。


Debug Information Level [CLANG_DEBUG_INFORMATION_LEVEL]



在Xcode 7.2.1中,Debug Information Level的默认值为Compiler default,还有一个选项是Line tables only

官方文档的描述是:

Toggles the amount of debug information emitted when debug symbols are enabled. This can impact the size of the generated debug information, which can matter in some cases for large projects (such as when using LTO).

当我把Debug Information Level设置为Line tables only的时候,然后构建app,每个源文件在编译时,都多了一个编译参数:-gline-tables-only

Clang的文档中这样解释-gline-tables-only

Generate line number tables only.
This kind of debug info allows to obtain stack traces with function names, file names and line numbers (by such tools as gdb or addr2line). It doesn’t contain any other data (e.g. description of local variables or function parameters).

这种类型的调试信息允许获得带有函数名、文件名和行号的函数调用栈,但是不包含其他数据(比如局部变量和函数参数)。

所以当Debug Information Level设置为Line tables only的时候,断点依然会中断,但是无法在调试器中查看局部变量的值:

现在把Debug Information Level设置回Compiler default,然后试验下一个设置。


Strip Linked Product [STRIP_INSTALLED_PRODUCT]



在Xcode7.2.1中,Strip Linked Product在DEBUG和RELEASE下均默认为YES

这是一个让我困惑了很久的设置选项。当我把这一设置选项改为NO的时候,最终构建生成的app大小没有任何变化,这让我觉得很奇怪。

原来,Strip Linked Product也受到Deployment Postprocessing设置选项的影响。在Build Settings中,我们可以看到,Strip Linked Product是在Deployment这栏中的,而Deployment Postprocessing相当于是Deployment的总开关。
Xcode7.2.1中,Deployment Postprocessing在DEBUG和RELEASE下均默认为NO

现在我们把Deployment Postprocessing设置为YES,对比Strip Linked Product设为YESNO的这两种情况,发现当Strip Linked Product设为YES的时候,app的构建过程多了这样两步:

  1. 在app构建的开始,会生成一些.hmap辅助文件;(为什么会多出这一步我好像还不太清楚)
  2. 在app构建的末尾,会执行Strip操作。




Strip Linked Product设为YES的时候,运行app,断点不会中断,在程序中打印[NSThread callStackSymbols]也无法看到类名和方法名:

** 0   XSQSymbolsDemo                      0x000000010001a7f4 XSQSymbolsDemo + 26612**

而在程序崩溃时,函数调用栈中也无法看到类名和方法名,注意右上角变成了unnamed_function:


继续保持Strip Linked ProductDeployment PostprocessingYES,下面来看看Strip Style设置选项。


Strip Style [STRIP_STYLE]



在Xcode7.2.1中,Strip Style在DEBUG和RELEASE下均默认All Symbols

官方文档中对Strip Style的描述:

Defines the level of symbol stripping to be performed on the linked product of the build. The default value is defined by the target's product type. [STRIP_STYLE]

All Symbols - Completely strips the binary, removing the symbol table and relocation information. [all, -s]
Non-Global Symbols - Strips non-global symbols, but saves external symbols. [non-global, -x]
Debugging Symbols - Strips debugging symbols, but saves local and global symbols. [debugging, -S]

选择不同的Strip Style时,app构建末尾的Strip操作会被带上对应的参数。

如果选择debugging symbols的话,函数调用栈中,类名和方法名还是可以看到的。

如果我们构建的不是一个app,而是一个静态库,需要注意,静态库是不可以strip all的。这时构建会失败。想想符号在重定位时的作用,如果构建的静态库真的能剥离所有符号,那么它也就没法被链接了。

现在我们保持Deployment PostprocessingYESStrip Linked Product改回NOStrip Style改回All Symbols,接下来看下一个设置。


Strip Debug Symbols During Copy [COPY_PHASE_STRIP]



网上有很多文章,以为Strip Debug Symbols During Copy开启的时候,app中的调试符号会被剥离掉。我感觉他们混淆了Strip Linked ProductStrip Debug Symbols During Copy的用法。

文档上的描述是:

Activating this setting causes binary files which are copied during the build (e.g., in a Copy Bundle Resources or Copy Files build phase) to be stripped of debugging symbols. It does not cause the linked product of a target to be stripped (use Strip Linked Product for that).

Strip Debug Symbols During Copy中的During Copy是什么意思呢?我觉得可能是app中引入的某些类型的库,在app的构建过程中需要被复制一次。虽然我暂时没找全究竟什么样的“库”需要在app构建时被复制,但是我发现,当app中包含extension或者watch app的时候,构建过程中会有Copy的步骤:

当我将app(而非extension)的Strip Debug Symbols During Copy设置为YES之后,在这句copy的命令中会多出-strip-debug-symbols参数。

但是这里,strip并不能成功,并且出现了warning:

warning: skipping copy phase strip, binary is code signed: /Users/xsq/Library/Developer/Xcode/DerivedData/XSQSymbolsDemo-cysszdsykroyyddkvvyffgboglvo/Build/Products/Debug-iphoneos/Today.appex/Today

这似乎是由于app中的today extention已经经过了code sign,导致无法被篡改引起的警告。

那么如果略过code sign的过程,是否就能成功strip呢?我想使用模拟器调试可以略过code sign过程,于是便在模拟器上试了试。果然这个warning消失了。

Strip Debug Symbols During Copy设置为YES时,打开对应.app文件的“显式包内容”,可以看到,/PlugIns/Today.appex文件的大小变小了。(不过这些只能在使用模拟器时奏效)

Strip Debug Symbols During Copy置为YES的时候,today extension中的断点将不会中断,但是打印[NSThread callStackSymbols]时的类名和方法名还是可以看见的。

现在我们把Strip Debug Symbols During Copy设置回NO,来看看下一个设置。


Debug Information Format [DEBUG_INFORMATION_FORMAT]



Xcode7.2.1中,Debug Information Format在DEBUG下默认为DWARF,在RELEASE下默认为DWARF with dSYM File

官方文档的解释是:

This setting controls the format of debug information used by the developer tools. [DEBUG_INFORMATION_FORMAT]

DWARF - Object files and linked products will use DWARF as the debug information format. [dwarf]
DWARF with dSYM File - Object files and linked products will use DWARF as the debug information format, and Xcode will also produce a dSYM file containing the debug information from the individual object files (except that a dSYM file is not needed and will not be created for static library or object file products). [dwarf-with-dsym]

Debug Information FormatDWARF with dSYM File的时候,构建过程中多了一步Generate dSYM File:


最终产出的文件也多了一个dSYM文件。

不过,既然这个设置叫做Debug Information Format,所以首先得有调试信息。如果此时Generate Debug Symbols选择的是NO的话,是没法产出dSYM文件的。

dSYM文件的生成,是在Strip等命令执行之前。所以无论Strip Linked Product是否开启,生成的dSYM文件都不会受影响。

不过正如文档中所说,无法为静态库生成dSYM文件。即便为给一个静态库的Debug Information Format设置为DWARF with dSYM File,构建过程中依然不会有生成dSYM文件的步骤。


一种配置方案



了解了每个设置的意思,个人觉得对于一个普通的app来说可以这样配置这些设置:

  • Generate Debug Symbols:DEBUG和RELEASE下均设为YES(和Xcode默认一致);
  • Debug Information Level:DEBUG和RELEASE下均设为Compiler default(和Xcode默认一致);
  • Deployment Postprocessing:DEBUG下设为NO,RELEASE下设为YES,这样RELEASE模式下就可以去除符号缩减app的大小(但是似乎设置为YES后,会牵涉一些和bitcode有关的设置,对于bitcode暂时还不太了解(´・_・`));
  • Strip Linked Product:DEBUG下设为NO,RELEASE下设为YES,用于RELEASE模式下缩减app的大小;
  • Strip Style:DEBUG和RELEASE下均设为All Symbols(和Xcode默认一致);
  • Strip Debug Symbols During Copy:DEBUG下设为NO,RELEASE下设为YES
  • Debug Information Format:DEBUG下设为DWARF,RELEASE下设为DWARF with dSYM File,dSYM文件需要用于符号化crash log(和Xcode默认一致);

参考

深入理解计算机系统
Build Setting Reference
Skipping Copy Phase Strip
xcode build settings for debug symbol
Clang Compiler User’s Manual
Symbolification: Shipping Symbols
Technical Q&A QA1490


2016.04.17更新



某天,我看了公司的项目的设置,发现Deployment Postprocessing这项在DEBUG和RELEASE下均为NO,让我有些奇怪,难道公司的项目没有滤去调试符号?
于是我archive了一下,发现,在archive的过程中,其实是跑了strip的命令的,让我有点吃惊。这说明run和archive的构建过程是不同的。

查了官方文档,暂时没能查到run和archive到底有哪里不同,但是这里对ACTION的解释让我有些在意。对ACTION的设置会影响到Deployment Postprocessing的默认值,即当$ACTION = install的时候,Deployment Postprocessing默认为YES

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 【转载】曾梦想仗剑走天涯 1.Xcode IDE概览 说明:从左到右,依次是“导航窗格(Navigator)->边...
    06a6a973d7ab阅读 3,819评论 2 20
  • 1.Xcode IDE概览 说明:从左到右,依次是“导航窗格(Navigator)->边列(Gutter)->焦点...
    小地阅读 5,357评论 0 9
  • 参考文章链接:关于Xcode编译性能优化的研究工作总结 一、编译时长优化Architectures 在Build ...
    夏天的风_song阅读 1,727评论 0 2
  • 什么是符号表? 符号表是内存地址与函数名、文件名、行号的映射表。符号表元素如下所示: <起始地址> <结束地址> ...
    深圳阳光阅读 12,165评论 28 5
  • 冻瑟都里镇,叶落老铁山。他乡故岸,灯雨碎月漫空天。忽念雪飘旧路,才有急行切语,舞墨祭当年。做土桃花木,窗上稚燕还。...
    见龙君阅读 270评论 1 0