初始mach-o文件及在项目中应用

5cd0250c241087a65429248759cdc015.jpeg

c360278f5a3d3a043cbc61e3c3079172.gif

本文字数:2250

预计阅读时间:15分钟

3600e827f24e4809cc31403e3df1c660.png

01

认识mach-o的必要性

了解mach-o的结构可以帮助认识系统加载二进制文件的动态链接和静态链接。应用层面,使用initialize的c++函数计算启动时间耗时也需要以mach-o的结构知识为铺垫。还可以用在使用clang自注册启动任务上。后续会一一展开说明。

02

mach-o的定义

mach-o是mach object的缩写,是存储程序或库的标准格式。app的mach-o又称为可执行文件,静态库的.a文件也为mach-o文件,还有诸如此类的一些文件。

  • .o目标文件:MH_OBJECT

  • 静态库文件.a : MH_OBJECT

  • 可执行文件:MH_EXECUTE

  • 动态库:MH_DYLIB

  • dyld:MH_DYLINKER

  • 符号信息:MH_DSYM。可在loader.h的源码中看到全部的mach-o文件。

    181bde3cbfa57d6cbd89c4bb613e3dcf.png

想要深入了解mach-o,可以自己创建一个,在xocde的build setting --> mach-o type 下选择类型,依据xcode的提示步骤可以创建出。如果已经有了文件,想知道是否为mach-o,也可以使用xcode打开文件,在build setting --> mach-o type下查看属于哪种类型。xcode的查看示意见下图:e84c518d9dce2dd02f3dffc8cef7eb43.pngbd1c450ac00a4ee92780e264372d3f3e.png

03

mach-o的结构

查看mach-o的内部结构需要借助于工具mach-o View下载地址。目前下载下来之后需要在mac上运行使用。举例,使用mach-o View查看app的可执行文件,首先需要编译项目,这样会生成.app文件,然后项目中搜索.app:

0dfd1f8761b0cc8bb0c09b22a073dce7.png

右键show in finder,就会找到app包。如下图:

49afc6001b0137c2f219c173545199f1.png

查找可执行文件,文件以项目名称命名的。下图中第一个就是:

0e59a10c02c12c6df426e55b0613b62f.png

通过打开mach-o View可以看到,mach-o分为三大部分,无论是什么类型的mach-o文件,都分为3大部分。

  • mach-o header 描述了Mach-o的cpu框架以及加载命令等信息;

  • load Commands 记录虚拟内存中的布局例如有哪些段,段从哪开始,段占用多大空间;

  • data 记录段的具体数据。如下图,三大部分在mach-o中分布:

a8b41a8d434e02d2bc28611992c63c41.png

1、第一部分:mach-o Header 详解

mach-o header 的结构如下图中红框展示:

15c173552496d94c81c0a61682742d45.png

  • magic number :系统加载器通过该字段判断文件适用于32位还是64位;

  • cpu type:cpu类型,该字段确保系统可以将合适的二进制文件在当下架构下进行,为x86,arm64等;

  • file type :说明文件类型(可执行文件、库文件、核心转储文件、内核扩展文件、DYSM文件、动态库等)mach-o为MH-EXECUTE.;

  • number of load command 说明加载命令的条数;

  • size of load commands 表示加载命令的大小;

如上所述,header介绍了文件的基础信息。

2、第二部分:mach-o内容

mach-o的内容部分分为load commands和 data。

  • load commands 如图所示:

    3ca3a357bac9c3c3c1c60813948aadd7.jpeg

每一个命令的含义下表:

命令名称命令含义
LC_SEGMENT_64将文件中的段映射到进程地址空间
LC_DYLD_INFO_ONLYdyld相关信息
LC_SYMTAB加载全局符号表信息
LC_DYSYMTAB动态链接符号表信息
LC_DYLD_INFO_ONLYdyld相关信息
LC_LOAD_DYLINKER加载一个动态链接器,也就是加载dyld
LC_UUIDapp的uuid
LC_VERSION_MIN_IPHONEOS支持最低系统版本
LC_MAIN设置程序主线程的入口地址
LC_LOAD_DYLIB(动态库名称)加载相应的动态库
LC_FUNCTION_STARTS函数启示地址表
LC_CODE_SIGNATURE代码签名

