【iOS】——编译链接和动态链接器

前言

计算机语言分为机器语言:汇编语言,高级语言。
可以将高级语言分为两种:1,编译语言和解释型语言(直译式语言)。

img

编译型语言(一次性翻译)

编译型语言的程序只要经过编译器编译之后,每次运行程序都可以直接运行如oc,swift等

解释型语言(逐步进行解释执行)

解释语言编写的程序在每次运行时都需要通过解释器对程序进行动态解释和执行,如php,javascript等

编译链接过程:

1,预处理:macro 宏, import 头文件替换及处理其他的预编译指令,产生.i文件。(都是以#号开头)

2,编译:把预处理完的一系列文件进行一系列词法、语法、静态分析,并且优化后生成相应的汇编代码,产生.s文件;

3,汇编:汇编器将汇编代码生成机器指令,输出目标文件,产生.o文件(根据汇编指令和机器指令的对照表一一翻译就可以了);

4,链接:在一个文件中可能会到其他文件,因此,还需要将编译生成的目标文件和系统提供的文件组合到一起,这个过程就是链接。经过链接,最后生成可执行文件。

img

预处理(预编译)-> 产生.i文件

使用终端到main.m所在文件夹,使用命令:

clang -E main.m -o main.i

处理源代码文件中的以"#"开头的预编译指令:

  • "#define"删除并展开对应宏定义。

  • 处理所有的条件预编译指令。如#if/#ifdef/#else/#endif。

  • "#include/#import"包含的文件递归插入到此处。

  • 删除所有的注释"//或/**/"。

  • 添加行号和文件名标识。如“# 1 “main.m””,编译调试会用到。

编译 -> 产生.s文件

编译器:用来把源文件转换为更低级的语言,xcode使用的clang前端编译器的作用就是把源代码转化为更为低级的LLVM IR,这个LLVM IR是操作系统无关的,然后后端编译器LLVM通过这个中间语言来进行下一步二进制文件的产出。这要得益于LLVM的三层架构,假如你需要增加一种语言,只需要增加一种前端,如过你需要增加一种处理器架构,也只需要增加一种后端。

img

编译器前端:Clang编译器前端的任务是进行:语法分析,语义分析,生成中间代码(intermediate representation )。在这个过程中,会进行类型检查,如果发现错误或者警告会标注出来在哪一行。Clang 是一个C、C++、Objective-C和Objective-C++编程语言的编译器前端。

公用优化器:将生成的中间文件进行优化,去除冗余代码,进行结构优化。将优化后的中间代码再次转换,变成汇编语言,并再次进行优化,最后将各个文件代码转换为机器代码并链接。

编译器后端:

clang -S main.i -o main.s

编译过程也分为 词法分析 -> 语法分析 -> 静态分析 最后优化生成相应的汇编代码,得到.s文件

词法分析:源代码的字符序列分割成一个个token(关键字、标识符、字面量、特殊符号),比如把标识符放到符号表(静态链接那篇,重点讲符号表)。

语法分析:把词法分析生成的token生成抽象语法树 AST,此时运算符号的优先级确定了;有些符号具有多重含义也确定了,比如“*”是乘号还是对指针取内容;表达式不合法、括号不匹配等,都会报错。

静态分析:分析类型声明和匹配问题。比如整型和字符串相加,肯定会报错。

一般会把类型分为两类:动态的和静态的。动态的在运行时做检查,静态的在编译时做检查。以往,编写代码时可以向任意对象发送任何消息,在运行时,才会检查对象是否能够响应这些消息。由于只是在运行时做此类检查,所以叫做动态类型。

静态类型,是在编译时做检查。当在代码中使用 ARC 时,编译器在编译期间,会做许多的类型检查:因为编译器需要知道哪个对象该如何使用。

中间语言生成和优化:CodeGen根据AST自顶向下遍历逐步翻译成 LLVM IR,并且在编译期就可以确定的表达式进行优化,比如代码里t1=2+6,可以优化t1=8。(假如开启了bitcode,)

目标代码生成与优化:根据中间语言生成依赖具体机器的汇编语言。并优化汇编语言。这个过程中,假如有变量且定义在同一个编译单元里,那给这个变量分配空间,确定变量的地址。假如变量或者函数不定义在这个编译单元,得链接时候,才能确定地址。

汇编 -> 产生.o文件

clang -c main.s -o main.o

汇编器将上一步生成的可读的汇编代码转化为机器代码。最终产物就是 以 .o 结尾的目标文件。

链接

clang main.o -o main

这一阶段是将上个阶段生成的目标文件和引用的静态库链接起来,最终生成可执行文件(Mach-O),链接器解决了目标文件和库之间的链接。

动态库和静态库

动态库

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行时才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期。
  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)将一些程序升级变得简单。
  • 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。

