完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
方案简介
OCPack是一种 iOS 平台上 App 动态化威廉希尔官方网站 方案,用户可以使用 Objective-C 语言编写待动态化的功能逻辑(生成.m文件),然后通过OCPack提供的工具链生成 patch 文件(.bin格式)。客户端则内置了一个基于 Native 环境的的虚拟栈机,它可以动态加载并执行存储在客户端的 patch 文件中的方法。Patch 文件可根据业务需要随时下载、更新并由虚拟机重新加载、运行。 此方案的主要优点:
|
|
|
|
威廉希尔官方网站
方案
OCPack复用 clang 前端来分析目标 Objective-C 代码的语法树,通过自定义 ASTFrontendAction 来遍历语法树,生成自定义指令集的汇编程序。在客户端,由自研的虚拟栈机来解释执行汇编程序中的二进制指令。 生成 patch 文件的基本数据流程是:
在运行时,客户端内置的虚拟栈机能够根据用户需求加载指定的 patch 文件,然后就可以执行其中任意方法了。 以下分模块来介绍主要威廉希尔官方网站 点: 编译模块: 功能:Objective-C程序(.m) -> 语法树 -> 汇编程序(.s) 1. 独立的编译程序 主要使用 clang 的 libTooling 接口,实现了 AST FrontendAction,通过实现自定义的 ASTConsumer 递归遍历语法树,对不同的节点类型作相应处理,生成可执行的汇编指令程序。
|
|
|
|
栈机汇编指令集
为了连接包含有 Objective-C 代码逻辑的语法树和客户端运行的虚拟机,OCPack需要定义一套比较完整的汇编指令集。该指令集应该满足以下两个条件:
2.1 push 和 pop 指令 栈机中最基本的部件是操作栈,用于存放正在进行中的操作数和操作结果。如:要计算 1 + 2,栈机需要执行类似以下指令: push instant 1 push instant 2 add 先将两个操作数1和2依次 push 进操作栈,再执行 add 操作。add 操作负责先 pop 对应的操作数,经过加法计算后再将结果 push 进栈。以上指令执行完后,操作栈顶存放的就是操作结果3。 但只有操作栈是不够的,程序逻辑的复杂性要求像局部变量、方法参数等数据拥有确定不变的内存地址,因此OCPack将局部变量、静态变量、常量、指针、立即数等分别对应一个段,每种类型的变量对应于所属段中的一个序号(index)。
线程无关的数据段主要包括: const //常量字符串 static //静态变量 instant //立即数 //注:线程无关的段数据存放在machine中,各线程都可见 在对语法树进行遍历的过程中,OCPack编译器会维护一个符号表,对每个变量声明(VarDecl)建立相应的符号表项,存放其段名和序号(index)。 对语法树中的变量引用(VarDeclRef 结点),OCPack编译器会找到其相应的 VarDecl 的符号表项,生成相应的 push、pop 指令。 push和pop指令的参数就是段名和序号(index):
2.4 跳转指令 为了实现条件判断 if/else 和 for 循环等流程控制语法,OCPack指令集定义了jmp和jmp_if指令,根据语法树中对应类型的节点具体情况,生成相应的跳转指令和跳转 label。这些文本跳转 label 会被存储在 .s 文件中,然后在下一阶段(Assembler 将 .s 转换为 .bin时)被替换成相应的偏移地址。 2.5 switch指令 1) switch跳转表 switch需要运行时决定跳到哪个 case label 对应的地址,只用jmp_if需要在 case列表代码尾部插入多条比较语句,而栈机又需要每次比较前都push相应的参数,实现比较繁琐而且性能较差,因此OCPack在指令集中增加了cmp_n、resolve_label和jmp_tos指令。
分别维护一个 break和 continue 的 label 栈,栈顶元素为当前 break 或 continue 调用时应该 jmp 到的目标 label,在目标表达式开始和结束时进行入栈和出栈操作。在遇到语法树上结点为 break 或 continue 时,取出当前栈顶的目标 label,生成jmp 目标label指令。 2.6 call指令
2.8 左右值转换
2.9 Objective-C 方法调用指令
|
|
|
|
汇编模块
功能:汇编程序(.s) -> 二进制补丁程序(.bin) 解析整个 .s 文本,将文本 token 转换为对应的二进制数据,主要包括:
注: 二进程文件在运行时所需的大部分数据其排布都与 .bin 文件里的排布完全相同,这样能方便地使用内存映射来实现 .bin 文件的加载,从而可以减少私有内存的占用量。 加载模块 功能:二进制补丁程序(.bin)加载 在调用 load_image 时,虚拟机会先将 .bin 文件 mmap 到一段内存中,检测 magic number, bin version 及 arch 是否匹配。 然后按全局区的大小申请一段 shared anonymous mmap 内存。 然后分别加载各个数据段,建立必要的运行时内存数据,主要的数据段包括:
执行模块 功能:二进制补丁程序(.bin)的执行 1) 虚拟机基本信息
注:VM 函数栈帧具体内存布局如下: 2) Objective-C 调用虚拟机方法
要支持此流程,需保证 f2 调用完成后虚拟机当前栈帧的 sp 与调用前完全一致,以保证 f1 的执行不受影响。 4) 虚拟机方法间互相调用 在调用OC方法时,会先检测对应的方法是否在导出函数表中,如果在,则走此流程。这也要求调用虚拟机方法时的参数表应该与直接调用 OC 方法是一致的,否则还需要重新拷贝参数做适配,降低虚拟机性能。 5) 多线程支持
由OCPack编译器生成或指定一个 GUID,后续生成的所有相关文件(包括.s、.sym、.bin以及运行时生成的崩溃 log)中都存有此 GUID。线上的崩溃日志发送回来后,崩溃解析服务器能够根据日志中的 GUID 查找到相应的符号文件进行符号解析。同时构建服务器数据库中存储了对应 GUID 的 bin 文件打包时所有依赖项的源信息(包括对应的 .s 文件、bin 代码对应的源代码版本、OCPack工具链的版本等),方便开发重现、定位相关问题。 9) Hook Objective-C 方法
|
|
|
|
性能优化
|
|
|
|
未来计划
链接器
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
“0元购”智元灵犀X1机器人,软硬件全套图纸和代码全公开!资料免费下载!
9085 浏览 2 评论
1440 浏览 0 评论
【实操文档】在智能硬件的大模型语音交互流程中接入RAG知识库
7594 浏览 1 评论
防止AI大模型被黑客病毒入侵控制(原创)聆思大模型AI开发套件评测4
1169 浏览 0 评论
不可错过!人工神经网络算法、PID算法、Python人工智能学习等资料包分享(附源代码)
3478 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-23 22:30 , Processed in 0.675460 second(s), Total 80, Slave 64 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号