From 459b8da27b511a2a2f0554fdfeddf6944015fbb2 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Sun, 29 Mar 2026 05:34:14 +0700 Subject: [PATCH] Implement ld_so cache backed by shm --- Cargo.toml | 3 +- src/ld_so/linker.rs | 123 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ff7819cbfb..deec6cb92e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -130,8 +130,9 @@ redox_protocols.workspace = true [features] # to enable trace level, take out this `no_trace` -default = ["check_against_libc_crate", "no_trace"] +default = ["check_against_libc_crate", "ld_so_cache", "no_trace"] check_against_libc_crate = ["__libc_only_for_layout_checks"] +ld_so_cache = [] no_trace = ["log/release_max_level_debug"] # for very verbose activity beyond trace level trace_tls = [] diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index cb85754ad0..a3e10b5a07 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -34,6 +34,10 @@ use crate::{ }, sync::rwlock::RwLock, }; + +#[cfg(feature = "ld_so_cache")] +use crate::header::sys_stat::stat; + #[cfg(not(target_arch = "x86"))] use crate::{ld_so::dso::resolve_sym, platform::types::c_uint}; @@ -97,7 +101,10 @@ impl MmapFile { let mut stat = crate::header::sys_stat::stat::default(); Sys::fstat(fd, Out::from_mut(&mut stat))?; - let size = stat.st_size as usize; + Self::from_fd(fd, stat.st_size as usize) + } + + fn from_fd(fd: i32, size: usize) -> core::result::Result { let ptr = unsafe { Sys::mmap( ptr::null_mut(), @@ -112,16 +119,37 @@ impl MmapFile { Ok(Self { fd, ptr, size }) } + fn anonymous(size: usize) -> core::result::Result { + let ptr = unsafe { + Sys::mmap( + ptr::null_mut(), + size, + sys_mman::PROT_READ | sys_mman::PROT_WRITE, + sys_mman::MAP_PRIVATE | sys_mman::MAP_ANONYMOUS, + -1, + 0, + ) + }?; + + Ok(Self { fd: -1, ptr, size }) + } + fn data(&self) -> &[u8] { unsafe { core::slice::from_raw_parts(self.ptr.cast::(), self.size) } } + + fn as_mut_slice(&self) -> &mut [u8] { + unsafe { core::slice::from_raw_parts_mut(self.ptr.cast::(), self.size) } + } } impl Drop for MmapFile { fn drop(&mut self) { unsafe { Sys::munmap(self.ptr, self.size).unwrap(); - Sys::close(self.fd).unwrap(); + if self.fd != -1 { + Sys::close(self.fd).unwrap(); + } } } } @@ -932,14 +960,93 @@ impl Linker { DlError::NotFound })?; - let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC; - let file = MmapFile::open(CStr::borrow(&path_c), flags).map_err(|err| { - if debug { - eprintln!("[ld.so]: failed to open '{}': {}", path, err) + // TODO: Caches may silently fail within multiple users (try to leverage capabilities?) + // TODO: No way to specify weak cache or pruning the cache manually + + #[cfg(feature = "ld_so_cache")] + let file = { + let mut mtime_sec = 0; + let mut mtime_nsec = 0; + let mut source_size = 0; + + let src_fd = Sys::open(CStr::borrow(&path_c), fcntl::O_RDONLY | fcntl::O_CLOEXEC, 0) + .map_err(|err| { + if debug { + eprintln!("[ld.so]: failed to open '{}': {}", path, err) + } + DlError::NotFound + })?; + let mut st = stat::default(); + if Sys::fstat(src_fd, Out::from_mut(&mut st)).is_ok() { + mtime_sec = st.st_mtim.tv_sec; + mtime_nsec = st.st_mtim.tv_nsec; + source_size = st.st_size as usize; } - DlError::NotFound - })?; + let shm_path_str = format!( + "/scheme/shm/ld.so.cache.{}.{}.{}\0", + path.replace('/', "_"), + mtime_sec, + mtime_nsec + ); + let shm_path = unsafe { CStr::from_bytes_with_nul_unchecked(shm_path_str.as_bytes()) }; + + let mut shm_exists = false; + + if let Ok(shm_fd) = Sys::open(shm_path, fcntl::O_RDONLY, 0) { + let mut shm_stat = stat::default(); + if Sys::fstat(shm_fd, Out::from_mut(&mut shm_stat)).is_ok() { + shm_exists = true; + if shm_stat.st_size > 0 { + if let Ok(mmap_file) = MmapFile::anonymous(source_size) { + let mut offset = 0; + let buf = mmap_file.as_mut_slice(); + while offset < source_size { + match Sys::read(shm_fd, &mut buf[offset..]) { + Ok(0) | Err(_) => break, + Ok(n) => offset += n, + } + } + let _ = Sys::close(shm_fd); + return Ok(mmap_file); + } + let _ = Sys::close(shm_fd); + } + } + let _ = Sys::close(shm_fd); + } + + let file = MmapFile::from_fd(src_fd, source_size).map_err(|err| { + if debug { + eprintln!("[ld.so]: failed to map '{}': {}", path, err) + } + DlError::NotFound + })?; + + if !shm_exists { + let _ = Sys::open(shm_path, fcntl::O_CREAT | fcntl::O_RDWR, 0o600) + .map(|fd| Sys::close(fd)); + } else { + if let Ok(shm_fd) = Sys::open(shm_path, fcntl::O_RDWR, 0o600) { + let _ = Sys::ftruncate(shm_fd, source_size as i64); + let _ = Sys::write(shm_fd, file.data()); + let _ = Sys::close(shm_fd); + } + } + + file + }; + #[cfg(not(feature = "ld_so_cache"))] + let file = { + let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC; + MmapFile::open(CStr::borrow(&path_c), flags).map_err(|err| { + if debug { + eprintln!("[ld.so]: failed to open '{}': {}", path, err) + } + + DlError::NotFound + })? + }; Ok(file) }