简介

程序员编写的是源代码,而计算机运行的则是CPU能识别的机器指令,因此必须要有一系列工具或程序来将源代码转化为机器指令,这个转化的过程需要经历编译和链接两个主要阶段。所谓编译就是将源代码文件转化为中间的目标文件(Object file)。目标文件的后缀一般为.o。iOS系统的目标文件也是一种mach-o格式的文件,mach-o文件的头部结构体:struct mach_header中的filetype成员字段用来描述当前文件的类型,目标文件所对应的类型是MH_OBJECT。目标文件中的布局结构和内容和可执行文件中的布局结构和内容非常相似,编译后形成的目标文件中的代码段(__TEXT Segment)中的节(__text Section) 中的内容存放的是已经被编译为机器指令的二进制代码了。

iOS开发交流技术群:563513413,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!

静态库和动态库的存在形式

  • 静态库:.a 和 .framework
  • 动态库:.dylib 和 .framework

静态库和动态库的区别

  • 静态库:链接时,静态库会被完整地复制到可执行文件中,被多次使用就有多份冗余拷贝
  • 动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存
  • 下面就是一个目标文件的布局结构:

image.png

重定位表(Relocation table)

系统的编译操作是针对一个个源文件的独立行为。通常情况下在编写程序时会引用其他源文件或者动态库中定义的函数或者类方法以及全局变量,因此在编译阶段所有的外部引用符号的地址是无法被确定的,此时生成的目标文件中的段(Segment)中的节(Section)中的外部函数调用指令的操作数部分以及外部全局变量符号的地址的值都将是0。在后续的链接过程中需要调整这些指令的操作数的值来进行重定位(Relocation),为此系统在编译的目标文件中的对那些有外部符号引用的节(Section)中都会建立一个重定位表(Relocation table)。这个重定位表中的每个条目会将所有需要进行重定位的指令或者数据访问的位置信息以及引用的外部符号的信息记录起来,以便在链接时进行更新处理。下面的图表展示了这个结构:

image

简要的说一下链接步骤所做的事情

当编译器对所有的源代码文件编译完成后,接下来的步骤就是链接了。链接的主要功能就是将所有目标文件中的各个相同段和节的信息依次连接起来拼装成一个单独的可执行文件。同时还会将所有目标文件中需要Relocation的部分的指令进行调整,因为此时可以知道每个引用符号的位置了。在链接时系统会分析每个目标文件中的依赖信息,也就是说链接成一个可执行文件中各段各节的内容总是无依赖的目标文件放在前面而有依赖的目标文件放置在后面。

静态库的作用

每当我们build一个工程项目时,系统总是会先将所有源代码编译为目标文件,再将目标文件链接为可执行程序。即使是我们改变其中某一个文件中的源代码,而其他文件没有改变也是如此。因此为了加快编译速度,有些文件将不再以源代码的形式提供,而是可以将一部分目标文件先集中起来形成一个静态库。这样就可以对这部分文件略过编译而直接进行链接从而加快编译的速度。

对于iOS系统来说因为不支持第三方以动态库的形式集成到我们的工程中以及上传到appstore。而第三方提供的库因为安全和知识产权以及保密的特性不大可能以源代码的形式提供给我们,而是以静态库的形式提供给我们。

可见静态库的作用主要是为了加快编译速度、进行模块划分、以及代码安全的功能。静态库是一个编译产生的结果,而动态库则是编译链接产生的结果。静态库的组成其实是一个个目标文件。


蓝天
32 声望5 粉丝