加入收藏 | 设为首页 | 会员中心 | 我要投稿 无忧刷机网 - 51刷机网 (https://www.51shuaji.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 苹果频道 > 苹果资讯 > 正文

iOS 系统的延迟绑定机制

发布时间:2017-05-28 16:51:44 所属栏目:苹果资讯 来源:www.jianshu.com
导读:延迟绑定机制是指将符号的绑定工作推迟到符号第一次被程序调用的时候。为了大家更好地理解延迟绑定的概念以及我们为什么要延迟绑定,本文首先会介绍一些程序链接方面的知识。相关背景链接在编译过程中的位置一般来说...

延迟绑定机制是指将符号的绑定工作推迟到符号第一次被程序调用的时候。为了大家更好地理解延迟绑定的概念以及我们为什么要延迟绑定,本文首先会介绍一些程序链接方面的知识。相关背景链接在编译过程中的位置一般来说...

延迟绑定机制是指将符号的绑定工作推迟到符号第一次被程序调用的时候。为了大家更好地理解延迟绑定的概念以及我们为什么要延迟绑定,本文首先会介绍一些程序链接方面的知识。

相关背景

链接在编译过程中的位置

一般来说,代码的编译过程分为以下几个阶段:

  • 预处理

    主要包括头文件导入、宏展开等过程。

  • 语法以及语义分析

    首先对代码进行扫描分析,生成抽象语法树(Abstract Syntax Tree),语法树中还记录了每个节点在源代码中的位置,方便编译器定位问题;之后编译器对其进行更高级别的静态分析,确保程序中没有错误,例如调用对象未实现的方法、类型转换错误、对可能导致内存泄露的代码进行警告等。

  • 中间代码生成及优化

    将代码进一步转换成中间代码(LLVM IR),对其进行相应的优化处理,并输出汇编代码。

  • 汇编

    将汇编代码生成相应的目标文件。

  • 链接

    合并多个目标文件,最后输出一个可执行文件或是库文件。

链接是程序编译过程中的最后一步,也是十分重要的一步,它主要有两方面的工作:(1)符号解析。将符号的引用和符号的定义联系起来;(2)重定位。将符号的定义和具体的地址对应起来,并修改所有对这些符号的引用,使它们指向相应的地址。

静态链接

在很久很久以前,链接是指静态链接,也就是将所需的库文件全部都拷贝一份到程序中,最终形成一个可执行文件。静态链接在技术上是没有什么问题的,但是随着时间的推移,人们也发现了它身上的一些硬伤:

  • 最终生成的可执行文件十分臃肿、巨大。

  • 编译时间大大增加。

  • 浪费存储器资源。相同的代码会被复制到不同的程序中,操作系统运行的程序越多,浪费就越严重。

  • 更新和维护困难。如果你要更新一个库文件,那么你必须要重新修改编译参数,然后将以上费时费力的编译过程重新跑一边,如果其中出了一点偏差,那么不好意思,一切都要重新来过,反复几次后程序不一定能编译出来,但孩子一定可以打酱油了(_)

所以为了解决这些问题,勤劳、善良的程序员们又发明了新的技术:动态链接。

动态链接

静态链接问题的根源在于它使程序和静态库的联系过于紧密,解决问题的关键是降低二者间的耦合度,动态链接技术为此应运而生。

与静态链接相比,动态链接将相关符号的绑定工作推迟到程序被加载到内存中执行的时候,这不仅减少了程序的编译时间,而且也使得库文件能够真正的被不同的程序所共享。此处的“共享”有两点含义:一是指库文件在操作系统中只存在一份,而不是像静态链接那样将库文件给每个程序都拷贝一份;二是指在程序运行的过程中,共享库的 text 段的内容可以被不同的进程所共享。

与动态链接技术相对应的库文件叫做动态库文件,在 Windows 上是 dll 文件,在 Linux 上是 so 文件,而在 Mac 上则是 dylib 文件。

我们知道,把对符号的引用修正为符号所对应的地址是链接过程中的关键部分,动态库也是一样,它也要做出相应的修改,但是最尴尬的地方在于动态库只有一份,但是它会被很多进程加载,而且它事先并不知道自己会被加载到哪里。

举个例子:假设动态库加载到进程 A 的地址为 0xAAAAAA,链接结束后动态库相关符号的地址也被修改,如果此后没有进程加载该动态库,那么一切都没有问题。可是直到某一天,进程 B 也要加载此动态库,还硬要把它加载到 0xBBBBBB 上,这样麻烦就来了。动态库中符号的相关地址是基于 0xAAAAAA 的,在进程 B 中是无法工作的,那么要基于 0xBBBBBB 修改吗?这样进程 A 就不能工作了。重新拷贝一份到进程 B 吗?那你还共享个啥啊!!!

还有一个潜在的问题,那就是动态库的 text 段必须是可写的,否则加载的时候就无法修改相关符号进行重定位,这就会使安全性大打折扣。

为了使动态链接成为可能,我们勤劳、善良的程序员又发明了新的技术,即 PIC(Position Independent Code)。

Position Independent Code

PIC 又称为位置无关代码,即相关代码加载到任何位置都可以正常运行,动态库的编译都需要加上 -fPIC -shared 选项。

Use -fPIC or -fpic to generate position independent code. Whether to use -fPIC or -fpic to generate position independent code is target-dependent. The -fPIC choice always works, but may produce larger code than -fpic (mnenomic to remember this is that PIC is in a larger case, so it may produce larger amounts of code). Using -fpic option usually generates smaller and faster code, but will have platform-dependent limitations, such as the number of globally visible symbols or the size of the code. The linker will tell you whether it fits when you create the shared library. When in doubt, I choose -fPIC, because it always works.

那么 PIC 是如何实现的?它又是如何在不修改 text 段的情况下,让同一动态库加载到不同进程的不同位置?使用动态库的程序又需要做哪些工作?

答案其实很简单,就是多一层引用关系。

既然 text 段不让写,那我就写 data 段呗

(编辑:无忧刷机网 - 51刷机网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读