elf_loader/format/
mod.rs

1pub(crate) mod dylib;
2pub(crate) mod exec;
3
4use crate::{
5    ELFRelro, ElfRelocation, Loader, Result,
6    arch::{Dyn, ElfPhdr, ElfRelType},
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
40/// User-defined data associated with the loaded ELF file
41pub 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
88    init_fn: Option<extern "C" fn()>,
89    /// .init_array
90    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/// An unrelocated elf file
125#[derive(Debug)]
126pub enum Elf {
127    Dylib(ElfDylib),
128    Exec(ElfExec),
129}
130
131/// A elf file that has been relocated
132#[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
175// 使用CoreComponentRef是防止出现循环引用
176pub(crate) fn create_lazy_scope<F>(libs: Vec<CoreComponentRef>, pre_find: &F) -> LazyScope
177where
178    F: Fn(&str) -> Option<*const ()>,
179{
180    Arc::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    /// Relocate the elf file with the given dynamic libraries and function closure.
193    /// # Note
194    /// During relocation, the symbol is first searched in the function closure `pre_find`.
195    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    /// Relocate the elf file with the given dynamic libraries and function closure.
216    /// # Note
217    /// * During relocation, the symbol is first searched in the function closure `pre_find`.
218    /// * The `deal_unknown` function is used to handle relocation types not implemented by efl_loader or failed relocations
219    /// * relocation will be done in the exact order in which the dynamic libraries appear in `scope`.
220    /// * When lazy binding, the symbol is first looked for in the global scope and then in the local lazy scope
221    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(&ElfRelType, &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 initialized
262    is_init: AtomicBool,
263    /// file name
264    name: CString,
265    /// elf symbols
266    pub(crate) symbols: Option<SymbolTable>,
267    /// dynamic
268    dynamic: Option<NonNull<Dyn>>,
269    /// rela.plt
270    pub(crate) pltrel: Option<NonNull<ElfRelType>>,
271    /// phdrs
272    phdrs: &'static [ElfPhdr],
273    /// .fini
274    fini_fn: Option<extern "C" fn()>,
275    /// .fini_array
276    fini_array_fn: Option<&'static [extern "C" fn()]>,
277    /// needed libs' name
278    needed_libs: Box<[&'static str]>,
279    /// user data
280    user_data: UserData,
281    /// lazy binding scope
282    pub(crate) lazy_scope: Option<LazyScope<'static>>,
283    /// semgents
284    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
298/// `CoreComponentRef` is a version of `CoreComponent` that holds a non-owning reference to the managed allocation.
299pub struct CoreComponentRef {
300    inner: Weak<CoreComponentInner>,
301}
302
303impl CoreComponentRef {
304    /// Attempts to upgrade the Weak pointer to an Arc
305    pub fn upgrade(&self) -> Option<CoreComponent> {
306        self.inner.upgrade().map(|inner| CoreComponent { inner })
307    }
308}
309
310/// The core part of an elf object
311#[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的方法可以拿到CoreComponent的引用,所以这里认为是安全的
323        unsafe {
324            let ptr = &mut *(Arc::as_ptr(&self.inner) as *mut CoreComponentInner);
325            // 在relocate接口处保证了lazy_scope的声明周期,因此这里直接转换
326            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    /// Creates a new Weak pointer to this allocation.
337    pub fn downgrade(&self) -> CoreComponentRef {
338        CoreComponentRef {
339            inner: Arc::downgrade(&self.inner),
340        }
341    }
342
343    /// Gets user data from the elf object.
344    #[inline]
345    pub fn user_data(&self) -> &UserData {
346        &self.inner.user_data
347    }
348
349    /// Gets the number of strong references to the elf object.
350    #[inline]
351    pub fn strong_count(&self) -> usize {
352        Arc::strong_count(&self.inner)
353    }
354
355    /// Gets the number of weak references to the elf object.
356    #[inline]
357    pub fn weak_count(&self) -> usize {
358        Arc::weak_count(&self.inner)
359    }
360
361    /// Gets the name of the elf object.
362    #[inline]
363    pub fn name(&self) -> &str {
364        self.inner.name.to_str().unwrap()
365    }
366
367    /// Gets the C-style name of the elf object.
368    #[inline]
369    pub fn cname(&self) -> &CStr {
370        &self.inner.name
371    }
372
373    /// Gets the short name of the elf object.
374    #[inline]
375    pub fn shortname(&self) -> &str {
376        self.name().split('/').last().unwrap()
377    }
378
379    /// Gets the base address of the elf object.
380    #[inline]
381    pub fn base(&self) -> usize {
382        self.inner.segments.base()
383    }
384
385    /// Gets the memory length of the elf object map.
386    #[inline]
387    pub fn map_len(&self) -> usize {
388        self.inner.segments.len()
389    }
390
391    /// Gets the program headers of the elf object.
392    #[inline]
393    pub fn phdrs(&self) -> &[ElfPhdr] {
394        &self.inner.phdrs
395    }
396
397    /// Gets the address of the dynamic section.
398    #[inline]
399    pub fn dynamic(&self) -> Option<NonNull<Dyn>> {
400        self.inner.dynamic
401    }
402
403    /// Gets the needed libs' name of the elf object.
404    #[inline]
405    pub fn needed_libs(&self) -> &[&str] {
406        &self.inner.needed_libs
407    }
408
409    /// Gets the symbol table.
410    #[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
466    entry: usize,
467    /// .got.plt
468    pub(crate) got: Option<NonNull<usize>>,
469    /// rela.dyn and rela.plt
470    pub(crate) relocation: ElfRelocation,
471    /// GNU_RELRO segment
472    pub(crate) relro: Option<ELFRelro>,
473    /// init
474    pub(crate) init: ElfInit,
475    /// lazy binding
476    lazy: bool,
477    /// DT_RPATH
478    rpath: Option<&'static str>,
479    /// DT_RUNPATH
480    runpath: Option<&'static str>,
481    /// PT_INTERP
482    interp: Option<&'static str>,
483    /// core component
484    pub(crate) core: CoreComponent,
485}
486
487impl ElfCommonPart {
488    /// Gets the entry point of the elf object.
489    #[inline]
490    pub fn entry(&self) -> usize {
491        self.entry + self.base()
492    }
493
494    /// Gets the core component reference of the elf object
495    #[inline]
496    pub fn core_component_ref(&self) -> &CoreComponent {
497        &self.core
498    }
499
500    /// Gets the core component of the elf object
501    #[inline]
502    pub fn core_component(&self) -> CoreComponent {
503        self.core.clone()
504    }
505
506    /// Whether lazy binding is enabled for the current elf object.
507    #[inline]
508    pub fn is_lazy(&self) -> bool {
509        self.lazy
510    }
511
512    /// Gets the DT_RPATH value.
513    #[inline]
514    pub fn rpath(&self) -> Option<&str> {
515        self.rpath
516    }
517
518    /// Gets the DT_RUNPATH value.
519    #[inline]
520    pub fn runpath(&self) -> Option<&str> {
521        self.runpath
522    }
523
524    /// Gets the PT_INTERP value.
525    #[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            // 获取映射到内存中的Phdr
536            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(
557                dynamic.pltrel,
558                dynamic.dynrel,
559                dynamic.relr,
560                dynamic.rel_count,
561            );
562            let symbols = SymbolTable::new(&dynamic);
563            let needed_libs: Vec<&'static str> = dynamic
564                .needed_libs
565                .iter()
566                .map(|needed_lib| symbols.strtab().get_str(needed_lib.get()))
567                .collect();
568            ElfCommonPart {
569                entry: self.ehdr.e_entry as usize,
570                relro: self.relro,
571                relocation,
572                init: ElfInit {
573                    init_param: self.init_params,
574                    init_fn: dynamic.init_fn,
575                    init_array_fn: dynamic.init_array_fn,
576                },
577                interp: self.interp,
578                lazy: self.lazy_bind.unwrap_or(!dynamic.bind_now),
579                got: dynamic.got,
580                rpath: dynamic
581                    .rpath_off
582                    .map(|rpath_off| symbols.strtab().get_str(rpath_off.get())),
583                runpath: dynamic
584                    .runpath_off
585                    .map(|runpath_off| symbols.strtab().get_str(runpath_off.get())),
586                core: CoreComponent {
587                    inner: Arc::new(CoreComponentInner {
588                        is_init: AtomicBool::new(false),
589                        name: self.name,
590                        symbols: Some(symbols),
591                        dynamic: NonNull::new(dynamic.dyn_ptr as _),
592                        pltrel: NonNull::new(dynamic.pltrel.map_or(null(), |plt| plt.as_ptr()) as _),
593                        phdrs,
594                        fini_fn: dynamic.fini_fn,
595                        fini_array_fn: dynamic.fini_array_fn,
596                        segments: self.segments,
597                        needed_libs: needed_libs.into_boxed_slice(),
598                        user_data: self.user_data,
599                        lazy_scope: None,
600                    }),
601                },
602            }
603        } else {
604            if is_dylib {
605                return Err(parse_dynamic_error("dylib does not have dynamic"));
606            }
607            let relocation = ElfRelocation::new(None, None, None, None);
608            ElfCommonPart {
609                entry: self.ehdr.e_entry as usize,
610                relro: self.relro,
611                relocation,
612                init: ElfInit {
613                    init_param: self.init_params,
614                    init_fn: None,
615                    init_array_fn: None,
616                },
617                interp: self.interp,
618                lazy: self.lazy_bind.unwrap_or(false),
619                got: None,
620                rpath: None,
621                runpath: None,
622                core: CoreComponent {
623                    inner: Arc::new(CoreComponentInner {
624                        is_init: AtomicBool::new(false),
625                        name: self.name,
626                        symbols: None,
627                        dynamic: None,
628                        pltrel: None,
629                        phdrs: &[],
630                        fini_fn: None,
631                        fini_array_fn: None,
632                        segments: self.segments,
633                        needed_libs: Box::new([]),
634                        user_data: self.user_data,
635                        lazy_scope: None,
636                    }),
637                },
638            }
639        };
640        Ok(common)
641    }
642
643    pub(crate) fn create_elf(self, phdrs: &[ElfPhdr], is_dylib: bool) -> Result<Elf> {
644        let elf = if is_dylib {
645            Elf::Dylib(self.create_dylib(phdrs)?)
646        } else {
647            Elf::Exec(self.create_exec(phdrs)?)
648        };
649        Ok(elf)
650    }
651}
652
653impl<M: Mmap> Loader<M> {
654    /// Load a elf file into memory
655    pub fn easy_load(&mut self, object: impl ElfObject) -> Result<Elf> {
656        self.load(object, None)
657    }
658
659    /// Load a elf file into memory
660    /// # Note
661    /// * When `lazy_bind` is not set, lazy binding is enabled using the dynamic library's DT_FLAGS flag.
662    pub fn load(&mut self, mut object: impl ElfObject, lazy_bind: Option<bool>) -> Result<Elf> {
663        let ehdr = self.buf.prepare_ehdr(&mut object)?;
664        let is_dylib = ehdr.is_dylib();
665        let (builder, phdrs) = self.load_impl(ehdr, object, lazy_bind)?;
666        builder.create_elf(phdrs, is_dylib)
667    }
668
669    /// Load a elf file into memory
670    /// # Note
671    /// * When `lazy_bind` is not set, lazy binding is enabled using the dynamic library's DT_FLAGS flag.
672    pub async fn load_async(
673        &mut self,
674        mut object: impl ElfObjectAsync,
675        lazy_bind: Option<bool>,
676    ) -> Result<Elf> {
677        let ehdr = self.buf.prepare_ehdr(&mut object)?;
678        let is_dylib = ehdr.is_dylib();
679        let (builder, phdrs) = self.load_async_impl(ehdr, object, lazy_bind).await?;
680        builder.create_elf(phdrs, is_dylib)
681    }
682}