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^

相关推荐
Doro再努力1 小时前
Vim 快速上手实操手册:从入门到生产环境实战
linux·编辑器·vim
wypywyp1 小时前
8. ubuntu 虚拟机 linux 服务器 TCP/IP 概念辨析
linux·服务器·ubuntu
Doro再努力2 小时前
【Linux操作系统10】Makefile深度解析:从依赖推导到有效编译
android·linux·运维·服务器·编辑器·vim
senijusene2 小时前
Linux软件编程:IO编程,标准IO(1)
linux·运维·服务器
忧郁的橙子.2 小时前
02-本地部署Ollama、Python
linux·运维·服务器
醇氧2 小时前
【linux】查看发行版信息
linux·运维·服务器
No8g攻城狮3 小时前
【Linux】Windows11 安装 WSL2 并运行 Ubuntu 22.04 详细操作步骤
linux·运维·ubuntu
XiaoFan0123 小时前
免密批量抓取日志并集中输出
java·linux·服务器
souyuanzhanvip3 小时前
ServerBox v1.0.1316 跨平台 Linux 服务器管理工具
linux·运维·服务器
HalvmånEver4 小时前
Linux:线程互斥
java·linux·运维