loader.h文件中可查看命令的官方注释。

  • data部分的内容如图所示:

4a1e4ceb7730b64da618ed5462e2c43e.png如图所示,data有2种段数据,一种为__TEXT段,一种为__DATA段。__text段是Mach-O文件中存储代码的一个特定段,它包含了程序的实际可执行代码。在__text段中,存储了程序的实际指令和函数定义。当程序被加载到内存中并执行时,操作系统会将__text段中的代码加载到内存中,并按照指令逐条执行,从而实现程序的功能。 __text段通常是以只读方式存储在Mach-O文件中,以确保代码的完整性和安全性。这意味着在程序运行时,__text段中的代码是不可被修改的,这有助于防止恶意软件对程序代码进行篡改。__data段是用来存储程序的静态数据的一个特定段。__data段包含了程序中的静态全局变量、静态局部变量和其他静态数据,这些数据在程序运行时需要被初始化和使用。与代码段__text不同,__data段存储的是程序运行时需要进行读写操作的数据。

__text各个段的含义:

名称作用
TEXT.text只有可执行的机器码
TEXT.cstring去重后的C字符串
TEXT.const初始化过的常量
TEXT.stubs符号桩。本质上是一小段会直接跳入lazybinding的表对应项指针指向的地址的代码。
TEXT.stub_helper辅助函数。上述提到的lazybinding的表中对应项的指针在没有找到真正的符号地址的时候,都指向这。
TEXT.unwind_info用于存储处理异常情况信息
TEXT.eh_frame调试辅助信息
_objc_classname类名称
objc_methlist方法列表

__text段在mach-o中的释义:

e2d012b6f303b8f6b192caa18e9ddaec.png

__data 各个段的含义:

名称作用

DATA.data

初始化过的可变的数据

DATA.nl_symbol_ptr

非lazy-binding的指针表,dyld 加载会立即绑定

DATA.la_symbol_ptr

lazy-binding的指针表,每个表项中的指针一开始指向stub_helper

DATA.const

没有初始化过的常量

DATA.mod_init_func

初始化函数,在main之前调用

DATA.mod_term_func

终止函数,在main返回之后调用

DATA.bss

没有初始化的静态变量

DATA.common

没有初始化过的符号声明

DATA.__objc_nlclslist

实现了 load 方法的类

__data 在mach-o中的展示:

a01ee2784cb4cbbfb4c219bcd76f63f6.png

04

mach-o的应用

认识了mach-o,可以将其运用在统计启动时期c++ static initializer 阶段耗时。c++ static initializer 阶段系统做了什么,一个是c++的构造函数属性函数,一个是非基础类型的c++静态全局变量的创建(通常是类或结构体)。在构造函数上打断点,可以得到如图:29ca5184dfc85f454a1aa7cecbcbf527.png

从dyld的源码中可以看到doModeInitFunction()的具体执行。如下图所示:a5ddaa5b3e7a1d5af59bd8ff917089d9.png从dyld的源码中可以看出,取出mod_init_func section 中的元素并执行。可以看出,mod_init_func section中存储的是函数地址,类型为initialize.了解这些之后,自己写一个带有计时的start和end函数,并在中间调用源函数地址。然后hook mod_init_func 中的所有地址,并替换执行自己的函数。步骤如下:

  • hook mod_init_func中的所有地址 。因为__mod_init_func section 位于__DATAsegment.__DATA segment 是数据段,是可以在运行时被修改的。并且,+load方法的执行是在dyld读取这些initializer之前。所以hook mod_init_func中的所有地址是可行的;

  • 修改mod_init_func数据。利用getsectiondata获取到segment的每一个数据,将自己写的方法替换表中的方法;

  • 调用原来的initializer。自己的Initializer中逐个获取每一个原函数地址,调用并计算耗时获取。

通过以上步骤,我们可以得出这一项的耗时,从而做出优化。

认识mach-o,是注册启动任务的必备知识。做注册启动任务的必要性有两点。

  1. 启动代码集中在AppDelegate中,代码逐渐臃肿,易读性降低,且代码之间耦合度高;

  2. 各个业务方加启动任务,都需要启动业务配合。