静态库

在程序编译期的链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

  • 程序在运行时独立运行,不需要依赖外部库。

  • 静态库的调用通常比动态库的调用更快,因为不需要动态链接

  • 生成的可执行程序较大。如果多个使用静态链接生成的程序同时运行会占用大量的内存空间静态库一旦被编译链接到可执行文件中,想要更新或替换静态库的代码需要重新编译整个程序。

动态库和静态库的区别

静态库

  • 在编译时加载

  • 优点:代码装载和执行速度比动态库快。

  • 缺点:浪费内存和磁盘空间,模块更新困难。

    动态库

  • 在运行时加载

  • 优点:体积比静态库小很多,更加节省内存。

  • 缺点:代码装载和执行速度比静态库慢。

动态链接器

动态链接器的定义

动态链接器通常指的是dylddyld是它负责处理程序和动态库(dylib,动态链接库)之间的链接操作。dyld的主要任务是在程序启动时解析和加载所需的动态库,并解决这些库中的符号引用。

  1. 加载动态库dyld在程序启动时会加载指定的动态库。这包括系统库和应用程序可能依赖的任何第三方库。dyld能够延迟加载某些库,直到它们被实际使用,这有助于提高启动速度和内存效率。
  2. 解析符号: 当程序引用了一个动态库中的函数或变量时,dyld会查找并绑定这些符号到正确的地址。这个过程称为符号解析,它确保了程序能正确地访问库中的功能。
  3. 重定位dyld还负责重定位,这意味着它会调整库中的地址,以确保它们在进程的虚拟地址空间中正确放置。这通常涉及修改库内部的指针,使它们指向正确的内存位置。
  4. 缓存dyld使用缓存机制来存储已加载的库和已解析的符号,这样在后续的程序执行中就不需要重复加载或解析相同的内容,从而加快了程序的运行速度。
  5. 懒惰链接(Lazy Binding): 为了进一步提高性能,dyld可以采用懒惰链接策略,只在程序真正尝试访问一个库中的符号时才解析该符号。这避免了在程序启动时不必要的工作。
  6. 可执行文件和动态库的集成: 在iOS中,dyld不仅处理动态库,还负责加载和执行可执行文件本身。可执行文件中包含了dyld的启动信息,告诉它需要加载哪些库和如何初始化程序。
  7. 安全特性dyld还实现了一些安全特性,如ASLR(地址空间布局随机化),通过随机化库的加载地址来增加攻击者预测内存布局的难度,从而提高系统的安全性。

dyld2和dyld3的区别

dyld2dyld3dyld的不同版本,它们在功能和性能上有一些关键区别

下图为dyld2执行流程:

img

下图为dyld3执行流程:

img

相比于dyld 3,dyld 2的加载过程没有那么优化。它没有将工作分成两个阶段,而是直接在进程中完成所有任务,包括解析、查找依赖、映射文件、查找符号以及绑定和重定位等。这意味着这些操作可能会阻塞主线程,导致应用程序启动速度变慢。此外,由于没有生成和使用闭包,dyld 2也没有提供额外的安全性保障来防止恶意软件尝试修改或注入代码到正在运行的应用程序中。

