From de9e8a6177d3adb134f1d5215baefec114765538 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 17 Dec 2024 01:07:17 +1100 Subject: [PATCH] feat(ld.so): config Currently supported options are `LD_DEBUG` and `LD_LIBRARY_PATH`. Signed-off-by: Anhad Singh --- src/ld_so/linker.rs | 91 ++++++++++++++++++++++++++++++++++++++------- src/ld_so/start.rs | 10 ++++- src/start.rs | 2 +- 3 files changed, 87 insertions(+), 16 deletions(-) diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index 5e95514da1..947b09aa10 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -68,8 +68,55 @@ impl Symbol { } } +bitflags::bitflags! { + #[derive(Debug, Default)] + pub struct DebugFlags: u32 { + /// Displays what objects and where they are being loaded. + const BASE_ADDRESS = 1 << 1; + /// Displays library search paths. + const SEARCH = 1 << 2; + } +} + +#[derive(Default)] +pub struct Config { + debug_flags: DebugFlags, + library_path: Option, +} + +impl Config { + pub fn from_env(env: &BTreeMap) -> Self { + let debug_flags = env + .get("LD_DEBUG") + .map(|value| { + let mut flags = DebugFlags::empty(); + for opt in value.split(',') { + flags |= match opt { + "baseaddr" => DebugFlags::BASE_ADDRESS, + "search" => DebugFlags::SEARCH, + _ => { + eprintln!("[ld.so]: unknown debug flag '{}'", opt); + DebugFlags::empty() + } + }; + } + + flags + }) + .unwrap_or(DebugFlags::empty()); + + let library_path = env.get("LD_LIBRARY_PATH").cloned(); + + Self { + debug_flags, + library_path, + } + } +} + pub struct Linker { - ld_library_path: Option, + config: Config, + next_object_id: usize, next_tls_module_id: usize, tls_size: usize, @@ -81,9 +128,9 @@ pub struct Linker { const root_id: usize = 1; impl Linker { - pub fn new(ld_library_path: Option) -> Self { + pub fn new(config: Config) -> Self { Self { - ld_library_path, + config, next_object_id: root_id, next_tls_module_id: 1, tls_size: 0, @@ -323,7 +370,7 @@ impl Linker { return Ok(()); } - let path = Linker::search_object(name, &self.ld_library_path, parent_runpath)?; + let path = self.search_object(name, parent_runpath)?; let data = Linker::read_file(&path)?; let (obj, tcb_master) = DSO::new( &path, @@ -334,11 +381,15 @@ impl Linker { self.next_tls_module_id, self.tls_size, )?; - trace!( - "[ldso] loading object: {} at {:#x}", - name, - obj.mmap.as_ptr() as usize - ); + + if self.config.debug_flags.contains(DebugFlags::BASE_ADDRESS) { + eprintln!( + "[ld.so]: loading object: {} at {:#x}", + name, + obj.mmap.as_ptr() as usize + ); + } + new_objects.push(obj); objects_data.push(data); @@ -373,31 +424,45 @@ impl Linker { } fn search_object( + &self, name: &str, - ld_library_path: &Option, parent_runpath: &Option, ) -> Result { + let debug = self.config.debug_flags.contains(DebugFlags::SEARCH); + if debug { + eprintln!("[ld.so]: looking for '{}'", name); + } + let mut full_path = name.to_string(); if accessible(&full_path, F_OK).is_ok() { + if debug { + eprintln!("[ld.so]: found at '{}'!", full_path); + } return Ok(full_path); } else { let mut search_paths = Vec::new(); if let Some(runpath) = parent_runpath { search_paths.extend(runpath.split(PATH_SEP)); } - if let Some(ld_path) = ld_library_path { + if let Some(ld_path) = self.config.library_path.as_ref() { search_paths.extend(ld_path.split(PATH_SEP)); } search_paths.push("/lib"); for part in search_paths.iter() { full_path = format!("{}/{}", part, name); - trace!("trying path {}", full_path); + if debug { + eprintln!("[ld.so]: trying path '{}'", full_path); + } if accessible(&full_path, F_OK).is_ok() { + if debug { + eprintln!("[ld.so]: found at '{}'!", full_path); + } return Ok(full_path); } } } - return Err(Error::Malformed(format!("failed to locate '{}'", name))); + + Err(Error::Malformed(format!("failed to locate '{}'", name))) } fn read_file(path: &str) -> Result> { diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs index 5c695cf39e..b3b1d181ee 100644 --- a/src/ld_so/start.rs +++ b/src/ld_so/start.rs @@ -19,7 +19,13 @@ use crate::{ ALLOCATOR, }; -use super::{access::accessible, debug::_r_debug, linker::Linker, tcb::Tcb, PATH_SEP}; +use super::{ + access::accessible, + debug::_r_debug, + linker::{Config, Linker}, + tcb::Tcb, + PATH_SEP, +}; use crate::header::sys_auxv::{AT_ENTRY, AT_PHDR}; use goblin::elf::header::header64::SIZEOF_EHDR; @@ -248,7 +254,7 @@ pub extern "C" fn relibc_ld_so_start( } base }; - let mut linker = Linker::new(ld_library_path); + let mut linker = Linker::new(Config::from_env(&envs)); let entry = match linker.load_program(&path, base_addr) { Ok(entry) => entry, Err(err) => { diff --git a/src/start.rs b/src/start.rs index 754a7bbe07..3d56738632 100644 --- a/src/start.rs +++ b/src/start.rs @@ -155,7 +155,7 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { // Set linker pointer if necessary if tcb.linker_ptr.is_null() { //TODO: get ld path - let linker = Linker::new(None); + let linker = Linker::new(ld_so::linker::Config::default()); //TODO: load root object tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker))); }