我们利用mach-o结构的__DATA可读写性。所以可以通过clang的section函数在编译阶段写入macho文件中一个__DATA段。__DATA段存储函数指针的指针。具体的使用步骤为:

  1. 编写注册方法的宏,提供给外部使用;

  2. 业务方注册任务,注册的每个时机都会在编译期间新增一个__DATA类型section,存储任务函数;

  3. App运行,在注册的时机函数中使用getsectbynamefromheader_64遍历取出相应Section中的函数,并依次执行。

代码如下:

static void Launch_Func_(void);\
__attribute__((used, section("__DATA, "#period""))) static const void * __Func__= Launch_Func_;\
static void Launch_Func_(void)#define RegisterLaunchTaskOnWillFinishLaunchPeriod\RegisterLaunchTask(willFinishLaunch)#define RegisterLaunchTaskOnDidFinishLaunchPeriod\RegisterLaunchTask(didFinishLaunch)#define RegisterLaunchTaskOnDidFinishADPeriod\RegisterLaunchTask(didFinishAD)#define RegisterLaunchTaskOnDidFinishHomepagePeriod\RegisterLaunchTask(didFinishHome)

各个业务的使用代码如下:

RegisterLaunchTaskOnDidFinishHomepagePeriod{/*do sth*/
}

参考资料:

1.https://everettjf.github.io/2017/02/06/a-method-of-hook-static-2.initializers/# https://github.com/fangshufeng/MachOView

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

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

相关文章

2、排列重要性 Permutation Importance

您认为模型哪些特性是重要的? 文章目录 1、简介2、工作原理3、代码示例4、解释排列重要性1、简介 对于模型来说,我们可能会问的最基本的一个问题是:哪些特征对预测影响最大? 这个概念被称为特征重要性。 有多种方法可以衡量特征重要性。一些方法回答了上面提到的问题的微…

怎么把几百M大小的视频做成二维码?扫码播放视频在线教程

怎么把几百M大小的视频做成一个二维码展示呢?通过二维码来作为视频的载体是现在很常用的一种手段,通过这种方式不仅成本比较低,而且传播速度也比较快,通过访问云端数据就可以播放视频。 视频二维码生成的方法一般会通过二维码生成…

C++模版初阶

前言 在本文我们将学习模版的基础知识点,了解泛型编程。 一、泛型编程 1、引入 我们如何实现一个通用的交换函数呢? 我们先看一段代码,如下: void Swap(int& left, int& right) {int temp left;left right;right te…

机器学习 | 如何利用集成学习提高机器学习的性能?

目录 初识集成学习 Bagging与随机森林 Otto Group Product(实操) Boosting集成原理 初识集成学习 集成学习(Ensemble Learning)是一种通过组合多个基本模型来提高预测准确性和泛化能力的机器学习方法。它通过将多个模型的预测结果进行整合或投票来做…

【Java程序设计】【C00243】基于Springboot的社区医院管理系统(有论文)

基于Springboot的社区医院管理系统(有论文) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的社区医院管理服务系统 本系统分为系统功能模块、管理员功能模块、用户功能模块以及医生功能模块。 系统功能模块:社…

ElementUI Form:Checkbox 多选框

ElementUI安装与使用指南 Checkbox 多选框 点击下载learnelementuispringboot项目源码 效果图 el-checkbox.vue &#xff08;Checkbox 多选框&#xff09;页面效果图 项目里el-checkbox.vue代码 <script> const cityOptions [上海, 北京, 广州, 深圳] export def…

JProfiler for Mac:提升性能和诊断问题的终极工具

在当今的高性能计算和多线程应用中&#xff0c;性能优化和问题诊断是至关重要的。JProfiler for Mac 是一个强大的性能分析工具&#xff0c;旨在帮助开发者更好地理解其应用程序的运行情况&#xff0c;提升性能并快速诊断问题。 JProfiler for Mac 的主要特点包括&#xff1a;…

2024/2/3

一&#xff0e;选择题 1、适宜采用inline定义函数情况是&#xff08;C&#xff09; A. 函数体含有循环语句 B. 函数体含有递归语句‘、考科一 ’ C. 函数代码少、频繁调用 D. 函数代码多、不常调用 2、假定一个函数为A(int i4, int j0) {;}, 则执行“A (1);”语句后&#xff0c…

机器学习复习(2)——线性回归SGD优化算法

目录 线性回归代码 线性回归理论 SGD算法 手撕线性回归算法 模型初始化 定义模型主体部分 定义线性回归模型训练过程 数据demo准备 模型训练与权重参数 定义线性回归预测函数 定义R2系数计算 可视化展示 预测结果 训练过程 sklearn进行机器学习 线性回归代码…

电商小程序01需求分析

目录 1 电商用例分析2 功能架构3 原型开发3.1 首页3.2 店铺页面3.3 配货单3.4 配货单有货3.5 我的应用3.6 商品详情3.7 订单确认3.8 收货地址3.9 店铺详情3.10 店铺分类3.11 商品分类 总结 低代码学习的时候最高效的方法就是带着问题去学习&#xff0c;一般可以先从电商小程序开…

【大数据】Flink SQL 语法篇(三):窗口聚合(TUMBLE、HOP、SESSION、CUMULATE)

Flink SQL 语法篇&#xff08;三&#xff09;&#xff1a;窗口聚合 1.滚动窗口&#xff08;TUMBLE&#xff09;1.1 Group Window Aggregation 方案&#xff08;支持 Batch / Streaming 任务&#xff09;1.2 Windowing TVF 方案&#xff08;1.13 只支持 Streaming 任务&#xff…

配置实例—交换机VLAN聚合配置实例

一、组网需求 某公司拥有多个部门且位于同一网段&#xff0c;为了提升业务安全性&#xff0c;将不同部门的用户划分到不同VLAN中。现由于业务需要&#xff0c;不同部门间的用户需要互通。如图1所示&#xff0c;VLAN2和VLAN3为不同部门&#xff0c;现需要实现不同VLAN间的用户可…

浪漫的通讯录(顺序表篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人能…

代码随想录算法训练营第39天 | 62.不同路径 + 63.不同路径 II

今日任务 62.不同路径 63. 不同路径 II 62.不同路径 - Medium 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只…

flutter如何实现省市区选择器

前言 当我们需要用户填写地址时&#xff0c;稳妥的做法是让用户通过“滚轮”来滑动选择省份&#xff0c;市&#xff0c;区&#xff0c;此文采用flutter的第三方库来实现这一功能&#xff0c;比调用高德地图api简单一些。 流程 选择库 这里我选择了一个最近更新且支持中国的…

Acwing 141 周赛 解题报告 | 珂学家 | 逆序数+奇偶性分析

前言 整体评价 很普通的一场比赛&#xff0c;t2思维题&#xff0c;初做时愣了下&#xff0c;幸好反应过来了。t3猜猜乐&#xff0c;感觉和逆序数有关&#xff0c;和奇偶性有关。不过要注意int溢出。 欢迎关注: 珂朵莉的天空之城 A. 客人数量 题型: 签到 累加和即可 import…

Three.js学习3:第一个Three.js页面

一、一图看懂Three.js 坐标 这个没什么好说的&#xff0c;只是需要注意颜色。在 Three.js 提供的编辑器中&#xff0c;各种物体的坐标也这样的色彩&#xff1a; 红色&#xff1a;x 轴 绿色&#xff1a;y 轴 蓝色&#xff1a;z 轴 Three.js 提供的编辑器可以在本地 Three.js …

常用git指令

一.安装配置git&&利用SSH完成Git与GitHub的绑定 1.参考知乎网址&#xff1a;还不会使用 GitHub &#xff1f; GitHub 教程来了&#xff01;万字图文详解 二.在git上更新仓库步骤 1.在新建文件夹下&#xff0c;右键选择“git bash here” 2.把项目下载到本地&#xf…

AI应用开发-git开源项目的一些问题及镜像解决办法

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享&#xff0c;包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概…

微信小程序(三十一)本地同步存储API

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.存储数据 2.读取数据 3.删除数据 4.清空数据 源码&#xff1a; index.wxml <!-- 列表渲染基础写法&#xff0c;不明白的看上一篇 --> <view class"students"><view class"item…