dyld 3 包含这三个部分:

  • 进程外 Mach-O 分析器和编译器 (out-of-process mach-o parser
    由于 dyld 2 存在的问题,dyld 3 中将采用提前写入把结果数据缓存成文件的方式构成一个 lauch closure(可以理解为缓存文件)
  • 进程内引擎 执行 launch closure 处理 (in-process engine)
    验证”lauch closures“是否正确,映射dylib,执行main函数。此时,它不再需要分析mach-o header和执行符号查找,节省了不少时间。
  • launch closure 缓存服务 (launch closure cache )
    系统程序的 lauch closure 直接内置在 shared cache 中,而对于第三方APP,将在APP安装或更新时生成,这样就能保证 launch closure 总是在 APP 打开之前准备好。

dyld 3的符号缺失问题

dyld 2 默认采取的是 lazy symbol 的符号加载方式,但在 dyld 3中,在 App 启动之前,符号解析的结果已经在 lauch closure 内了,所以 lazy symbol 就不再需要。这时,如果有符号缺失的情况,APP 的行为会有不同:在 dyld 2 中,首次调用缺失符号时 APP 会 crash;而 dyld 3 中,缺失符号会导致 APP 一启动就会 crash。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/47726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 大屏外接显示器锁屏无触摸

一、大海捞针 1、首先查看log,发现异常log log表示主显示器即id 0的显示器有可交互窗口但是没有焦点,副显示器即id 4有焦点但是没有可交互窗口。猜想副显示器把主显示器的焦点抢走了,只需把焦点从副显示器挪回主显示器即可。 通过查看源代码知道上面这段log来自于InputDi…

filebeat,kafka,clickhouse,ClickVisual搭建轻量级日志平台

springboot集成链路追踪 springboot版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.3</version><relativePath/> <!-- lookup parent from…

【CSS in Depth 2 精译_019】3.2 CSS 的盒模型

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

【Qt安装与简易串口控制Arduino开发板小灯教程】

【Qt安装与简易串口控制Arduino开发板小灯教程】 1. 前言2. QT环境搭建3. 验证QT_Creator是否安装成功3.1 设计流程3. 2 上位机界面设计 4. 上位机逻辑代码编写4.1 添加串口库、包含串口相关头文件4.2 添加QSerialPort成员4.3 创建串口对象、搜索所有可用串口4.4 在编写“打开串…

微软成为PostgreSQL主要贡献者

微软对PostgreSQL贡献的很多新功能都来自于客户在使用微软Azure上的PostgreSQL管理实例数据库&#xff0c;所以这些新功能都来自于真实的客户需求 微软贡献的这些新功能都是比较实用的功能 在这里&#xff0c;【真实的客户需求】要突出一下&#xff0c;因为现在很多社区贡献者…

4. docker镜像、Dockerfile

docker镜像、Dockerfile 一、docker镜像1、镜像介绍2、镜像核心技术 二、Dockerfile定制镜像1、Dockerfile使用流程1.1 编写Dockerfile1.2、构建镜像1.3 创建容器测试镜像定制操作 2、Dockerfile常用指令 一、docker镜像 1、镜像介绍 分层的文件系统 优势&#xff1a;节省空间…

基于JAVA+SpringBoot+uniapp的心理小程序(小程序版本)

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、SpringCloud、Layui、Echarts图表、Nodejs、爬…

docker默认存储地址 var/lib/docker 满了,换个存储地址操作流程

1. 查看docker 存储地址 docker info如下 var/lib/docker2、查看内存大小 按需执行 df -h 找超过100M的大文件 find / -type f -size 100M -exec ls -lh {} \; df -Th /var/lib/docker 查找这个文件的容量 df -h 查找所有挂载点 du -hs /home/syy_temp/*1、df -h 2、sud…

2-38 基于matlab的蚁群算法优化无人机uav巡检

基于matlab的蚁群算法优化无人机uav巡检&#xff0c;巡检位置坐标可根据需求设置&#xff0c;从基地出发&#xff0c;返回基地&#xff0c;使得路径最小。可设置蚁群数量&#xff0c;信息素系数。输出最佳路线长度。程序已调通&#xff0c;可直接运行。 2-38 蚁群算法优化无人…

科普文:多线程如何使用CPU缓存?

一、前言 计算机的基础知识聊的比较少&#xff0c;但想要更好的理解多线程以及为后续多线程的介绍做铺垫&#xff0c;所以有必要单独开一篇来聊一下 CPU cache。 二、CPU 前面有一篇文章关于 CPU是如何进行计算 感兴趣的同学&#xff0c;可以先移步了解一下&#xff0c;不了…

[003-02-10].第10节:Docker环境下搭建Redis主从复制架构

我的博客大纲 我的后端学习大纲 我的Redis学习大纲 1.cluster&#xff08;集群&#xff09;模式-docker版 哈希槽分区进行亿级数据存储 1.1.面试题&#xff1a;1~2亿条数据需要缓存&#xff0c;请问如何设计这个存储案例 1.回答&#xff1a;单机单台100%不可能&#xff0c;肯…

细说MCU用定时器控制ADC采样频率的实现方法并通过Simulink查看串口输出波形

目录 一、硬件工程 二、建立Simulink模型 1.安装MATLAB和Simulink 2.建立Simulink模型 三、代码修改 1.修改回调函数 2.产看结果 3.完整的main.c 本文作者的文章 细说MCU用定时器控制ADC采样频率的实现方法-CSDN博客 https://wenchm.blog.csdn.net/article/details/…

270-VC709E 基于FMC接口的Virtex7 XC7VX690T PCIeX8 接口卡

一、板卡概述 本板卡基于Xilinx公司的FPGA XC7VX690T-FFG1761 芯片&#xff0c;支持PCIeX8、两组 64bit DDR3容量8GByte&#xff0c;HPC的FMC连接器&#xff0c;板卡支持各种FMC子卡扩展。软件支持windows&#xff0c;Linux操作系统。 二、功能和技术指标&#xff1a; 板卡功…

Getx学习笔记之中间件鉴权

目录 前言 一、实现步骤 1.添加依赖 2.创建鉴权中间件 3.定义路由 4.设置初始路由 5.模拟登陆状态 二、Getx鉴权步骤总结 三、本文demo示例 四、参考文章 前言 在 Flutter 中&#xff0c;使用 GetX 可以很方便地实现中间件鉴权&#xff08;Authentication&#xff09…

MySQL生产环境迁移至YashanDB数据库深度体验

前言 首届YashanDB「迁移体验官」开放后&#xff0c;陆续收到「体验官」们的投稿&#xff0c;小崖在此把优秀的投稿文章分享给大家~今天分享的用户文章是《MySQL生产环境迁移至YashanDB数据库深度体验》&#xff08;作者&#xff1a;呆呆的私房菜&#xff09;&#xff0c;满满…

Python简化命令行界面库之fire使用详解

概要 在开发命令行工具时,开发者通常需要编写大量代码来解析命令行参数,这既耗时又容易出错。Python Fire 是 Google 开源的一个库,旨在简化命令行界面的开发。它可以将任何 Python 对象自动生成一个命令行界面,从而大大减少了开发时间和代码复杂度。本文将详细介绍 Pytho…

Elasticsearch基础(五):使用Kibana Discover探索数据

文章目录 使用Kibana Discover探索数据 一、添加样例数据 二、数据筛选 使用Kibana Discover探索数据 一、添加样例数据 登录Kibana。在Kibana主页的通过添加集成开始使用区域&#xff0c;单击试用样例数据。 在更多添加数据的方式页面下方&#xff0c;单击其他样例数据集…

Vscode+Pyside6开发之虚拟环境配置以及错误解决

Pyside开发之虚拟环境配置以及错误解决 开发环境一、项目创建以及虚拟环境设置1.创建项目2. 新建py文件,新建虚拟环境3.激活虚拟环境二、项目位置改变pip命令报错1.删除原来的虚拟环境2. 产生包列表文件requirements.txt3.重新创建虚拟环境4.重新安装包文件5.其他错误开发环境…

Notepad++换安装路径之后,右键打开方式报错:Windows无法访问指定设备、路径或文件。你可能没有适当的权限访问该项目。的处理方法

把Notepad添加到右键打开方式&#xff0c;可以参考下面的3篇文章添加&#xff1a; https://blog.csdn.net/xiaoerbuyu1233/article/details/88287747 https://blog.csdn.net/qq_44000337/article/details/120277317 https://www.cnblogs.com/zhrngM/p/12899026.html 这里主要是…

谷歌浏览器自动填充密码时,el-input样式错乱

使用到谷歌浏览器的记忆功能&#xff0c;选择的内容为浏览器保存的内容时 会导致element-plus的el-input样式改变 只需要增加一个css样式&#xff0c;就可以解决问题 :deep .el-input__inner {box-shadow: 0 0 0 1000px #fff inset; }修改后