1pub(crate) mod dylib;
2pub(crate) mod exec;
3
4use crate::{
5 ELFRelro, ElfRelocation, Loader, Result,
6 arch::{Dyn, ElfPhdr, ElfRela},
7 dynamic::ElfDynamic,
8 loader::Builder,
9 mmap::Mmap,
10 object::{ElfObject, ElfObjectAsync},
11 parse_dynamic_error,
12 relocation::LazyScope,
13 segment::ElfSegments,
14 symbol::SymbolTable,
15};
16use alloc::{
17 boxed::Box,
18 ffi::CString,
19 sync::{Arc, Weak},
20 vec::Vec,
21};
22use core::{
23 any::Any,
24 ffi::{CStr, c_int},
25 fmt::Debug,
26 marker::PhantomData,
27 ops::Deref,
28 ptr::{NonNull, null},
29 sync::atomic::{AtomicBool, Ordering},
30};
31use dylib::{ElfDylib, RelocatedDylib};
32use elf::abi::PT_LOAD;
33use exec::{ElfExec, RelocatedExec};
34
35struct DataItem {
36 key: u8,
37 value: Option<Box<dyn Any>>,
38}
39
40pub struct UserData {
42 data: Vec<DataItem>,
43}
44
45impl UserData {
46 #[inline]
47 pub const fn empty() -> Self {
48 Self { data: Vec::new() }
49 }
50
51 #[inline]
52 pub fn insert(&mut self, key: u8, value: Box<dyn Any>) -> Option<Box<dyn Any>> {
53 for item in self.data.iter_mut() {
54 if item.key == key {
55 let old = core::mem::take(&mut item.value);
56 item.value = Some(value);
57 return old;
58 }
59 }
60 self.data.push(DataItem {
61 key,
62 value: Some(value),
63 });
64 None
65 }
66
67 #[inline]
68 pub fn get(&self, key: u8) -> Option<&Box<dyn Any>> {
69 self.data.iter().find_map(|item| {
70 if item.key == key {
71 return item.value.as_ref();
72 }
73 None
74 })
75 }
76}
77
78#[derive(Clone, Copy)]
79pub(crate) struct InitParams {
80 pub argc: usize,
81 pub argv: usize,
82 pub envp: usize,
83}
84
85pub(crate) struct ElfInit {
86 init_param: Option<InitParams>,
87 init_fn: Option<extern "C" fn()>,
89 init_array_fn: Option<&'static [extern "C" fn()]>,
91}
92
93impl ElfInit {
94 #[inline]
95 pub(crate) fn call_init(self) {
96 if let Some(init_params) = self.init_param {
97 self.init_fn
98 .iter()
99 .chain(self.init_array_fn.unwrap_or(&[]).iter())
100 .for_each(|init| unsafe {
101 core::mem::transmute::<_, extern "C" fn(c_int, usize, usize)>(*init)(
102 init_params.argc as _,
103 init_params.argv,
104 init_params.envp,
105 );
106 });
107 } else {
108 self.init_fn
109 .iter()
110 .chain(self.init_array_fn.unwrap_or(&[]).iter())
111 .for_each(|init| init());
112 }
113 }
114}
115
116impl Deref for Relocated<'_> {
117 type Target = CoreComponent;
118
119 fn deref(&self) -> &Self::Target {
120 &self.core
121 }
122}
123
124#[derive(Debug)]
126pub enum Elf {
127 Dylib(ElfDylib),
128 Exec(ElfExec),
129}
130
131#[derive(Debug, Clone)]
133pub enum RelocatedElf<'scope> {
134 Dylib(RelocatedDylib<'scope>),
135 Exec(RelocatedExec<'scope>),
136}
137
138impl<'scope> RelocatedElf<'scope> {
139 #[inline]
140 pub fn into_dylib(self) -> Option<RelocatedDylib<'scope>> {
141 match self {
142 RelocatedElf::Dylib(dylib) => Some(dylib),
143 RelocatedElf::Exec(_) => None,
144 }
145 }
146
147 #[inline]
148 pub fn into_exec(self) -> Option<RelocatedExec<'scope>> {
149 match self {
150 RelocatedElf::Dylib(_) => None,
151 RelocatedElf::Exec(exec) => Some(exec),
152 }
153 }
154
155 #[inline]
156 pub fn as_dylib(&self) -> Option<&RelocatedDylib<'scope>> {
157 match self {
158 RelocatedElf::Dylib(dylib) => Some(dylib),
159 RelocatedElf::Exec(_) => None,
160 }
161 }
162}
163
164impl Deref for Elf {
165 type Target = ElfCommonPart;
166
167 fn deref(&self) -> &Self::Target {
168 match self {
169 Elf::Dylib(elf_dylib) => &elf_dylib,
170 Elf::Exec(elf_exec) => &elf_exec,
171 }
172 }
173}
174
175pub(crate) fn create_lazy_scope<F>(libs: Vec<CoreComponentRef>, pre_find: &F) -> LazyScope
177where
178 F: Fn(&str) -> Option<*const ()>,
179{
180 Box::new(move |name| {
181 libs.iter().find_map(|lib| {
182 pre_find(name).or_else(|| unsafe {
183 RelocatedDylib::from_core_component(lib.upgrade().unwrap())
184 .get::<()>(name)
185 .map(|sym| sym.into_raw())
186 })
187 })
188 })
189}
190
191impl Elf {
192 pub fn easy_relocate<'iter, 'scope, 'find, 'lib, S, F>(
196 self,
197 scope: S,
198 pre_find: &'find F,
199 ) -> Result<RelocatedElf<'lib>>
200 where
201 S: Iterator<Item = &'iter RelocatedDylib<'scope>> + Clone,
202 F: Fn(&str) -> Option<*const ()>,
203 'scope: 'iter,
204 'iter: 'lib,
205 'find: 'lib,
206 {
207 match self {
208 Elf::Dylib(elf_dylib) => Ok(RelocatedElf::Dylib(
209 elf_dylib.easy_relocate(scope, pre_find)?,
210 )),
211 Elf::Exec(elf_exec) => Ok(RelocatedElf::Exec(elf_exec.easy_relocate(scope, pre_find)?)),
212 }
213 }
214
215 pub fn relocate<'iter, 'scope, 'find, 'lib, S, F, D>(
222 self,
223 scope: S,
224 pre_find: &'find F,
225 deal_unknown: D,
226 local_lazy_scope: Option<LazyScope<'lib>>,
227 ) -> Result<RelocatedElf<'lib>>
228 where
229 S: Iterator<Item = &'iter RelocatedDylib<'scope>> + Clone,
230 F: Fn(&str) -> Option<*const ()>,
231 D: Fn(&ElfRela, &CoreComponent, S) -> core::result::Result<(), Box<dyn Any>>,
232 'scope: 'iter,
233 'iter: 'lib,
234 'find: 'lib,
235 {
236 let relocated_elf = match self {
237 Elf::Dylib(elf_dylib) => RelocatedElf::Dylib(elf_dylib.relocate(
238 scope,
239 pre_find,
240 deal_unknown,
241 local_lazy_scope,
242 )?),
243 Elf::Exec(elf_exec) => RelocatedElf::Exec(elf_exec.relocate(
244 scope,
245 pre_find,
246 deal_unknown,
247 local_lazy_scope,
248 )?),
249 };
250 Ok(relocated_elf)
251 }
252}
253
254#[derive(Clone)]
255pub(crate) struct Relocated<'scope> {
256 pub(crate) core: CoreComponent,
257 pub(crate) _marker: PhantomData<&'scope ()>,
258}
259
260pub(crate) struct CoreComponentInner {
261 is_init: AtomicBool,
263 name: CString,
265 pub(crate) symbols: Option<SymbolTable>,
267 dynamic: Option<NonNull<Dyn>>,
269 pub(crate) pltrel: Option<NonNull<ElfRela>>,
271 phdrs: &'static [ElfPhdr],
273 fini_fn: Option<extern "C" fn()>,
275 fini_array_fn: Option<&'static [extern "C" fn()]>,
277 needed_libs: Box<[&'static str]>,
279 user_data: UserData,
281 pub(crate) lazy_scope: Option<LazyScope<'static>>,
283 pub(crate) segments: ElfSegments,
285}
286
287impl Drop for CoreComponentInner {
288 fn drop(&mut self) {
289 if self.is_init.load(Ordering::Relaxed) {
290 self.fini_fn
291 .iter()
292 .chain(self.fini_array_fn.unwrap_or(&[]).iter())
293 .for_each(|fini| fini());
294 }
295 }
296}
297
298pub struct CoreComponentRef {
300 inner: Weak<CoreComponentInner>,
301}
302
303impl CoreComponentRef {
304 pub fn upgrade(&self) -> Option<CoreComponent> {
306 self.inner.upgrade().map(|inner| CoreComponent { inner })
307 }
308}
309
310#[derive(Clone)]
312pub struct CoreComponent {
313 pub(crate) inner: Arc<CoreComponentInner>,
314}
315
316unsafe impl Sync for CoreComponent {}
317unsafe impl Send for CoreComponent {}
318
319impl CoreComponent {
320 #[inline]
321 pub(crate) fn set_lazy_scope(&self, lazy_scope: Option<LazyScope>) {
322 unsafe {
324 let ptr = &mut *(Arc::as_ptr(&self.inner) as *mut CoreComponentInner);
325 ptr.lazy_scope = core::mem::transmute(lazy_scope);
327 };
328 }
329
330 #[inline]
331 pub(crate) fn set_init(&self) {
332 self.inner.is_init.store(true, Ordering::Relaxed);
333 }
334
335 #[inline]
336 pub fn downgrade(&self) -> CoreComponentRef {
338 CoreComponentRef {
339 inner: Arc::downgrade(&self.inner),
340 }
341 }
342
343 #[inline]
345 pub fn user_data(&self) -> &UserData {
346 &self.inner.user_data
347 }
348
349 #[inline]
351 pub fn strong_count(&self) -> usize {
352 Arc::strong_count(&self.inner)
353 }
354
355 #[inline]
357 pub fn weak_count(&self) -> usize {
358 Arc::weak_count(&self.inner)
359 }
360
361 #[inline]
363 pub fn name(&self) -> &str {
364 self.inner.name.to_str().unwrap()
365 }
366
367 #[inline]
369 pub fn cname(&self) -> &CStr {
370 &self.inner.name
371 }
372
373 #[inline]
375 pub fn shortname(&self) -> &str {
376 self.name().split('/').last().unwrap()
377 }
378
379 #[inline]
381 pub fn base(&self) -> usize {
382 self.inner.segments.base()
383 }
384
385 #[inline]
387 pub fn map_len(&self) -> usize {
388 self.inner.segments.len()
389 }
390
391 #[inline]
393 pub fn phdrs(&self) -> &[ElfPhdr] {
394 &self.inner.phdrs
395 }
396
397 #[inline]
399 pub fn dynamic(&self) -> Option<NonNull<Dyn>> {
400 self.inner.dynamic
401 }
402
403 #[inline]
405 pub fn needed_libs(&self) -> &[&str] {
406 &self.inner.needed_libs
407 }
408
409 #[inline]
411 pub fn symtab(&self) -> Option<&SymbolTable> {
412 self.inner.symbols.as_ref()
413 }
414
415 #[inline]
416 pub(crate) fn segments(&self) -> &ElfSegments {
417 &self.inner.segments
418 }
419
420 fn from_raw(
421 name: CString,
422 base: usize,
423 dynamic: ElfDynamic,
424 phdrs: &'static [ElfPhdr],
425 mut segments: ElfSegments,
426 user_data: UserData,
427 ) -> Self {
428 segments.offset = (segments.memory.as_ptr() as usize).wrapping_sub(base);
429 Self {
430 inner: Arc::new(CoreComponentInner {
431 name,
432 is_init: AtomicBool::new(true),
433 symbols: Some(SymbolTable::new(&dynamic)),
434 pltrel: None,
435 dynamic: NonNull::new(dynamic.dyn_ptr as _),
436 phdrs,
437 segments,
438 fini_fn: None,
439 fini_array_fn: None,
440 needed_libs: Box::new([]),
441 user_data,
442 lazy_scope: None,
443 }),
444 }
445 }
446}
447
448impl Debug for CoreComponent {
449 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
450 f.debug_struct("Dylib")
451 .field("name", &self.inner.name)
452 .finish()
453 }
454}
455
456impl Deref for ElfCommonPart {
457 type Target = CoreComponent;
458
459 fn deref(&self) -> &Self::Target {
460 &self.core
461 }
462}
463
464pub struct ElfCommonPart {
465 entry: usize,
467 pub(crate) got: Option<NonNull<usize>>,
469 pub(crate) relocation: ElfRelocation,
471 pub(crate) relro: Option<ELFRelro>,
473 pub(crate) init: ElfInit,
475 lazy: bool,
477 rpath: Option<&'static str>,
479 runpath: Option<&'static str>,
481 interp: Option<&'static str>,
483 pub(crate) core: CoreComponent,
485}
486
487impl ElfCommonPart {
488 #[inline]
490 pub fn entry(&self) -> usize {
491 self.entry + self.base()
492 }
493
494 #[inline]
496 pub fn core_component_ref(&self) -> &CoreComponent {
497 &self.core
498 }
499
500 #[inline]
502 pub fn core_component(&self) -> CoreComponent {
503 self.core.clone()
504 }
505
506 #[inline]
508 pub fn is_lazy(&self) -> bool {
509 self.lazy
510 }
511
512 #[inline]
514 pub fn rpath(&self) -> Option<&str> {
515 self.rpath
516 }
517
518 #[inline]
520 pub fn runpath(&self) -> Option<&str> {
521 self.runpath
522 }
523
524 #[inline]
526 pub fn interp(&self) -> Option<&str> {
527 self.interp
528 }
529}
530
531impl Builder {
532 pub(crate) fn create_common(self, phdrs: &[ElfPhdr], is_dylib: bool) -> Result<ElfCommonPart> {
533 let common = if let Some(dynamic) = self.dynamic {
534 let (phdr_start, phdr_end) = self.ehdr.phdr_range();
535 let phdrs = self.phdr_mmap.unwrap_or_else(|| {
537 phdrs
538 .iter()
539 .filter(|phdr| phdr.p_type == PT_LOAD)
540 .find_map(|phdr| {
541 let cur_range =
542 phdr.p_offset as usize..(phdr.p_offset + phdr.p_filesz) as usize;
543 if cur_range.contains(&phdr_start) && cur_range.contains(&phdr_end) {
544 return unsafe {
545 Some(core::mem::transmute(self.segments.get_slice::<ElfPhdr>(
546 phdr.p_vaddr as usize + phdr_start - cur_range.start,
547 self.ehdr.e_phnum() * size_of::<ElfPhdr>(),
548 )))
549 };
550 }
551 None
552 })
553 .unwrap()
554 });
555
556 let relocation = ElfRelocation::new(dynamic.pltrel, dynamic.dynrel, dynamic.rela_count);
557 let symbols = SymbolTable::new(&dynamic);
558 let needed_libs: Vec<&'static str> = dynamic
559 .needed_libs
560 .iter()
561 .map(|needed_lib| symbols.strtab().get_str(needed_lib.get()))
562 .collect();
563 ElfCommonPart {
564 entry: self.ehdr.e_entry as usize,
565 relro: self.relro,
566 relocation,
567 init: ElfInit {
568 init_param: self.init_params,
569 init_fn: dynamic.init_fn,
570 init_array_fn: dynamic.init_array_fn,
571 },
572 interp: self.interp,
573 lazy: self.lazy_bind.unwrap_or(!dynamic.bind_now),
574 got: dynamic.got,
575 rpath: dynamic
576 .rpath_off
577 .map(|rpath_off| symbols.strtab().get_str(rpath_off.get())),
578 runpath: dynamic
579 .runpath_off
580 .map(|runpath_off| symbols.strtab().get_str(runpath_off.get())),
581 core: CoreComponent {
582 inner: Arc::new(CoreComponentInner {
583 is_init: AtomicBool::new(false),
584 name: self.name,
585 symbols: Some(symbols),
586 dynamic: NonNull::new(dynamic.dyn_ptr as _),
587 pltrel: NonNull::new(dynamic.pltrel.map_or(null(), |plt| plt.as_ptr()) as _),
588 phdrs,
589 fini_fn: dynamic.fini_fn,
590 fini_array_fn: dynamic.fini_array_fn,
591 segments: self.segments,
592 needed_libs: needed_libs.into_boxed_slice(),
593 user_data: self.user_data,
594 lazy_scope: None,
595 }),
596 },
597 }
598 } else {
599 if is_dylib {
600 return Err(parse_dynamic_error("dylib does not have dynamic"));
601 }
602 let relocation = ElfRelocation::new(None, None, None);
603 ElfCommonPart {
604 entry: self.ehdr.e_entry as usize,
605 relro: self.relro,
606 relocation,
607 init: ElfInit {
608 init_param: self.init_params,
609 init_fn: None,
610 init_array_fn: None,
611 },
612 interp: self.interp,
613 lazy: self.lazy_bind.unwrap_or(false),
614 got: None,
615 rpath: None,
616 runpath: None,
617 core: CoreComponent {
618 inner: Arc::new(CoreComponentInner {
619 is_init: AtomicBool::new(false),
620 name: self.name,
621 symbols: None,
622 dynamic: None,
623 pltrel: None,
624 phdrs: &[],
625 fini_fn: None,
626 fini_array_fn: None,
627 segments: self.segments,
628 needed_libs: Box::new([]),
629 user_data: self.user_data,
630 lazy_scope: None,
631 }),
632 },
633 }
634 };
635 Ok(common)
636 }
637
638 pub(crate) fn create_elf(self, phdrs: &[ElfPhdr], is_dylib: bool) -> Result<Elf> {
639 let elf = if is_dylib {
640 Elf::Dylib(self.create_dylib(phdrs)?)
641 } else {
642 Elf::Exec(self.create_exec(phdrs)?)
643 };
644 Ok(elf)
645 }
646}
647
648impl<M: Mmap> Loader<M> {
649 pub fn easy_load(&mut self, object: impl ElfObject) -> Result<Elf> {
651 self.load(object, None)
652 }
653
654 pub fn load(&mut self, mut object: impl ElfObject, lazy_bind: Option<bool>) -> Result<Elf> {
658 let ehdr = self.buf.prepare_ehdr(&mut object)?;
659 let is_dylib = ehdr.is_dylib();
660 let (builder, phdrs) = self.load_impl(ehdr, object, lazy_bind)?;
661 builder.create_elf(phdrs, is_dylib)
662 }
663
664 pub async fn load_async(
668 &mut self,
669 mut object: impl ElfObjectAsync,
670 lazy_bind: Option<bool>,
671 ) -> Result<Elf> {
672 let ehdr = self.buf.prepare_ehdr(&mut object)?;
673 let is_dylib = ehdr.is_dylib();
674 let (builder, phdrs) = self.load_async_impl(ehdr, object, lazy_bind).await?;
675 builder.create_elf(phdrs, is_dylib)
676 }
677}