Monday, January 15, 2018

Understanding JavaScriptCore JIT

JSC 的架构分为 4 层: LLint, Baseline JIT, DFG JIT, FTL JIT. Webkit 的优势在于对不同种类 JS 解析负荷的适应性. 而这种适应性是有条件的. 显而易见, DFG 的编译无法在满足低延迟的同时具有高吞吐量, 使得 short-running code 具有高延迟性. 所以就有了 FTL 来处理繁重的优化任务, 而 DFG 继续负责轻量级优化, 这样就可以在处理 longer-/shorter-running code 的策略上达到一种妥协与平衡.

首先来看 DFG Mode 优化流程如下:

Bytecode -> Bytecode Parser => Type Inference => Type Check Insertion => CPS Opt Phases => DFG Backend

DFG 实现了很多传统编译器的功能: 寄存器配置, CFG 简化, common subexpression/dead code 去除, 常数传播, 稀疏有条件的常数传播等等. 但是真正的编译器还必须要知道变量类型, 堆对象结构. 因此 DFG 实现了通过收集 LLInt/Baseline 解释信息, 以及 inline cache 技术对变量类型进行预测推导. 在推断失败的情况下通过 OSR exit 返回 Baseline JIT.

而 FTL Mode 优化路径是这样的:

Bytecode -> Bytecode Parser => Type Inference => Type Check Insertion => CPS Opt Phases => SSA Conversion => SSA Opt Phases => LLVM IR -> LLVM

其实就是把 DFG IR 转化成了 LLVM IR, 调用 LLVM 来产生机器码. 于是有了更强大的优化特性, 辟如全域数值编号,更成熟的指令选择器, 更强大的寄存器配置等. LLVM IR 同样基于 SSA, 所以这是一种线性的转化. 并且, LLVM IR 是静态类型的, 配合 DFG 在类型推断上具有的优势, 将 JavaScript 转化为 LLVM IR 就成了一件顺其自然的事情:

JavaScript => DFG CPS IR => DFG SSA IR => LLVM IR

所以, 每一层转化都减少了一部分 JavaScript 的动态性.

为了适应 JavaScript 语言特性, 还需要将 LLVM 和 GC 结合起来. Webkit 将 JS 对象储存在 mark space 和 copy space 中, fixed-size object 和它们相关联的 property 储存在 mark-sweep 中,而后者储存的是 variable-size object, 如 butterfly, (content of) typed array 等.

对于堆对象, 需要有类型映射, 告诉我们哪些字段有指针以及这些指针如何 decode. 只能从其他对象访问的对象可能会被移动, 并且更新指向它们的指针. 在栈中则不需如此, 每一个要从栈中引用的对象必须被固定. GC 的栈扫描必须做下列事情:

0. 确保它除开栈本身之外还读取所有寄存器
1. 保守地考虑每个指针长度的字段可能是指针类型
2. 固定任何一个看起来可能从栈中到达的对象

这意味着这个编译器可以用内存中的值来做任何事情而不需要知道它们是不是指针.

众所周知, SMC 是实现高性能虚拟机的基石. 此编译器实现了以下功能:

0. 部分编译, 即通过 SMC 来延迟 patch 一部分路径.
1. 非法处理, 类型假设不成立时取消对相关函数的调用并触发 OSR Exit.
2. 动态的虚拟化的多态内联缓存.

以上的每一个功能都可以看作是 SMC 内联汇编的实现. 然而, 具体修改的内容并不由 LLVM 提供, 而是 LLVM client. 具体流程大致如下:

patchpoint => emit nop sled => emit machine code => patch or repatch

因为多态内联的缘故, 给 LLVM 带来了一些有趣的优化方法. 比如, 我们所视为控制流的东西, LLVM 可以将其转化为数据流, 得以产生更快更简单的代码.

根据 SMC 直接修改汇编的特性, 我推测它所在的内存页是需要 rwx 权限的, 应该会给漏洞利用带来一些影响, 比如是不是可以通过 info leak 泄露 JIT 代码所在内存页地址, 然后把 shellcode 映射过去达到代码执行的效果? 不过还没试过, 以后再来研究利用, Q-Q

暂且就这么多了, 感觉优化这块的攻击面值得挖一下, 但是又遇到了很多问题没弄懂, 仍然有待学习~

ref:
https://webkit.org/blog/3362/introducing-the-webkit-ftl-jit/
https://en.wikipedia.org/wiki/Static_single_assignment_form
https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)

No comments:

Post a Comment

Compiler Optimizations

Peephole optimization In  compiler theory , peephole optimization is a kind of  optimization  performed over a very small set of instruct...