前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >为何百兆静态库能打进数兆的可执行文件?

为何百兆静态库能打进数兆的可执行文件?

作者头像
落影
发布于 2018-04-27 10:21:17
发布于 2018-04-27 10:21:17
2.5K10
代码可运行
举报
文章被收录于专栏:落影的专栏落影的专栏
运行总次数:0
代码可运行

前言

第三方库是工程开发必不可少的部分,而第三方库可以是.a和.framework的静态库,也可以是.framework的动态库,其中静态库是最常用的方式。

静态库往往比较大,可在打包到可执行文件之后,对安装包大小的增加远远小于静态库本身的Size。

那么,就产生两个问题:

1、静态库里面存在什么内容?

2、静态链接到可执行文件后为什么体积变小?

本文就以.framework的静态库来分析具体情况。

正文

1、framework静态库的打包

新建工程,选择Cocoa Touch Framework,再到Build Settings选择Mach-O TypeStatic Library,然后build出来目标文件就是framework静态库。

2、framework静态库的内容

按照上面的步骤打包出来的LYTestKit.framework,具体的内容如下:

  • Headers为头文件;
  • plist文件和Modules文件夹是一些描述文件;
  • LYTestKit为Mach-O binary文件,LYTestKit占了静态库99%的体积。
3、LYTestKit文件内容分析

打开terminal(终端),进入文件夹所在目录,输入指令file LYTestKit

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
LYTestKit: Mach-O universal binary with 4 architectures: [arm_v7:current ar archive] [arm64]
LYTestKit (for architecture armv7): current ar archive
LYTestKit (for architecture i386):  current ar archive
LYTestKit (for architecture x86_64):    current ar archive
LYTestKit (for architecture arm64): current ar archive

可以知道LYTestKit包括armv7i386x86_64arm64四种CPU架构的指令。

接下来就是我们的大杀器Hopper Disassembler登场。

软件的链接地址,密码:vbrqit

Hopper Disassembler打开LYTestKit,选择架构为arm64,再选择一个原工程对应的.o文件,首先映入眼帘的是下面这段描述:(不知道.o文件是什么的,点这里复习下)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
--------------------------------------------------------------------------------

        File: /Users/loyinglin/Documents/LYTestKit/Framework/LYTestKit.framework/LYTestKit
        MachO file
        CPU: aarch64
        64 bits

--------------------------------------------------------------------------------
*/

