#elf #loader #async #unix

no-std elf_loader

A pure-rust library for loading ELF dynamic libraries from both memory and files

8 breaking releases

new 0.9.0 Feb 20, 2025
0.7.0 Feb 16, 2025
0.3.0 Dec 9, 2024
0.1.0 Nov 17, 2024

#155 in Operating systems

Download history 83/week @ 2024-11-12 40/week @ 2024-11-19 9/week @ 2024-11-26 220/week @ 2024-12-03 107/week @ 2024-12-10 5/week @ 2024-12-17 11/week @ 2025-01-07 2/week @ 2025-01-14 109/week @ 2025-01-21 75/week @ 2025-01-28 75/week @ 2025-02-04 214/week @ 2025-02-11

473 downloads per month
Used in 2 crates

MIT/Apache

120KB
3K SLoC

license

elf_loader

English | 中文

The elf_loader crate provides an async loading interface for loading ELF dynamic libraries from both memory and files.

Documentation

Capabilities

✨ Works in no_std environments ✨

This crate provides an elf loading interface which does not use any std features, so it can be used in no_std environments such as kernels and embedded device.

✨ Fast speed ✨

This crate makes full use of some features of rust and can generate code with excellent performance. The elf_loader is designed to achieve faster performance than libloading, specifically aiming to surpass the speed of the dynamic linker/loader (ld.so).

✨ Very easy to port and has good extensibility ✨

If you want to port this crate, you only need to implement the Mmap trait for your platform. And you can use hook functions to implement additional functionality based on this crate.

✨ Tiny library with few dependencies ✨

With minimal features, this crate only depends on the elf, cfg-if, and bitflags crates.

✨ Compile-time checking ✨

Utilize Rust's lifetime mechanism to check at compile time whether the dependent libraries of a dynamic library are deallocated prematurely, and whether the dynamic library to which a symbol belongs has been deallocated.
For example, there are three dynamic libraries loaded by elf_loader: a, b, and c. Library c depends on b, and b depends on a. If either a or b is dropped before c is dropped, the program will not pass compilation. (You can try this in the examples/relocate.)

Usage

It implements the general steps for loading ELF files and leaves extension interfaces, allowing users to implement their own customized loaders.

Feature

Feature Description
fs Enable support for filesystems
use-libc Use libc as the backend, otherwise directly use linux syscalls
mmap Use the default implementation on platforms with mmap when loading ELF files
version Use the version information of symbols when resolving them.

Example

Load a simple dynamic library

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);
    }

	// Symbols required by dynamic library 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() };
	// Load dynamic library liba.so 
	let loader = Loader::<MmapImpl>::new();
    let liba = loader
        .easy_load_dylib(ElfFile::from_path("target/liba.so").unwrap())
        .unwrap();
	// Relocate symbols in liba.so
    let a = liba.easy_relocate([].iter(), &pre_find).unwrap();
	// Call function a in liba.so
    let f = unsafe { a.get::<fn() -> i32>("a").unwrap() };
    f();
}

mini-loader

This repository provides an example of a mini-loader implemented using elf_loader. The miniloader can load PIE files and currently only supports x86_64 .

Load ls:

$ cargo build --release -p mini-loader --target=x86_64-unknown-none
$ ./mini-loader /bin/ls

It should be noted that mini-loader must be compiled with the release parameter.

dlopen-rs

dlopen-rs is also implemented based on the elf_loader library. It implements the functionality of dlopen, allowing dynamic libraries to be opened at runtime. And it has implemented hot reloading.

TODO

  • Support more CPU instruction sets (currently only supports AArch64, Riscv64, X86-64).
  • Improve support for DT_FLAGS flag bits.
  • Improve comments and documentation.
  • Add examples (e.g., an example of loading dynamic libraries using an asynchronous interface).
  • Add support for more instruction sets in the example mini-loader.
  • Add more performance tests and correctness tests.
  • Further optimize performance using portable simd.
  • Find a dynamic library suitable for testing performance (and make sure it's large enough).
    ...

Supplement

If you encounter any issues during use, feel free to raise them on GitHub. We warmly welcome everyone to contribute code to help improve the functionality of elf_loader. 😊

Dependencies

~510–770KB
~13K SLoC