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

news2024/10/7 10:23:14

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.coloradmin.cn/o/1434277.html

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

相关文章

Stable Diffusion 模型下载:ReV Animated

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十下载地址模型介绍 该模型能够创建 2.5D 类图像生成。此模型是检查点合并,这意味着它是其他模型的产物,以创建从原始模型派生的产品。 条目内容类型大模型

【c/python】GtkGrid

一、GtkGrid GtkGrid 是 GTK (GIMP Toolkit) 中的一个基础容器构件(widget),它可以用来安排其他构件在一个灵活的多行多列的网格中。每个加入网格的构件都可以占据一个或多个行和列。由于 GtkGrid 提供了在二维空间中安排构件的方式&#xf…

kvm qemu 优化 windows 虚拟机速度

主要优化磁盘 io 和网络 io 都选为 virtio windows 驱动下载 https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.185-2/virtio-win-0.1.185.iso I also had incredibly slow performance with my virtual HDD. The followin…

【LeetCode】刷题总结 - 15. 三数之和

15. 三数之和 | LeetCode 思路 首先对 nums 进行排序,然后设置三个指针:left、mid、right: left 从最左边开始,依次向后遍历每次固定住 left 后,就化为一个 2sum 问题: mid left 1,right …

基于Java (spring-boot)的实验室管理系统

一、项目介绍 基于Java (spring-boot)的交通管理系统功能:注册登录、个人信息管理、驾驶证业务类型管理、机动车业务类型管理、新闻类型管理、违法处理业务类型管理、驾驶证业务管理、机动车业务管理、新闻管理、违法处理业务管理、用户管理。 二、作品包含 ​ 三、…

[软件工具]文档页数统计工具软件pdf统计页数word统计页数ppt统计页数图文打印店快速报价工具

文档页数统计工具软件——打印方面好帮手 在信息化时代,文档已成为我们工作、学习、生活中不可或缺的一部分。无论是学术论文、商业报告,还是个人日记,都需要我们对其进行有效的管理。而在这个过程中,文档页数统计工具软件就显得…

[office] 教你实现Excel中工作表重命名的诀窍 #知识分享#职场发展#其他

教你实现Excel中工作表重命名的诀窍 在Excel中要实现工作表的重命名其实不是难事,重在你要掌握技巧。一些初学者,可能还不是特别的懂。今天,小编就要一步步来教一下大家了。有两种方法,大家学好了。 方法一、打开excel表格&#x…

111.乐理基础-五线谱-五线谱的节奏型、打拍子

内容参考于:三分钟音乐社 上一个内容:110.乐理基础-五线谱-五线谱的速度-CSDN博客 首先必须先看 打拍子 这些东西 简谱里的节奏型总结图: 换成五线谱的节奏型:简谱里会把两个八分音符用根横线连起来,所以五线谱里也…

C#中dll引用常见错误

当你在使用C#开发程序时,经常会遇到需要引用外部的dll文件来扩展程序的功能或者使用一些第三方库。然而,在引用这些dll文件的过程中,有时候会遇到一些问题,比如上面提到的错误信息:“未能加载文件或程序集“System.Run…

Java实现婚恋交友网站 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 会员管理模块2.3 新闻管理模块2.4 相亲大会管理模块2.5 留言管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 会员信息表3.2.2 新闻表3.2.3 相亲大会表3.2.4 留言表 四、系统展示五、核心代码5.…

如何使用MCSM搭建我的世界Java版服务器并实现远程联机游戏

文章目录 1. 安装JAVA2. MCSManager安装3.局域网访问MCSM4.创建我的世界服务器5.局域网联机测试6.安装cpolar内网穿透7. 配置公网访问地址8.远程联机测试9. 配置固定远程联机端口地址9.1 保留一个固定tcp地址9.2 配置固定公网TCP地址9.3 使用固定公网地址远程联机 本教程主要介…

寒假作业-day4

单向链表增删 #include <myhead.h> typedef struct a {int date;struct a *next; }aa; //创建节点 aa *Creat() {aa *s(aa*)malloc(sizeof(aa));s->date0;s->nextNULL;return s; } //头插 aa *insert(aa *head,int num) {aa *sCreat();s->datenum;if(NULLhead)…

[C语言] 指针详解(1)

一. 指针 利用指针,可以找到相对应内存地址(唯一的一段编号),从而定位数据. (通俗来说,指针就是变量,用来存放内存单元的地址) 保存一段 16进制的 地址编号 二、指针类型/变量: 类型: 基础类型* 如: int* char*指针变量: int* pa pa就为指针变…

2.5学习总结

2.5 1.传纸条 2.装箱问题 3.开心的金明 4.传球游戏 5.修改数组 6.对局匹配 7.刷题统计 传纸条https://www.luogu.com.cn/problem/P1006 题目描述 小渊和小轩是好朋友也是同班同学&#xff0c;他们在一起总有谈不完的话题。一次素质拓展活动中&#xff0c;班上同学安排坐成一…

【已解决】青龙面板依赖安装失败原因

青龙面板必须安装依赖&#xff0c;才可以执行脚本&#xff0c;这是不争的事实。 如果脚本跑不起来&#xff0c;就去看看依赖吧。 NodeJs 依赖如下 axios request canvas cheerio js-base64 dotenv magic tough-cookie ws7.4.3 require requests date-fns ts-md5 typescript j…

Office恢复旧UI|Office UI问题|Word UI|小喇叭找不到

Office恢复旧UI&#xff5c;Office UI问题&#xff5c;Word UI&#xff5c;小喇叭找不到 问题描述&#xff1a;Office新版本默认新UI&#xff0c;主界面没有小喇叭可以切换到旧UI. 解决方案&#xff1a; 以下述内容新建.txt&#xff0c;保存并改后缀为.reg&#xff0c;双击打开…

从领域外到领域内:LLM在Text-to-SQL任务中的演进之路

导语 本文介绍了ODIS框架&#xff0c;这是一种新颖的Text-to-SQL方法&#xff0c;它结合了领域外示例和合成生成的领域内示例&#xff0c;以提升大型语言模型在In-context Learning中的性能。 标题&#xff1a;Selective Demonstrations for Cross-domain Text-to-SQL会议&am…

Qt设计师中(没有现成的控件):如何添加QToolBar工具栏

1、在QtCreator设计师界面中,在MainWindow上右键,有“添加工具栏”菜单项 2、但只有在MainWindow上右键才有&#xff0c;在其它控件上方点击则没有&#xff0c;那么怎么在对话框上添加呢&#xff1f; 可以添加一个QWidget&#xff0c;然后手动在ui文件里把class改为QToolBar就…

ONLYOFFICE 桌面编辑器8.0上新!六大更新内容等你来用!

各位铁铁&#xff0c;相信你们对ONLYOFFICE都不陌生了&#xff0c;那么今天咱们具体来看看ONLYOFFICE桌面编辑器8.0的上的六大新内容吧~ 更新一&#xff1a;可填写的PDF表单 8.0版本中最引人瞩目的改进之一&#xff0c;是具备创建高度复杂的PDF表单的能力&#xff0c;并允许用…

CSS的Day05(浮动+flex布局)

跟着黑马程序员的课&#xff0c;稍稍对CSS的了解 常见的显示模式&#xff1a;行内、块级、行内块 在HTML中&#xff0c;标准流也称为文档流或普通流&#xff0c;是指元素按照其在HTML文档中的出现顺序依次排列的方式。在标准流中&#xff0c;元素会自动占据父容器的空间&#…