作者Lipraxde (静夜)
看板CompilerDev
标题[分享] LiteJIT - 支援 X86/RISC-V 的 JIT
时间Mon Jul 12 03:13:07 2021
https://github.com/Lipraxde/LiteJIT
以前念书时为了在 RISC-V 上跑 binary translator 临时做的 JIT,能够把 C、object
file 读进来,做完 relocation 後拿来跑。
目前可以支援的有 X86、RISC-V,RISC-V 的部分当时我是用 native compiler 编,直接
跑在 HiFive Unleashed 上,近几天试了 cross compiler,发现 RISC-V relocation
type 的命名似乎不太一样,编不起来 Orz。
从 C 到执行的流程差不多是这样:
C -> execlp call cc -> load temp.o -> relocation
编译 C 程式码的部分其实是用 execlp 去呼叫 cc,编译成 temp.o,我实际上做的部分只
有将 temp.o 读进来,然後做 relocation。
大概介绍一下将 object file 读进来会发生的事,
1. 最一开始呢,LiteJIT 会先要一块空的 memory 当 code cache:
┌─────────────────────────────┐
| |
│ Free space │
| |
└─────────────────────────────┘
↑ ↑
got_ptr text_ptr
2. 拿到要跑的 object file 後,透过移动 text_ptr 来 allcoate memory,将所有有
SHF_ALLOC flag 的 section 复制进 cache:
┌──────────────────────┬──────┐
| | |
│ Free space │ data / text│
| | |
└──────────────────────┴──────┘
↑ ↑
got_ptr text_ptr
虽然叫 text_ptr,不过实际上不管 data / text 都会透过它来 allocate。
3. 接着做 relocation,有几种情形,如果不需要 GOT、PLT 的话就直接做,
3.a. 需要 GOT entry 的时候,透过移动 got_ptr 来 allocate GOT entry:
┌───┬──────────────────┬──────┐
| New | | |
│ GOT | Free space │ data / text│
|entry | | |
└───┴──────────────────┴──────┘
↑ ↑
got_ptr text_ptr
3.b. 需要 PLT entry 的时候,移动 text_ptr 来要一块空间输出 PLT entry:
┌───┬──────────────┬───┬──────┐
| New | | New | |
│ GOT | Free space | PLT │ data / text│
|entry | | entry| |
└───┴──────────────┴───┴──────┘
↑ ↑
got_ptr text_ptr
并把要输出的指令写到 PLT entry 里。
4. Relocation 後 code cache 里面大概会像这样:
┌─────┬──────────┬─────┬──────┐
| | | | |
│ GOT | Free spa| PLT │ data / text│
| | | | |
└─────┴──────────┴─────┴──────┘
↑ ↑
got_ptr text_ptr
这时候就可以去查 symbol (function) 来呼叫了,当然还可以继续加 object file。
5. 当 got_ptr、text_ptr 撞在一起的时候,表示 code cache 里面已经没空间了,加入
新的 object file 会失败,这时候要 create 一个新的 LiteJIT XD。
结语:
当初在做 LiteJIT 的时候只是想让 binary translator 能够在 RISC-V 上跑 DBT,因为
用 LLVM 做的关系,object file 可以生现成的出来,不过那时 LLVM 的 JIT 还不支援
RISC-V (不知道现在行不行)。
一开始先从 X86 的 relocation 开始做,没记错的话 LiteJIT 里 X86 relocation 的部
分是我看文件慢慢弄出来的,後来一边看各种 linker 的实作、弄 RISC-V 的 relocation
时,发现我其实可以直接抄 LLVM Linker (lld) 底下 ELF/Arch/RISCV.cpp 里的东西就好
(基本上可以直接照搬),省了我不少功夫,感谢 PkmX 大大 XD。
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 180.177.0.100 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/CompilerDev/M.1626030790.A.BC9.html
1F:推 mshockwave: 感觉很像现在 LLVM Orc JIT 的object layer在做的事 07/12 12:10
2F:推 mshockwave: 推推! 07/12 12:10
3F:→ Lipraxde: 确实是 object layer 在做的事。其实在做 LiteJIT 更早 07/12 18:40
4F:→ Lipraxde: 之前,有跟同实验室的一位同学尝试 port RISC-V,看能 07/12 18:40
5F:→ Lipraxde: 不能让 LLVM 可以直接支援 JIT RISC-V,不过那时好像在 07/12 18:40
6F:→ Lipraxde: 插 stub、算 address 时遇到了些障碍,做出来的东西还 07/12 18:40
7F:→ Lipraxde: 不够用。比较熟 OrcJIT、relocation 後,觉得 OrcJIT 07/12 18:40
8F:→ Lipraxde: 大部分功能不太需要、relocation 自己做比较快,所以就 07/12 18:40
9F:→ Lipraxde: 没去动 LLVM 了 XD 07/12 18:40