接下来,是这个文件的描述:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        ; Segment
        ; Range: [0x0; 0x8a1b[ (35355 bytes)
        ; File offset : [3584; 38939[ (35355 bytes)
        ; Permissions: readable / writable / executable

整个文件的大小是35355 bytes,对应的区间为3584, 38939。

文件的最后一行为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0000000000008a1a        db  0x01 ; '.'

整个Segment的地址是0x8a1b结束,十六进制0x8a1b = 35355 十进制。

从这里可以看出,静态库中地址与大小一一对应。

可以这么理解,假如某条指令需要到地址0x0008a1a取值,即是相对应起始位置加上0x0008a1a偏移的地址。

而静态库中的偏移应该等于内存中的偏移,那么0x0008a1a的偏移地址在内存中的大小就是35355 bytes。

紧接着是下面这段描述:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        ; Section __text
        ; Range: [0x0; 0x2300[ (8960 bytes)
        ; File offset : [3584; 12544[ (8960 bytes)
        ; Flags: 0x80000400
        ;   S_REGULAR
        ;   S_ATTR_PURE_INSTRUCTIONS
        ;   S_ATTR_SOME_INSTRUCTIONS

.Section __text表示接下来是代码段的内容,机器指令的大小为8960 bytes。

类似的,代码段之后还有:

  • Section __objc_classrefs 类的引用,大小为 64 bytes
  • Section __objc_methname 自动生成和声明的函数名, 大小为2140 bytes;("viewDidLoad"、"init"这样的函数名常量)
  • Section __objc_selrefs selector的引用),大小为 520 bytes;(@selector(init)、@selector(setProperty:))
  • Section __objc_data 初始化的变量, 大小为80 bytes;(@property、ivar、 struct __objc_class这样的变量)
  • Section __objc_ivar ivar的引用,大小为 84 bytes;(OBJC_IVAR$_SampleClass._property) ivar是objc_ivar的指针,objc_ivar有变量名、变量类型等成员,如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef objc_ivar * Ivar;
  struct objc_ivar {
     char *ivar_name;
     char *ivar_type;
     int ivar_offset;
  #ifdef __LP64__
     int space;
  #endif
  }
  • Section __cstring 代码中声明的字符常量,大小为 1360 bytes;(@"Hello"、@"你好"这样的字符常量)
  • Section __cfstring 代码中声明的CFString字符常量,大小为 224 bytes
  • Section __objc_classname Objective-C Class的类名,大小为 64 bytes
  • Section __objc_const __objc_metaclass_xxx常量的引用和__objc_class_xxx structs 的声明,大小为 3672 bytes;(OC的runtime用结构体比如struct __objc_method、 struct __objc_ivar 、struct __objc_property)
  • Section __debug_str 调试用的字符信息,包括方法对应的字符串,大小为 5489 bytes
  • Section __debug_line 调试用的代码行号信息,大小为 2891 bytes
  • 以及各类其他的Section。

在大致了解一个.o文件的内部构成之后,我们来看看链接过程.o文件变化。

4、静态链接的过程

静态连接就是把静态链接库中的文件链接到可执行文件中,整个过程由链接器负责。

链接过程分为两步:

  • 1、空间和地址分配,扫描所有的目标文件,获得各个段的长度、属性、位置信息,并把所有的符号定义以及引用收集起来,放到全局的符号表中。通过所有段的长度,计算和合并后的长度和位置,并建立映射关系;
  • 2、符号解析和重定位,使用上一步收集到的信息,读取文件中段的数据和重定位信息,进行符号解析和重定位。

静态链接的更详细内容点这里

那么可执行文件的内部是什么组成?

答案是:File Header.text secton.data secton.bss secton四大部分。

File Header是文件头,描述整个文件的文件属性,包括是否可执行文件、目标操作系统、目标硬件等信息。文件头还包括一个段表(Section Table)描述下面几个段的偏移地址以及属性。

.text section是代码段,存放编译生成的指令;

.data section是数据段,存放已初始化的静态常量数据;

.bss section存放未初始化的静态常量。

静态库链接过程体积变小的答案

framework静态库在链接之后,体积会急剧减少,原因有几个:

1、用于链接的信息被剔除,比如说类引用、函数名等,字符信息中的函数名字等在链接时会放入链接表,用于查找地址,但不打入二进制文件;

2、调试用的信息比如符号串、代码行号等不会打入二进制包,而是额外生成符号表;

3、Xcode默认在release下会用fastest的优化选项;

总结

经过此次思考,对静态库的内容有更清晰的认识,也对编译与链接更加了解。

附录 exploring Mach-O binaries analysis of facebook app classllvm MCSectionMachO developer.apple Assemble asm_directives

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.04.25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
「对安装包大小的增加远远小于静态库本身的Size」这里还有个原因:只有真正使用的类、方法才会链接到可执行文件中。比如静态库有100个互相独立的类,如果只使用了其中一个类,那么只有该类会链接到可执行文件中。
「对安装包大小的增加远远小于静态库本身的Size」这里还有个原因:只有真正使用的类、方法才会链接到可执行文件中。比如静态库有100个互相独立的类,如果只使用了其中一个类,那么只有该类会链接到可执行文件中。
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
iOS逆向之Mach-O文件
阅读笔者的其他文章,我们了解了编译过程中的预处理、词法分析、语法分析、编译、链接等步骤。经常和编译型语言打交道的开发者对于可执行文件的编译过程肯定不陌生。我们用 Xcode 构建一个程序的过程中,会把源文件 (.m 和 .h) 文件转换为一个可执行文件。这个可执行文件中包含的字节码将会被 CPU (iOS 设备中的 ARM 处理器或 Mac 上的 Intel 处理器) 执行。
VV木公子
2021/03/07
11.2K0
iOS逆向之Mach-O文件
深入iOS系统底层之静态库介绍
程序员编写的是源代码,而计算机运行的则是CPU能识别的机器指令,因此必须要有一系列工具或程序来将源代码转化为机器指令,这个转化的过程需要经历编译和链接两个主要阶段。所谓编译就是将源代码文件转化为中间的目标文件(Object file)。目标文件的后缀一般为.o。iOS系统的目标文件也是一种mach-o格式的文件,mach-o文件的头部结构体:struct mach_header中的filetype成员字段用来描述当前文件的类型,目标文件所对应的类型是MH_OBJECT。目标文件中的布局结构和内容和可执行文件中的布局结构和内容非常相似,编译后形成的目标文件中的代码段(__TEXT Segment)中的节(__text Section) 中的内容存放的是已经被编译为机器指令的二进制代码了。下面就是一个目标文件的布局结构:
欧阳大哥2013
2019/03/04
1.4K0
Apple 操作系统可执行文件 Mach-O
Mach-O 的全称是 Mach Object File Format。可以是可执行文件,目标代码或共享库,动态库。Mach 内核的操作系统比如 macOS,iPadOS 和 iOS 都是用的 Mach-O。Mach-O 包含程序的核心逻辑,以及入口点主要功能。
用户7451029
2020/06/16
3K0
Mach-O文件结构
作为iOS,iPadOS、macOS平台的可执行文件格式,Mach-O文件涉及App启动运行、bitcode分析、 crash符号化等诸多多个功能:
梧雨北辰
2021/11/24
1.5K0
Mach-O文件结构
检查第三方库是否包含 bitcode 信息
iOS 9 发布后,开发者可以提交包含 bitcode 的程序到APPStore。当 llvm 更新或者新款手机使用了新的cpu命令集架构时,苹果可以使用最新的llvm版本重新将bitcode编译为安装包,确保能够充分利用新的llvm的最新优化或者适配最新的cpu命令集架构,避免了开发者手动提交新安装包的繁琐过程。
酷酷的哀殿
2020/11/20
1.8K0
代码管理| 手把手教你封装自己的静态库SDK
这里重点说下,怎样饮用Bundle中的图片资源。这里使用的是简写:@"JWJFramework.bundle/open"其中JWJFramework.bundle是Bundle的名称。
進无尽
2018/09/12
1.5K0
代码管理| 手把手教你封装自己的静态库SDK
Mach-O相关概念
Mach-O是Mach Object的缩写,是Mac/iOS上用于存储程序、库的标准格式
Scott_Mr
2022/05/11
1K0
Mach-O相关概念
Xcode 常见 CLI 工具
在咱们日常开发中,或多或少都会用到 Xcode 内置的一些CLI工具,但是大部分小伙伴可能只是会用到一些具体的命令,今天我们就一起来聊一聊 Xcode 内置的常见Command Lines Tool。
CoderStar
2022/09/23
3.7K0
Xcode 创建.a和framework静态库
最近因为项目中的聊天SDK,需要封装成静态库,所以实践了一下创建静态库的步骤,做下记录。
Haley_Wong
2018/08/22
3.4K0
Xcode 创建.a和framework静态库
浅谈 LinkMap 检查每个类占用大小
LinkMap 文件是 Xcode 产生可执行文件的同时生成的链接信息,用来描述可执行文件的构造成分,包括代码段 __TEXT 和数据段 __DATA 的分布情况。只要设置 Project->Build Settings->Write Link Map File 为 YES,并设置 Path to Link Map File,build 完后就可以在设置的路径看到 LinkMap 文件了:
s_在路上
2018/09/30
1.9K0
浅谈 LinkMap 检查每个类占用大小
APP生成与运行(二)
iOS开发中,main函数是我们熟知的程序启动入口,但实际上并非真正意义上的入口,因为在我们运行程序,再到main方法被调用之间,程序已经做了许许多多的事情,比如我们熟知的runtime的初始化就发生在main函数调用前,还有程序动态库的加载链接也发生在这阶段。
Helloted
2022/06/07
1.3K0
APP生成与运行(二)
mach-o文件分析多余的类和方法
最近做包大小优化,在做项目代码优化时,其中有一个过程是分析Mach-O文件,看网上很多文章都说通过otool分析Mach-O,获取objc_classrefs、objc_classlist等,然后找出无用类和无用方法。
莫空9081
2021/06/15
3.8K0
编译与链接过程的思考
前言 最近遇到一个错误,如下 在解决过程中,回顾了很多知识,于是有了这篇文章。 关键词:预处理、编译、汇编、链接、动态链接库、静态链接库、真机调试。 正文 以.c文件的编译流程为例,如下图
落影
2018/04/27
1.3K1
编译与链接过程的思考
iOS里的动态库和静态库
静态库:链接时,静态库会被完整地复制到可执行文件中,被多次使用就有多份冗余拷贝(图1所示)
且行且珍惜_iOS
2022/05/13
3K0
iOS里的动态库和静态库
不给“爸爸”添麻烦 - iTOP iOS 动态库改造
苹果官方文档 对提交商店 APP 的二进制文件中__TEXT段大小有限制,超过大小限制的应用在提交评审的时候会被拒绝...
腾讯Bugly
2018/03/23
2.3K2
减包-删除无用的代码
使用开源工具 LSUnusedResources 检查重复图片,但是可能会有误报,比如 [@”image%d”, index] 这种引用方式无法检查到,需要人工在核对一边。
Helloted
2022/06/08
1.5K0
减包-删除无用的代码
iOS强化 : 熟悉 Mach-O 文件
Mach-O(Mach Object)是 macOS、iOS、iPadOS 存储程序和库的文件格式。对应系统通过应用二进制接口(application binary interface,缩写为ABI) 来运行该格式的文件。
网罗开发
2021/04/26
1.2K0
iOS强化 : 熟悉 Mach-O 文件
探秘 Mach-O 文件
之前负责项目的包体积优化学习了 Mach-O 文件的格式,那么 Mach-O 究竟是怎么样的文件,知道它的组成之后我们又能做点什么?本文会从 Mach-O 文件的介绍讲起,再看看认识它后的一些实际应用。
会写bug的程序员
2020/06/19
2.4K0
探秘 Mach-O 文件
ios的动态库和静态库
当你创建一个framework文件时,系统“默认”是一个动态库的格式,如果想做成静态库,需要在buildSetting中将Mach-O Type选项设置为Static Library就行了!
码客说
2019/10/22
8790
iOS开发静态库SDK指南: 搭建一个提高开发效率的静态库工程、混淆带有bitcode sectname 的静态库
【代码混淆】1、基于编译器混淆静态库(StaticLib)2、字符串加密:使用clang-c接口
公众号iOS逆向
2021/03/08
9970
相关推荐
iOS逆向之Mach-O文件
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验