惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Archives - TechRepublic
Security Archives - TechRepublic
Project Zero
Project Zero
K
Kaspersky official blog
G
Google Developers Blog
T
Threat Research - Cisco Blogs
T
The Blog of Author Tim Ferriss
Cyberwarzone
Cyberwarzone
Y
Y Combinator Blog
Recorded Future
Recorded Future
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cisco Talos Blog
Cisco Talos Blog
Latest news
Latest news
Microsoft Security Blog
Microsoft Security Blog
H
Help Net Security
S
Schneier on Security
P
Palo Alto Networks Blog
H
Hacker News: Front Page
N
News and Events Feed by Topic
N
Netflix TechBlog - Medium
博客园 - Franky
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
SecWiki News
SecWiki News
Cloudbric
Cloudbric
TaoSecurity Blog
TaoSecurity Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Hacker News
The Hacker News
C
Check Point Blog
L
LangChain Blog
腾讯CDC
小众软件
小众软件
T
Tenable Blog
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
L
LINUX DO - 最新话题
A
About on SuperTechFans
Google Online Security Blog
Google Online Security Blog
C
Cisco Blogs
Recent Announcements
Recent Announcements
Hacker News: Ask HN
Hacker News: Ask HN
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Vercel News
Vercel News
雷峰网
雷峰网
美团技术团队
D
DataBreaches.Net
Martin Fowler
Martin Fowler
Help Net Security
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
F
Full Disclosure
博客园_首页

yulingtianxia's blog

Flutter 官方终于出手了,DartNative 将何去何从? CPP-Summit 2020 实现 Native 异步回调 Flutter 如何实现 Flutter 同步调用 Native API DartNative 内存自动管理 如何实现一行命令自动生成 Flutter 插件 告别 Flutter Channel,调用 Native API 仅需一行代码! BlockHook and Memory Safety Passing Out Parameter in DartNative 在 Flutter 中玩转 Objective-C Block DartNative Struct DartNative Memory Management: C++ Non-Object DartNative Memory Management: NSObject 谈谈 dart_native 混合编程引擎的设计 用 Dart 来写 Objective-C 代码 BlockHook with Invocation(2) BlockHook with Invocation(1) BlockHook with Private Data BlockHook with Revocation
App 二进制文件重排已经被玩坏了
杨萧玉 · 2019-09-01 · via yulingtianxia's blog

文章目录

  1. 1. 苹果官方文档的古老方案
  2. 2. Facebook 的 hfsort
  3. 3. 基于 Clang SanitizerCoverage 的方案
  4. 4. 后记

『二进制文件重排优化启动速度』本是一项上古 PC 时代就玩过的东东,前一阵子借助某宇宙大厂重新火了一把。不过令我惊讶的是:这么简单个事情竟然搞得如此复杂,而且还声称『开拓性的探索、在没有业界经验可供参考』。。。

说真话可能会得罪人,但是我怕过吗? 我怂了,这段掐了。

其实二进制文件重排很简单啊,重点在于生成 order 文件。我基于 Clang SanitizerCoverage 和业界已有的经验,整了个 AppOrderFiles,一个调用搞定!Enjoy it!

1
2
3
AppOrderFiles(^(NSString *orderFilePath) {
NSLog(@"OrderFilePath:%@", orderFilePath);
});

苹果官方文档的古老方案

苹果的官方文档很早就给了二进制文件重排的方案:Improving Locality of Reference,『早』到甚至被苹果提示这份文档已经年久失修,部分工具和链接失效了。文档的过时不仅体现在还是 GCC 时代,连工具链比如像 gprof 也不能用了,不过 Google 也给出了 macOS 上的替代品,有兴趣的可以去研究下。

Facebook 的 hfsort

需要先用 hf-prod-collect.sh 收集数据,然后塞给 hfsort 生成 hotfuncs.txt 文件。很好很强大,不过对于编程小白来说有一定的使用成本。

PS:此方案来自于我写了这篇文章后,jmpews 大神丢给我了个链接,受益匪浅。(其实我啥都看不懂)

基于 Clang SanitizerCoverage 的方案

Clang 10 documentation 中可以看到 LLVM 官方对 SanitizerCoverage 的详细介绍,包含了示例代码。

简单来说 SanitizerCoverage 是 Clang 内置的一个代码覆盖工具。它把一系列以 __sanitizer_cov_trace_pc_ 为前缀的函数调用插入到用户定义的函数里,借此实现了全局 AOP 的大杀器。其覆盖之广,包含 Swift/Objective-C/C/C++ 等语言,Method/Function/Block 全支持。

开启 SanitizerCoverage 的方法是:在 build settings 里的 “Other C Flags” 中添加 -fsanitize-coverage=func,trace-pc-guard。如果含有 Swift 代码的话,还需要在 “Other Swift Flags” 中加入 -sanitize-coverage=func-sanitize=undefined。所有链接到 App 中的二进制都需要开启 SanitizerCoverage,这样才能完全覆盖到所有调用。

基于 Clang SanitizerCoverage 我写了个工具 AppOrderFiles。CocoaPods 接入,一行调用生成 Order File。啥也不说了,全在 GayHub 里了:https://github.com/yulingtianxia/AppOrderFiles

当然这也不完全是我的原创,对照着 Clang 文档的同时,还参考了 Improving App Performance with Order Files 这篇文章的代码。人家这篇文章虽然早就给出了,不过还是有一些 bug 和优化空间的。

原理就是在 SanitizerCoverage 的回调函数里将地址先收集到队列里,调用 AppOrderFiles() 后会停止收集,并将队列中的 PC 地址依次翻译符号,最后去重。反正代码也不多,直接贴核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
static OSQueueHead queue = OS_ATOMIC_QUEUE_INIT;

static BOOL collectFinished = NO;

typedef struct {
void *pc;
void *next;
} PCNode;




void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
uint32_t *stop) {
static uint32_t N;
if (start == stop || *start) return;
printf("INIT: %p %p\n", start, stop);
for (uint32_t *x = start; x < stop; x++)
*x = ++N;
}








void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
if (!*guard) return;
if (collectFinished) {
return;
}






*guard = 0;
void *PC = __builtin_return_address(0);
PCNode *node = malloc(sizeof(PCNode));
*node = (PCNode){PC, NULL};
OSAtomicEnqueue(&queue, node, offsetof(PCNode, next));
}

后记

苹果官方也提供了 PGO 的详细文档,而且操作很简单。不过它跟二进制文件重排还是有区别的,这里不展开讲了。毕竟相对于对业务代码加载优先级的优化来说,PGO 对启动优化性价比没那么高,应该就是高频调用函数内联之类的(这句纯属瞎扯)。

我为啥过了这么久才发此文呢?猜猜原因是啥:

A. 不爱蹭热度
B. 喜欢炒冷饭
C. 忙准备答辩
D. 8 月已经发过文章了,这篇得等到 9 月发,这样才不浪费

碰到不会的题,我一般三短一长选最长。