rustld 0.1.55

A modern ELF loader (static & dynamic linker + compatible glibc & musl) written in Rust
Documentation
//! Rustld is a modern (and working) ELF x86_64 & aarch64 loader (static & dynamic linker + compatible glibc & musl) written in Rust
//! You can run (almost) **everything** with it.
//!
//! ## Rust SDK:
//! ```ignore
//! // With syscall trampoline obfuscation:
//! rustld::ElfLoader::new_with_obf(true).execute_from_bytes(target_bytes, target_argv, None, None, false);
//! // Without obfuscation:
//! rustld::ElfLoader::new().execute_from_bytes(target_bytes, target_argv, None, None, false);
//! // Optional explicit entrypoint:
//! rustld::ElfLoader::new_with_obf(true).execute_from_bytes_with_entry(
//!     target_bytes, target_argv,
//!     Some("hello"), // or None
//!     None,          // or Some(0x399)
//!     None, None, false,
//! );
//! ```
//!
//! ## Basic usage example:
//! ```no_run
//! use std::{ffi::OsStr, os::fd::AsRawFd, os::unix::ffi::OsStrExt};
//! use rustld::ElfLoader;
//!
//! fn main() {
//!     unsafe {
//!         let argv_storage = collect_process_arguments();
//!         if argv_storage.len() < 2 {
//!             eprintln!(
//!                 "Usage: rustld [--entry-symbol <name> | --entry-addr <addr>] <program> [args...]"
//!             );
//!             std::process::exit(1);
//!         }
//!         let mut args = argv_storage.into_iter();
//!         let _self_name = args.next();
//!         let mut entry_symbol: Option<String> = None;
//!         let mut entry_address: Option<usize> = None;
//!         let mut target_argv: Vec<String> = Vec::new();
//!
//!         while let Some(arg) = args.next() {
//!             if arg == "--entry-symbol" {
//!                 let Some(symbol) = args.next() else {
//!                     eprintln!("Error: --entry-symbol expects a value");
//!                     std::process::exit(1);
//!                 };
//!                 entry_symbol = Some(symbol);
//!                 continue;
//!             }
//!             if arg == "--entry-addr" {
//!                 let Some(raw_addr) = args.next() else {
//!                     eprintln!("Error: --entry-addr expects a value");
//!                     std::process::exit(1);
//!                 };
//!                 let parsed = parse_address(&raw_addr);
//!                 entry_address = Some(parsed);
//!                 continue;
//!             }
//!             target_argv.push(arg);
//!             target_argv.extend(args);
//!             break;
//!         }
//!
//!         if target_argv.is_empty() {
//!             eprintln!("Error: missing target program path");
//!             std::process::exit(1);
//!         }
//!         if entry_symbol.is_some() && entry_address.is_some() {
//!             eprintln!("Error: --entry-symbol and --entry-addr are mutually exclusive");
//!             std::process::exit(1);
//!         }
//!
//!         let target_bytes = map_file_readonly(OsStr::from_bytes(target_argv[0].as_bytes()));
//!
//!         #[cfg(debug_assertions)]
//!         eprintln!("Executing target binary: {}", target_argv[0]);
//!         if entry_symbol.is_some() || entry_address.is_some() {
//!             ElfLoader::new_with_obf(true).execute_from_bytes_with_entry(
//!                 target_bytes,
//!                 target_argv,
//!                 entry_symbol.as_deref(),
//!                 entry_address,
//!                 None,
//!                 None,
//!                 false,
//!             );
//!         } else {
//!             ElfLoader::new_with_obf(true).execute_from_bytes(target_bytes, target_argv, None, None, false);
//!         }
//!     }
//! }
//!
//! fn parse_address(raw: &str) -> usize {
//!     let (digits, radix) = if let Some(hex) = raw.strip_prefix("0x") {
//!         (hex, 16)
//!     } else if let Some(hex) = raw.strip_prefix("0X") {
//!         (hex, 16)
//!     } else {
//!         (raw, 10)
//!     };
//!
//!     match usize::from_str_radix(digits, radix) {
//!         Ok(value) => value,
//!         Err(_) => {
//!             eprintln!("Error: invalid entry address: {raw}");
//!             std::process::exit(1);
//!         }
//!     }
//! }
//!
//! fn collect_process_arguments() -> Vec<String> {
//!     std::env::args_os()
//!         .map(|arg| arg.to_string_lossy().into_owned())
//!         .collect()
//! }
//!
//! unsafe fn map_file_readonly(path: &OsStr) -> &'static [u8] {
//!     use rustld::syscall::mmap::{self, MAP_PRIVATE, PROT_READ};
//!
//!     let file = match std::fs::File::open(path) {
//!         Ok(file) => file,
//!         Err(error) => {
//!             eprintln!("Error: could not open target binary: {error}");
//!             std::process::exit(1);
//!         }
//!     };
//!
//!     let length = match file.metadata() {
//!         Ok(metadata) => metadata.len() as usize,
//!         Err(error) => {
//!             eprintln!("Error: could not stat target binary: {error}");
//!             std::process::exit(1);
//!         }
//!     };
//!
//!     if length == 0 {
//!         eprintln!("Error: target binary is empty");
//!         std::process::exit(1);
//!     }
//!
//!     let mapped = mmap::mmap(
//!         core::ptr::null_mut(),
//!         length,
//!         PROT_READ,
//!         MAP_PRIVATE,
//!         file.as_raw_fd() as isize,
//!         0,
//!     );
//!     let mapped_addr = mapped as isize;
//!     if mapped_addr < 0 {
//!         eprintln!("Error: could not map target binary");
//!         std::process::exit(1);
//!     }
//!
//!     core::mem::drop(file);
//!     core::slice::from_raw_parts(mapped as *const u8, length)
//! }
//! ```
//!

#![cfg_attr(docsrs, feature(doc_cfg))]
#![feature(impl_trait_in_assoc_type)]
#![feature(c_variadic)]
#![feature(thread_local)]
#![allow(dead_code)]

pub(crate) mod arch;
#[cfg_attr(target_arch = "x86_64", path = "arch/x86_64/syscall/mod.rs")]
#[cfg_attr(target_arch = "aarch64", path = "arch/aarch64/syscall/mod.rs")]
pub mod syscall;

pub mod runtime_loader;

mod c_api;
mod elf;
mod global_allocator;
mod io_macros;
mod ld_stubs;
mod libc;
mod linking;
mod page_size;
mod shared_object;
mod start;
mod tls;
mod utils;

pub use runtime_loader::{host_environment_pointer, ElfLoader};
pub use start::auxiliary_vector::{AuxiliaryVectorItem, AuxiliaryVectorIter};