#elf #loader #async #unix #object-file

no-std elf_loader

A pure-rust library for loading all ELF format files 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

#257 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

140KB
3.5K SLoC

license elf_loader on docs.rs

elf_loader

English | 中文

elf_loader can load various forms of ELF files from memory or files, including Executable file, Shared object file, and Position-Independent Executable file.

Documentation

Usage

elf_loader can load various ELF files and provides interfaces for extended functionality. It can be used in the following areas:

  • Use it as an ELF file loader in operating system kernels
  • Use it to implement a Rust version of the dynamic linker
  • Use it to load ELF dynamic libraries on embedded devices

Capabilities

✨ Works in no_std environments ✨

This library does not depend on Rust std, nor does it depend on libc (although you can enable it to use libc via a feature), so it can be used in no_std environments such as kernels and embedded devices.

✨ Fast speed ✨

This library draws on the strengths of musl and glibc's ld.so implementation and fully utilizes some features of Rust (such as static dispatch), allowing it to generate high-performance code. dlopen-rs based on elf_loader has better performance than libloading.

✨ Very easy to port and has good extensibility ✨

If you want to port elf_loader, you only need to implement the Mmap and ElfObject traits for your platform. When implementing the Mmap trait, you can refer to the default implementation provided by elf_loader: mmap. In addition, you can use the hook functions provided by this library to extend the functionality of elf_loader to implement any other features you want. When using the hook functions, you can refer to: hook in dlopen-rs.

✨ Tiny library with few dependencies ✨

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

✨ Provides asynchronous interfaces ✨

elf_loader provides asynchronous interfaces for loading ELF files, which can achieve higher performance in scenarios where ELF files are loaded concurrently.
However, you need to implement the Mmap and ElfObjectAsync traits according to your application scenario. For example, instead of using mmap to directly map ELF files, you can use a combination of mmap and file reading (mmap creates memory space, and then the content of the ELF file is read into the space created by mmap) to load ELF files, thus fully utilizing the advantages brought by the asynchronous interface.

✨ Compile-time checking ✨

Utilize Rust's lifetime mechanism to check at compile time whether the dependent libraries of a dynamic library are deallocated prematurely.
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.)

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

mini-loader is implemented based on the elf_loader library. mini-loader can load and execute elf files, and currently only supports x86_64.

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 support for more instruction sets in the example mini-loader.
  • Add more performance tests and correctness tests.
  • Further optimize performance using portable simd.
    ...

Supplement

You can report any issues you encounter while using this library on GitHub, and we warmly welcome everyone to submit code to improve the functionality of elf_loader. 😊

Dependencies

~510–780KB
~13K SLoC