dlopen_rs/core_impl/
loader.rs1use crate::core_impl::register::global_find;
2use crate::core_impl::traits::AsFilename;
3use crate::core_impl::types::{ARGC, ARGV, ENVP, ExtraData, LinkMap};
4use crate::utils::debug::add_debug_link_map;
5use crate::utils::linker_script::get_linker_script_libs;
6use crate::{OpenFlags, Result, error::find_symbol_error};
7use alloc::{
8 boxed::Box,
9 ffi::CString,
10 format,
11 string::{String, ToString},
12 sync::Arc,
13 vec::Vec,
14};
15use core::{
16 ffi::{c_char, c_int},
17 fmt::Debug,
18};
19use elf_loader::input::ElfFile;
20use elf_loader::loader::LifecycleContext;
21use elf_loader::{
22 Loader,
23 elf::{ElfDyn, ElfPhdr, abi::PT_DYNAMIC},
24 image::{ElfCoreRef, LoadedCore, RawDylib, Symbol},
25 input::{ElfBinary, ElfReader},
26};
27
28pub(crate) type ElfDylib = RawDylib<ExtraData>;
29pub(crate) type LoadedDylib = LoadedCore<ExtraData>;
30pub(crate) type CoreComponentRef = ElfCoreRef<ExtraData>;
31
32pub(crate) enum LoadResult {
33 Dylib(ElfDylib),
34 Script(Vec<String>),
35}
36
37#[inline]
41pub(crate) fn find_symbol<'lib, T>(
42 libs: &'lib [LoadedDylib],
43 name: &str,
44) -> Result<Symbol<'lib, T>> {
45 log::info!("Get the symbol [{}] in [{}]", name, libs[0].name());
46 libs.iter()
47 .find_map(|lib| unsafe { lib.get::<T>(name) })
48 .ok_or(find_symbol_error(format!("can not find symbol:{}", name)))
49}
50
51#[inline]
57pub(crate) fn create_lazy_scope(
58 deps: &[LoadedDylib],
59 flags: OpenFlags,
60) -> Arc<dyn for<'a> Fn(&'a str) -> Option<*const ()> + Send + Sync + 'static> {
61 let deps_weak: Vec<CoreComponentRef> = deps
62 .iter()
63 .map(|dep| unsafe { dep.core_ref().downgrade() })
64 .collect();
65 Arc::new(move |name: &str| {
66 let deepbind = flags.is_deepbind();
67
68 let local_find = || {
69 deps_weak.iter().find_map(|dep| unsafe {
70 let core = dep.upgrade()?;
71 let lib = LoadedDylib::from_core(core);
72 lib.get::<()>(name).map(|sym| {
73 log::trace!(
74 "Lazy Binding: find symbol [{}] from [{}] in local scope ",
75 name,
76 lib.name()
77 );
78 let val = sym.into_raw();
79 assert!(lib.base() != val as usize);
80 val
81 })
82 })
83 };
84
85 if deepbind {
86 local_find().or_else(|| unsafe { global_find::<()>(name).map(|s| s.into_raw()) })
87 } else {
88 unsafe { global_find::<()>(name) }
89 .map(|s| s.into_raw())
90 .or_else(local_find)
91 }
92 })
93}
94
95fn from_impl<'a, I>(object: I) -> Result<ElfDylib>
96where
97 I: ElfReader + elf_loader::input::IntoElfReader<'a>,
98{
99 let mut dylib = Loader::new()
100 .with_default_tls_resolver()
101 .with_context::<ExtraData>()
102 .with_init(|ctx: &LifecycleContext| {
103 let argc = unsafe { *core::ptr::addr_of!(ARGC) };
104 let argv = unsafe { *core::ptr::addr_of!(ARGV) };
105 let envp = unsafe { *core::ptr::addr_of!(ENVP) as *const *mut c_char };
106 type InitFn = unsafe extern "C" fn(c_int, *const *mut c_char, *const *mut c_char);
107 if let Some(init) = ctx.func() {
108 let init: InitFn = unsafe { core::mem::transmute(init) };
109 unsafe { init(argc as c_int, argv, envp) };
110 }
111 if let Some(init_array) = ctx.func_array() {
112 for &f in init_array {
113 let f: InitFn = unsafe { core::mem::transmute(f) };
114 unsafe { f(argc as c_int, argv, envp) };
115 }
116 }
117 })
118 .load_dylib(object)?;
119 let needed_libs = dylib
120 .needed_libs()
121 .iter()
122 .map(|s| s.to_string())
123 .collect::<Vec<_>>();
124
125 let name = dylib.name().to_string();
126 let base = dylib.base();
127 let dynamic_ptr = dylib
128 .phdrs()
129 .iter()
130 .find(|p| p.p_type == PT_DYNAMIC)
131 .map(|p| (base + p.p_vaddr as usize) as *mut ElfDyn)
132 .unwrap_or(core::ptr::null_mut());
133
134 let user_data = dylib.user_data_mut().unwrap();
135 user_data.needed_libs = needed_libs;
136 let c_name = CString::new(name).unwrap();
137
138 let mut link_map = Box::new(LinkMap {
139 l_addr: base as *mut _,
140 l_name: c_name.as_ptr(),
141 l_ld: dynamic_ptr as *mut _,
142 l_next: core::ptr::null_mut(),
143 l_prev: core::ptr::null_mut(),
144 });
145
146 unsafe { add_debug_link_map(link_map.as_mut()) };
147 user_data.link_map = Some(link_map);
148 user_data.c_name = Some(c_name);
149 Ok(dylib)
150}
151
152#[derive(Clone)]
157pub struct ElfLibrary {
158 pub(crate) inner: LoadedDylib,
159 pub(crate) deps: Option<Arc<[LoadedDylib]>>,
161}
162
163impl Debug for ElfLibrary {
164 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
165 f.debug_struct("Dylib").field("inner", &self.inner).finish()
166 }
167}
168
169impl ElfLibrary {
170 pub(crate) fn load(path: &str, content: Option<&[u8]>) -> Result<LoadResult> {
171 if let Some(bytes) = content {
172 if bytes.starts_with(b"\x7fELF") {
173 let dylib = Self::from_binary(bytes, path)?;
174 Ok(LoadResult::Dylib(dylib))
175 } else {
176 let libs = get_linker_script_libs(bytes);
177 Ok(LoadResult::Script(libs))
178 }
179 } else {
180 let header = crate::os::read_file_limit(path, 64)?;
181 if header.starts_with(b"\x7fELF") {
182 let dylib = Self::from_file(path)?;
183 Ok(LoadResult::Dylib(dylib))
184 } else {
185 let content = crate::os::read_file(path)?;
186 let libs = get_linker_script_libs(&content);
187 Ok(LoadResult::Script(libs))
188 }
189 }
190 }
191
192 fn from_file(path: impl AsFilename) -> Result<ElfDylib> {
193 let path_ref = path.as_filename();
194 let file = ElfFile::from_path(path_ref)?;
195 from_impl(file)
196 }
197
198 fn from_binary(bytes: &[u8], path: impl AsFilename) -> Result<ElfDylib> {
200 let file = ElfBinary::new(path.as_filename(), bytes);
201 from_impl(file)
202 }
203}
204
205pub trait DylibExt {
206 fn needed_libs(&self) -> &[String];
207 fn shortname(&self) -> &str;
208}
209
210impl DylibExt for LoadedDylib {
211 #[inline]
212 fn needed_libs(&self) -> &[String] {
213 &self.user_data().needed_libs
214 }
215
216 #[inline]
217 fn shortname(&self) -> &str {
218 let name = self.name();
219 if name.is_empty() {
220 "main"
221 } else {
222 self.short_name()
223 }
224 }
225}
226
227impl ElfLibrary {
228 #[inline]
230 pub fn name(&self) -> &str {
231 self.inner.name()
232 }
233
234 #[inline]
236 pub fn cname(&self) -> *const c_char {
237 self.inner
238 .user_data()
239 .c_name
240 .as_ref()
241 .map(|n| n.as_ptr())
242 .unwrap_or(core::ptr::null())
243 }
244
245 #[inline]
247 pub fn shortname(&self) -> &str {
248 self.inner.shortname()
249 }
250
251 pub fn flags(&self) -> OpenFlags {
253 use crate::core_impl::register::MANAGER;
254 crate::lock_read!(MANAGER)
255 .get(self.shortname())
256 .map(|e| e.flags)
257 .unwrap_or(OpenFlags::empty())
258 }
259
260 #[inline]
262 pub fn base(&self) -> usize {
263 self.inner.base()
264 }
265
266 #[inline]
268 pub fn mapped_len(&self) -> usize {
269 self.inner.mapped_len()
270 }
271
272 #[inline]
274 pub fn phdrs(&self) -> Option<&[ElfPhdr]> {
275 self.inner.phdrs()
276 }
277
278 #[inline]
280 pub fn needed_libs(&self) -> &[String] {
281 self.inner.needed_libs()
282 }
283
284 #[inline]
312 pub unsafe fn get<'lib, T>(&'lib self, name: &str) -> Result<Symbol<'lib, T>> {
313 find_symbol(self.deps.as_ref().unwrap(), name)
314 }
315
316 #[cfg(feature = "version")]
325 #[inline]
326 pub unsafe fn get_version<'lib, T>(
327 &'lib self,
328 name: &str,
329 version: &str,
330 ) -> Result<Symbol<'lib, T>> {
331 unsafe {
332 self.inner
333 .get_version(name, version)
334 .ok_or(find_symbol_error(format!("can not find symbol:{}", name)))
335 }
336 }
337}