某些博客谈起 objective c,会经常说 objective c 是一门非常动态的语言,你对这句话的认知达到了什么程度?
1 语言的动态性,静态性到底指什么?
对于动态,静态这两个词而言,常识告诉我们的一个区别就是—动态的更灵活,静态的相对稳定,对于语言来说,也可以这么去理解。
如果你有过C++编程经验,理解虚函数,会比较好的理解动态和静态是如何体现在语言上的,没有也没关系,我带你从不同的角度理解动静态。
提到语言的动态和静态,需要理解一些前置的知识
1.1 符号
** 符号是计算机高级语言的一个重要概念,我们平时写的代码里,定义的函数以及全局变量,都被称为符号(symbol)
这里要注意,只有全局变量才会被识别为符号,局部变量因为作用域的原因,不会被识别。
**
1.2 符号地址
** 就是所有的符号最终在可执行文件中都有自己的位置,所以符号肯定有它自己唯一的地址(类似0x3a2193000这样的16进制表示)**
1.3 方法
先上例子
定义一个类OCObject和它的方法,都是空实现,写个函数去调一下。
用clang去解释一下
会被翻译成两个静态函数,符号名被重新定义了下,I和C,代表实例和类方法,我们也由此发现了clang解释函数名的某些规则特点。从链接视角看,这些方法都是具体的符号,且都有自己的唯一地址。
对function的调用会被clang解释为
objc_msgSend(id _Nullable self, SEL _Nonnull op, …),后续就需要理解objc_msgSend(自行去搜过程,我就不说了),最终就是通过传入的 self + op去找到最终的函数符号。
我这里再多说点,贴张图
从上图我们可以知道,我们定义的oc方法,会被clang解释成一个static c 函数,并在命名上加一下修饰用做区分,同时,这些被修饰后的函数,才是被放进类的方法列表里的真正的函数。
从调用上看,objc_msgSend最终就是找到它们去执行。那么[self function]; 这行oc方法调用,在编译过程中,仅仅转成了objc_msgSend而已,根本不能确定具体要执行的目标函数地址,只有等到运行时,才真正找到那个函数符号,然后跳到对应地址去执行指令了。所以,这就是方法动态性的解释。
2 链接的本质
既然语言的动态性跟上述的符号查找,执行过程有关联,那么我们可以再从符号出发,谈谈链接.
核心过程就是符号解析—>重定位—->产出完全链接的可执行文件
这篇文章里我们要关注符号解析,即确定符号引用关系,将每个模块中引用的符号与某个目标模块的定义符号建立关联(即我在a模块里用到了b模块定义的某个方法,链接器需要确定引用这个关系)
我引一个例子,b模块有一个NSObject category,定义了一个function方法
a模块去调这个方法
这里的b模块有两种场景
1 b模块打成了静态库
我们首先确定
[self function] 这行调用会被解释成 objc_msgSend(self,sel_register(“function”))
这一句对于链接器来说,它没有解析出我们需要引用function符号,因此会把b中的function方法漏掉,不会链接进最终的可执行文件。而objc_msgSend,sel_register,这两个符号都会在链接过程中确定引用关系,都在libobjc.dylib,libobjc.dylib找到它们的定义处,然后完成重定位(此处包括链接重定位和装载重定位,目标都是绑定符号唯一地址)
所以在这种场景下,[self function] 这里运行时会出错,因为function这个符号没有被链接进来。方法查找会找不到。再强调一下链接时不报错,因为链接器不知道需要引用function符号。
2 b模块没有打成库,只是源码h和m,都放在主工程下面。
这种场景下,运行没有问题,但这和动态性并不构成矛盾,因为链接器会强制链接所有主工程下的文件,所以它不关心是否有引用关系,实际链接器还是没有确定对function的引用,但因为你是主工程下的文件,所以全部链接!
总结:objective c动态性的特点主要反映在方法的调用上,因为OC方法调用并非c函数那种直接调用,而是经过runtime做了消息转发,这层转发影响了链接符号解析的过程,不能识别到oc方法引用这一层。所以链接后,不能确定最终执行的函数地址,要推迟到运行期去确定。 也因为这个特性,我们才可以利用runtime运行时做OC方法的hook。
抛问题拓展:
1 场景1下如何帮助链接器确定对function的符号引用?
2 OCObject 有一个sayHello方法,并打成了静态库,下面两种调用有啥区别?只有case1的时候,只有case2的时候,case1和case2同时存在的时候,分别输出什么?
3 静态语言方法hook怎么办呢?hook的本质是什么?
结束
本文为原创