Skip to content

Commit 4387534

Browse files
authored
Jitlink (#20)
* support relocatable file loading * refactor the loading process * implement simple relocation However, there are bugs. * support plt fix bug * Realize the basic functions of jitlink
1 parent c441d83 commit 4387534

39 files changed

+3569
-2017
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
target
2-
.vscode
2+
.vscode
3+
zig*

Cargo.lock

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ features = ["alloc"]
7272
[dependencies]
7373
bitflags = "2.9.0"
7474
delegate = "0.13.3"
75+
hashbrown = "0.16.0"
7576

7677
[dev-dependencies]
7778
criterion = "0.5.1"

Cross.toml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
[build]
2-
pre-build = [
3-
"apt-get update && apt-get install --assume-yes --no-install-recommends lld",
4-
]
5-
6-
[build.env]
7-
passthrough = ["ELF_LOADER_CI=1"]
8-
91
[target.riscv64gc-unknown-none-elf]
102
image = "ghcr.io/cross-rs/riscv64gc-unknown-linux-gnu:main"
113

@@ -14,3 +6,6 @@ image = "ghcr.io/cross-rs/aarch64-unknown-linux-gnu:main"
146

157
[target.x86_64-unknown-none]
168
image = "ghcr.io/cross-rs/x86_64-unknown-linux-gnu:main"
9+
10+
[build.env]
11+
passthrough = ["ELF_LOADER_CI=1"]

README_zh.md

Lines changed: 126 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -4,153 +4,159 @@
44
[![elf_loader on docs.rs](https://docs.rs/elf_loader/badge.svg)](https://docs.rs/elf_loader)
55
[![Rust](https://img.shields.io/badge/rust-1.88.0%2B-blue.svg?maxAge=3600)](https://github.com/weizhiao/elf_loader)
66
[![Build Status](https://github.com/weizhiao/elf_loader/actions/workflows/rust.yml/badge.svg)](https://github.com/weizhiao/elf_loader/actions)
7+
78
# elf_loader
8-
`elf_loader`能够从内存、文件加载并重定位各种形式的elf文件,包括`Executable file``Shared object file``Position-Independent Executable file`
99

10-
[文档](https://docs.rs/elf_loader/)
10+
**高性能、跨平台、无标准库依赖的ELF文件加载器**
1111

12-
# 用途
13-
`elf_loader`能够加载各种elf文件,并留下了扩展功能的接口。它能够被使用在以下地方:
14-
* 在操作系统内核中使用它作为elf文件的加载器
15-
* 使用它实现Rust版本的动态链接器
16-
* 在嵌入式设备上使用它加载elf动态库
12+
`elf_loader` 能够从内存或文件加载各种形式的ELF文件,并提供运行时高效链接(包括静态链接与动态链接)。无论您是在开发操作系统内核、嵌入式系统,还是需要动态加载ELF库的应用程序,`elf_loader` 都能提供卓越的性能和灵活性。
1713

18-
# 优势
19-
### ✨ 可以在 `no_std` 环境中工作 ✨
20-
`elf_loader`不依赖Rust `std`,也不强制依赖`libc`和操作系统,因此它可以在内核和嵌入式设备等`no_std`环境中使用。
14+
[文档](https://docs.rs/elf_loader/) | [示例](https://github.com/weizhiao/rust-elfloader/tree/main/examples)
2115

22-
### ✨ 可以在Windows上加载elf动态库 ✨
23-
详细内容可以看[windows-elf-loader](https://github.com/weizhiao/rust-elfloader/tree/main/crates/windows-elf-loader)
16+
---
2417

25-
### ✨ 体积小 ✨
26-
`elf_loader`的体积非常小。基于`elf_loader`实现的[mini-loader](https://github.com/weizhiao/rust-elfloader/tree/main/crates/mini-loader)编译后的二进制文件大小仅为**26K**。下面是使用`bloat`工具分析二进制文件得到的结果:
27-
```shell
28-
cargo bloat --crates --release --target=x86_64-unknown-none -Zbuild-std=core,alloc,panic_abort -Zbuild-std-features=panic_immediate_abort,optimize_for_size
29-
Finished `release` profile [optimized] target(s) in 0.28s
30-
Analyzing target/x86_64-unknown-none/release/mini-loader
31-
32-
File .text Size Crate
33-
23.1% 47.9% 5.9KiB elf_loader
34-
9.1% 18.9% 2.3KiB alloc
35-
7.1% 14.8% 1.8KiB core
36-
3.7% 7.7% 974B [Unknown]
37-
3.2% 6.7% 854B linked_list_allocator
38-
1.5% 3.0% 383B compiler_builtins
39-
0.4% 0.8% 105B __rustc
40-
48.2% 100.0% 12.4KiB .text section size, the file size is 25.7KiB
41-
42-
Note: numbers above are a result of guesswork. They are not 100% correct and never will be.
43-
```
18+
## 🎯 核心应用场景
19+
20+
- **操作系统开发** - 作为内核中的ELF文件加载器
21+
- **动态链接器实现** - 构建Rust版本的动态链接器
22+
- **嵌入式系统** - 在资源受限设备上加载ELF动态库
23+
- **JIT编译系统** - 作为即时编译器的底层链接器
24+
- **跨平台开发** - 在Windows上加载ELF动态库(详见 [windows-elf-loader](https://github.com/weizhiao/rust-elfloader/tree/main/crates/windows-elf-loader)
25+
26+
---
27+
28+
## ✨ 卓越特性
29+
30+
### 🚀 极致性能
31+
汲取 `musl``glibc``ld.so` 的实现精华,结合Rust的零成本抽象,提供接近原生的性能表现:
4432

45-
### ✨ 速度快 ✨
46-
本库吸取`musl``glibc``ld.so`实现的优点,并充分利用了Rust的一些特性(比如静态分发),可以生成性能出色的代码。
47-
下面是性能测试的结果,你可以在Github Actions中的`bench` job中查看它:
4833
```shell
49-
elf_loader:new time: [36.333 µs 36.478 µs 36.628 µs]
50-
Found 9 outliers among 100 measurements (9.00%)
51-
2 (2.00%) low mild
52-
2 (2.00%) high mild
53-
5 (5.00%) high severe
54-
Benchmarking libloading:new
55-
Benchmarking libloading:new: Warming up for 3.0000 s
56-
57-
Benchmarking libloading:new: Collecting 100 samples in estimated 5.2174 s (111k iterations)
58-
Benchmarking libloading:new: Analyzing
59-
libloading:new time: [46.348 µs 47.065 µs 47.774 µs]
60-
Found 4 outliers among 100 measurements (4.00%)
61-
3 (3.00%) high mild
62-
1 (1.00%) high severe
63-
64-
Benchmarking elf_loader:get
65-
Benchmarking elf_loader:get: Warming up for 3.0000 s
66-
Benchmarking elf_loader:get: Collecting 100 samples in estimated 5.0000 s (476M iterations)
67-
Benchmarking elf_loader:get: Analyzing
68-
elf_loader:get time: [10.459 ns 10.477 ns 10.498 ns]
69-
Found 1 outliers among 100 measurements (1.00%)
70-
1 (1.00%) high severe
71-
72-
Benchmarking libloading:get
73-
Benchmarking libloading:get: Warming up for 3.0000 s
74-
Benchmarking libloading:get: Collecting 100 samples in estimated 5.0002 s (54M iterations)
75-
Benchmarking libloading:get: Analyzing
76-
libloading:get time: [93.226 ns 93.369 ns 93.538 ns]
77-
Found 11 outliers among 100 measurements (11.00%)
78-
7 (7.00%) high mild
79-
4 (4.00%) high severe
34+
# 性能基准测试对比
35+
elf_loader:new 36.478 µs
36+
libloading:new 47.065 µs
37+
38+
elf_loader:get 10.477 ns
39+
libloading:get 93.369 ns
8040
```
81-
需要注意的是elf_loader并不是一个动态链接器,它并不能自动解析动态库的依赖,不过它可以作为动态链接器的底层使用。
8241

83-
### ✨ 非常容易移植,具有良好的可扩展性 ✨
84-
如果你想要移植`elf_loader`,你只需为你的平台实现 `Mmap``ElfObject` trait。在实现`Mmap` trait时可以参考`elf_loader`提供的默认实现:[os](https://github.com/weizhiao/rust-elfloader/tree/main/src/os)
85-
此外你可以使用本库提供的`hook`函数来拓展`elf_loader`的功能实现其他任何你想要的功能,在使用`hook`函数时可以参考`dlopen-rs`里的:[hook](https://github.com/weizhiao/rust-dlopen/blob/main/src/loader.rs)
42+
### 📦 超轻量级
43+
核心实现极其精简,基于 `elf_loader` 构建的 [mini-loader](https://github.com/weizhiao/rust-elfloader/tree/main/crates/mini-loader) 编译后仅 **34KB**
44+
45+
### 🔧 无标准库依赖
46+
完全支持 `no_std` 环境,不强制依赖 `libc` 或操作系统,可在内核和嵌入式设备中无缝使用。
8647

87-
### ✨ 提供异步接口 ✨
88-
`elf_loader`提供了加载elf文件的异步接口,这使得它在某些并发加载elf文件的场景下有更高的性能上限。不过你需要根据自己的应用场景实现 `Mmap``ElfObjectAsync` trait。比如不使用mmap来直接映射elf文件,转而使用mmap+文件读取的方式(mmap创建内存空间再通过文件读取将elf文件的内容读取到mmap创建的空间中)来加载elf文件,这样就能充分利用异步接口带来的优势。
48+
### 🛡️ 编译期安全保障
49+
利用Rust的生命周期机制,在编译期检查ELF依赖关系,防止悬垂指针和use-after-free错误:
8950

90-
### ✨ 编译期检查 ✨
91-
利用Rust的生命周期机制,在编译期检查elf文件的依赖库是否被提前销毁,大大提高了安全性。
92-
比如说有三个被`elf_loader`加载的动态库`a`,`b`,`c`,其中`c`依赖`b``b`依赖`a`,如果`a``b`中的任意一个在`c` drop之前被drop了,那么将不会程序通过编译。(你可以在[examples/relocate](https://github.com/weizhiao/rust-elfloader/blob/main/examples/relocate_dylib.rs)中验证这一点)
51+
```rust
52+
// 如果依赖库在之前被销毁,编译将失败!
53+
let liba = load_dylib!("liba.so")?;
54+
let libb = load_dylib!("libb.so")?; // 依赖 liba
55+
// liba 在 libb 之前被销毁会导致编译错误
56+
```
9357

94-
### ✨ 延迟绑定 ✨
95-
`elf_loader`支持延迟绑定,这意味着当一个符号被解析时,它不会被立即解析,而是会在第一次被调用时才被解析。
58+
### 🔄 高级功能支持
59+
- **延迟绑定** - 符号在首次调用时解析,提升启动性能
60+
- **RELR重定位** - 支持现代相对重定位格式,减少内存占用
61+
- **异步接口** - 为高并发场景提供异步加载能力
62+
- **高度可扩展** - 通过trait系统轻松移植到新平台
9663

97-
### ✨ 支持RELR相对重定位格式 ✨
98-
`elf_loader`支持RELR相对重定位格式,有关RELR的详细内容可以看这里:[Relative relocations and RELR](https://maskray.me/blog/2021-10-31-relative-relocations-and-relr)
64+
---
9965

66+
## 🏗️ 架构设计
10067

101-
# Feature
68+
### 易于移植
69+
只需为您的平台实现 `Mmap``ElfObject` trait即可完成移植。参考我们的 [默认实现](https://github.com/weizhiao/rust-elfloader/tree/main/src/os) 快速上手。
10270

103-
| 特性 | 描述 |
104-
| --------------- | ------------------------------------ |
105-
| use-syscall | 使用`linux syscalls`作为后端 |
106-
| version | 在解析符号时使用符号的版本信息 |
107-
| log | 启用日志 |
108-
| rel | 将rel作为重定位条目的格式 |
109-
| portable-atomic | 支持没有native指针大小原子操作的目标 |
71+
### 钩子函数扩展
72+
通过hook函数扩展功能,实现自定义加载逻辑,详见 [dlopen-rs hook示例](https://github.com/weizhiao/rust-dlopen/blob/main/src/loader.rs)
11073

111-
在没有操作系统的情况下请关闭`use-syscall`这个feature。
74+
---
11275

113-
# 指令集支持
76+
## 📋 平台支持
11477

115-
| 指令集 | 支持 | 延迟绑定 | 测试 |
116-
| ----------- | ---- | -------- | ---------- |
117-
| x86_64 ||| ✅(CI) |
118-
| aarch64 ||| ✅(CI) |
119-
| riscv64 ||| ✅(CI) |
120-
| riscv32 ||| ✅(Manual) |
121-
| loongarch64 ||| ✅(CI) |
122-
| x86 ||| ✅(CI) |
123-
| arm ||| ✅(CI) |
78+
| 指令集 | 支持状态 | 延迟绑定 | 测试覆盖 |
79+
| ------------ | -------- | -------- | -------- |
80+
| x86_64 ||| CI |
81+
| AArch64 ||| CI |
82+
| RISC-V 64/32 ||| CI/手动 |
83+
| LoongArch64 ||| CI |
84+
| x86 ||| CI |
85+
| ARM ||| CI |
12486

125-
# 示例
126-
## 加载一个简单的动态库
87+
---
88+
89+
## 🚀 快速开始
90+
91+
### 添加依赖
92+
```toml
93+
[dependencies]
94+
elf_loader = "0.1"
95+
```
12796

97+
### 基本用法
12898
```rust
12999
use elf_loader::load_dylib;
130100
use std::collections::HashMap;
131101

132-
fn main() {
133-
fn print(s: &str) {
134-
println!("{}", s);
135-
}
136-
137-
// Symbols required by dynamic library liba.so
138-
let mut map = HashMap::new();
139-
map.insert("print", print as _);
140-
let pre_find = |name: &str| -> Option<*const ()> { map.get(name).copied() };
141-
// Load and relocate dynamic library liba.so
142-
let liba = load_dylib!("target/liba.so")
143-
.unwrap()
144-
.easy_relocate([].iter(), &pre_find)
145-
.unwrap();
146-
// Call function a in liba.so
147-
let f = unsafe { liba.get::<fn() -> i32>("a").unwrap() };
148-
println!("{}", f());
102+
fn main() -> Result<(), Box<dyn std::error::Error>> {
103+
// 提供动态库所需的符号
104+
let mut symbols = HashMap::new();
105+
symbols.insert("print", print as *const ());
106+
107+
let pre_find = |name: &str| -> Option<*const ()> {
108+
symbols.get(name).copied()
109+
};
110+
111+
// 加载并重定位动态库
112+
let lib = load_dylib!("target/libexample.so")?
113+
.easy_relocate([].iter(), &pre_find)?;
114+
115+
// 调用库中的函数
116+
let func = unsafe { lib.get::<fn() -> i32>("example_function")? };
117+
println!("结果: {}", func());
118+
119+
Ok(())
120+
}
121+
122+
fn print(s: &str) {
123+
println!("{}", s);
149124
}
150125
```
151126

152-
# 最低编译器版本支持
153-
Rust 1.88.0及以上
127+
---
128+
129+
## ⚙️ 特性开关
130+
131+
| 特性 | 描述 |
132+
| ----------------- | ------------------------- |
133+
| `use-syscall` | 使用Linux系统调用作为后端 |
134+
| `version` | 在符号解析时使用版本信息 |
135+
| `log` | 启用日志输出 |
136+
| `rel` | 使用REL格式的重定位条目 |
137+
| `portable-atomic` | 支持无原生原子操作的目标 |
138+
139+
**注意**: 在无操作系统的环境中请禁用 `use-syscall` 特性。
140+
141+
---
142+
143+
## 💡 系统要求
144+
145+
- **最低Rust版本**: 1.88.0+
146+
- **支持平台**: 所有主要架构(详见平台支持表格)
147+
148+
---
149+
150+
## 🤝 贡献与支持
151+
152+
我们热烈欢迎社区贡献!无论是改进核心功能、增加示例、完善文档还是修复问题,您的参与都将受到高度赞赏。
153+
154+
- **问题反馈**: [GitHub Issues](https://github.com/weizhiao/elf_loader/issues)
155+
- **功能请求**: 欢迎提出新功能建议
156+
- **代码贡献**: 提交Pull Request
157+
158+
如果这个项目对您有帮助,请给我们一个 ⭐ 以表示支持!
159+
160+
---
154161

155-
# 补充
156-
如果你在使用时遇到任何问题,都可以在github上提出issue,此外十分欢迎任何对elf加载器感兴趣的朋友贡献代码(改进elf_loader本身,增加样例,修改文档中存在的问题都可以)。如果觉得elf_loader对你有帮助的话不妨点个star吧。😊
162+
**立即开始使用 `elf_loader`,为您的项目带来高效的ELF加载能力!** 🎉

0 commit comments

Comments
 (0)