elf_loader:一个使用Rust编写的ELF加载器

本文介绍一个使用Rust实现的ELF加载器。

下面是elf_loader的仓库链接:

github:

https://github.com/weizhiao/elf_loaderhttps://github.com/weizhiao/elf_loader

crates.io

https://crates.io/crates/elf_loaderhttps://crates.io/crates/elf_loader

1 它能做什么?

elf_loader能够从内存、文件加载各种形式的elf文件,包括Executable file、Shared object file和Position-Independent Executable file。

PS:后面这两个其实是一类格式,Position-Independent Executable file其实就是带有入口的Shared object file,即可以执行的Shared object file。

鉴于此,它能够被使用在以下地方:

1 在操作系统内核中使用它作为elf文件的加载器

2 使用它实现Rust版本的动态链接器。PS:我自己也实现了一个https://github.com/weizhiao/dlopen-rs

3 在嵌入式设备上使用它加载elf动态库

2 优势

✨ 可以在 no_std环境中工作✨

elf_loader不依赖Rust std,也不强制依赖libc和操作系统,因此可以在内核和嵌入式设备等no_std环境中使用。

✨速度快✨

elf_loader吸取了musl和glibc里ld.so实现的优点,并充分利用了Rust的一些特性(比如静态分发),可以生成性能出色的代码。基于elf_loader实现的动态链接器dlopen-rs性能比libloading(ld.so)更好。

✨非常容易移植,具有良好的可扩展性✨

如果你想要移植elf_loader,你只需为你的平台实现 Mmap和ElfObject trait。在实现Mmap trait时可以参考elf_loader提供的默认实现:

elf_loader/src/mmap at main · weizhiao/elf_loader

此外你可以使用elf_loader提供的hook函数来拓展elf_loader的功能,实现其他任何你想要的功能,在使用hook函数时可以参考dlopen-rs里的实现:https://github.com/weizhiao/dlopen-rs/blob/main/src/loader/mod.rs

✨提供异步接口✨

elf_loader提供了加载elf文件的异步接口,这使得它在某些并发加载elf文件的场景下有更高的性能上限。不过你需要根据自己的应用场景实现 Mmap和ElfObjectAsync trait。比如不使用mmap来直接映射elf文件,转而使用mmap+文件读取的方式(mmap创建内存空间再通过文件读取将elf文件的内容读取到mmap创建的空间中)来加载elf文件,这样就能充分利用异步接口带来的优势。

✨编译期检查✨

elf_loader利用Rust的生命周期机制,在编译期检查elf文件的依赖库是否被提前销毁,大大提高了安全性。 比如说有三个被elf_loader加载的动态库a,b,c,其中c依赖b,b依赖a,如果a,b中的任意一个在c drop之前被drop了,那么将不会程序通过编译。你可以在examples/relocate中验证这一点:elf_loader/examples/relocate.rs at main · weizhiao/elf_loader · GitHub

3 示例

加载一个简单的动态库:

rust 复制代码
use elf_loader::{Loader, mmap::MmapImpl, object::ElfFile};
use elf_loader::{Loader, mmap::MmapImpl, object::ElfFile};
use std::{collections::HashMap, ptr::null};

fn main() {
    fn print(s: &str) {
        println!("{}", s);
    }

    // liba.so依赖的符号
    let mut map = HashMap::new();
    map.insert("__gmon_start__", null());
    map.insert("__cxa_finalize", null());
    map.insert("_ITM_registerTMCloneTable", null());
    map.insert("_ITM_deregisterTMCloneTable", null());
    map.insert("print", print as _);
    let pre_find = |name: &str| -> Option<*const ()> { map.get(name).copied() };
    // 加载动态库liba.so
    let mut loader = Loader::<MmapImpl>::new();
    let liba = loader
        .easy_load_dylib(ElfFile::from_path("target/liba.so").unwrap())
        .unwrap();
    // 重定位liba.so中的符号
    let a = liba.easy_relocate([].iter(), &pre_find).unwrap();
    // 调用liba.so中的函数a
    let f = unsafe { a.get::<fn() -> i32>("a").unwrap() };
    f();
}

4 补充

如果你在使用时遇到任何问题,都可以在本文的评论区或者github上提出问题,此外十分欢迎任何对elf加载器感兴趣的朋友贡献代码(改进elf_loader本身,增加样例,修改文档中存在的问题都可以)。如果觉得elf_loader对你有帮助的话不妨点个star。^v^

相关推荐
小灰灰搞电子6 小时前
Rust+Slint 实现动态消息提示框源码分享
开发语言·后端·rust
传奇开心果编程8 小时前
【Rust入门知识点学与练】第21课:Trait 进阶 Advanced Traits
开发语言·学习·rust
Johny_Zhao9 小时前
网络安全等级保护测评实施方案
linux·网络·人工智能·网络安全·信息安全·云计算·等保测评·系统运维·itsm
落羽的落羽10 小时前
【AI】快速理解AI应用的相关名词概念
linux·c++·人工智能·python·计算机网络·算法
刚入门的大一新生10 小时前
Linux-进程控制
linux·运维·服务器·c++
上火的金鱼妹10 小时前
K8S基础组件作用和关系整理
linux·运维·服务器·kubernetes
Vcaker10 小时前
Linux学习25-harbor私有仓库部署
linux·运维·学习
刃神太酷啦10 小时前
Redis 进阶核心:持久化 (RDB/AOF)、事务与主从复制全解析----《Hello Redis!》(5)
linux·c语言·数据库·c++·redis·缓存·bootstrap
编程的一拳超人10 小时前
DeepSeek Harness Linux/macOS/Windows 本地下载、启动与模型配置指南
linux·windows·macos·deepseek
时凌云.10 小时前
【2026最新】JDK 下载安装与环境配置全教程(Windows/Mac/Linux 三平台,零基础友好)
java·linux·macos