了解一个系统的唯一途径就是去阅读源代码
要想完全的了解一个系统唯一的方法就是去阅读这个系统的源代码实现!这个原则对于一个iOS程序员也是如此。很幸运的是我们现在处于一个开源代码迸发的美好时代(这里要感谢理查·马修·斯托曼以及他的GNU计划),很多优秀的库都以源代码的形式呈现给大家,甚至连iOS这种封闭的系统也迫于某种压力开放了部分源代码(虽然开放的部分并不一定和真实的相同),这也已经足以给了我们很多热情去窥探其内部的一些实现机制。目前网络上也有非常多的基于苹果的开源而介绍OC2.0的runtime原理以及runloop实现机制以及类的+load方法执行时机等等方面的文章。
当我们希望走更远时就会发现有一座大山阻挡着我们的去路。因为系统的闭源特性使得我们无法阅读到其中所有的源代码以及核心实现。那么是否我们就只能裹足不前了呢? 回答是NO!
源代码有高级形式的源代码也有低级形式的源代码。当我们被高级形式的源代码所阻时,低级形式的源代码却依旧为我们敞开着大门,就看你愿不愿意去找那把钥匙并打开它。低级形式的源代码是什么呢? 答案就是机器指令!!
我们知道凡是满足某个操作系统ABI规则的应用程序源代码最终都会编译和链接为某种特定格式的一条条机器指令并在CPU上执行。如果说程序的高级语言实现对于一个程序员来说是它的源代码的话,那么对于CPU来说一个程序的机器指令序列就是它的源代码。只不过机器语言对于很多人来说异常的晦涩难懂而已。
很高兴的一件事情就是虽然机器语言晦涩,我们的前辈们发明出了一种所谓机器语言的助记语言:汇编语言
汇编语言中的每条命令虽然几乎和每条机器指令一一对应,但是却增强了程序的可读性,使得我们面临的不再是一串干巴巴的二进制数字了。君不见目前很多的反编译工具以及即使是XCODE上我们都能看到汇编语言的场景。正是因为汇编语言的出现使得我们在阅读和分析源代码上就进了一大步!
当你精通汇编语言时!你看到的所有代码都将是源代码!
有人说汇编语言相对于高级语言来说依然晦涩难懂,但这其实并不是绝对的。曾记得中国第一代程序员的求伯君以及雷军这些前辈们最早接触的就是汇编语言,而且他们也都是用汇编语言进行程序编写的。就因为汇编语言离机器语言太近了,所以大家都会有一种望而生畏的感觉。诚然这些低级语言并没有像我们使用的高级语言那样更加符合自然语义和语法规则,但是它的优点就是非常的直接和单纯。当你深入的应用它时就会发现汇编其实并没有那么的复杂。在一个程序的机器指令中,大部分的指令代码所做的事情除了计算外就是将数据在寄存器与寄存器之间以及寄存器与内存之间进行移动。在高级语言中我们可以定义非常个性化的变量以及无限制的变量,而在低级语言中我们则只能使用那几个有限的寄存器来作为临时变量,以及像访问数组那样去访问内存地址。
下面的一张图可以看到实现一个累加功能代码片段的机器语言和汇编语言以及高级语言之间的差别:
看上面的代码时也许你对高级语言所表达的意义一目了然,而对于汇编语言的表达也许仔细多读几遍就能了解其意义,而对于机器语言则可能是一头雾水了。
说了这么多,也许有人会问汇编语言和我想要深入iOS系统底层有什么关系!
好问题! 答案就是iOS系统的封闭性,使得我们无法窥探到很多系统的底层实现, 并且当我们被某种问题或者某个实现原理所困扰却不得其法时,就可以通过对系统进行反编译而得到汇编语言来了解和阅读其实现原理;当我们面临突如其来的运行时崩溃时,就可以通过阅读汇编语言来了解其产生的原因;当我们的crash并没有上下文时,就可以通过汇编语言来定位和解决问题;当我们想解决某个问题而想做动态下发补丁时我们也可以借助汇编语言来完成;当我们想在越狱的机器上hook住某些应用时我们可以通过汇编语言来完成功能;当我们想最大的优化我们的系统以及某些关键部分的代码的性能时我们可以借助汇编语言;当我们想当一个黑客时我们可以借助汇编语言...,我们能借助汇编语言做的事情实在是太多太多了。 现在的应用编程语言都是越来越向高级语言发展,而呈现出简单化、智能化从而导致进入的门槛越来越低。越高级的语言因为其封装性就越离底层实现原理越远,你所能窥探的东西就越少,因此低级语言还是非常具有顽强的生命力和存在必要性的。君不见iOS所开源的runtime的源代码里面关于objc_msgSend函数的实现就是用汇编语言来编写的!这样的目的就是让这个函数的性能得到最大的优化。
所以说掌握和了解汇编语言知识不仅是进入iOS系统底层并且也是进入所有系统底层的一把钥匙,当你精通或者了解一些基础的汇编语言知识和技巧时,你就打开了通往一切都是源代码的大门。值得一提的就是我并不打算详细的去介绍关于汇编的一切,其实我们只要了解一些基础的汇编知识就能非常方便的帮助我们解决很多的事情。