dynlink/engines/
mod.rs

1pub mod twizzler;
2
3use std::{any::Any, collections::HashMap, sync::Arc};
4
5use elf::{endian::NativeEndian, ParseError};
6use twizzler_abi::object::{ObjID, MAX_SIZE, NULLPAGE_SIZE};
7use twizzler_rt_abi::object::ObjectHandle;
8
9use crate::{compartment::CompartmentId, library::UnloadedLibrary, DynlinkError};
10
11#[derive(Default)]
12pub struct LoadCtx {
13    pub set: HashMap<CompartmentId, ObjID>,
14}
15/// System-specific implementation functions for the dynamic linker, mostly
16/// involving loading objects.
17pub trait ContextEngine {
18    /// Load a given source backing into new backings, according to the given load directives.
19    fn load_segments(
20        &mut self,
21        src: &Backing,
22        ld: &[LoadDirective],
23        comp_id: CompartmentId,
24        load_ctx: &mut LoadCtx,
25    ) -> Result<Vec<Backing>, DynlinkError>;
26
27    /// Load a single object, based on the given unloaded library.
28    fn load_object(&mut self, unlib: &UnloadedLibrary) -> Result<Backing, DynlinkError>;
29
30    /// Select which compartment a library should go in.
31    fn select_compartment(&mut self, unlib: &UnloadedLibrary) -> Option<CompartmentId>;
32}
33
34/// A single load directive, matching closely with an ELF program header.
35#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
36pub struct LoadDirective {
37    pub load_flags: LoadFlags,
38    pub vaddr: usize,
39    pub memsz: usize,
40    pub offset: usize,
41    pub align: usize,
42    pub filesz: usize,
43}
44
45bitflags::bitflags! {
46    /// Some flags for a load directive.
47    #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
48    pub struct LoadFlags: u32 {
49        /// This load directive specifies a data (writable) segment.
50        const TARGETS_DATA = 1;
51    }
52}
53
54/// A backing type for the dynamic linker. Contains a handle to an object, and abstractions
55/// for treating Twizzler objects as object files.
56#[derive(Clone)]
57pub struct Backing {
58    _owner: Arc<dyn Any>,
59    start: *mut u8,
60    len: usize,
61    id: ObjID,
62    full_name: String,
63}
64
65unsafe impl Send for Backing {}
66unsafe impl Sync for Backing {}
67
68impl Backing {
69    pub fn new(inner: ObjectHandle, full_name: String) -> Self {
70        unsafe {
71            Self::new_owned(
72                inner.start(),
73                MAX_SIZE - NULLPAGE_SIZE * 2,
74                inner.id(),
75                Arc::new(inner),
76                full_name,
77            )
78        }
79    }
80
81    pub unsafe fn new_owned(
82        start: *mut u8,
83        len: usize,
84        id: ObjID,
85        owner: Arc<dyn Any>,
86        full_name: String,
87    ) -> Self {
88        Self {
89            _owner: owner,
90            start,
91            len,
92            id,
93            full_name,
94        }
95    }
96
97    pub fn full_name(&self) -> &str {
98        &self.full_name
99    }
100}
101
102impl Backing {
103    pub(crate) fn data(&self) -> (*mut u8, usize) {
104        (unsafe { self.start.add(NULLPAGE_SIZE) }, self.len)
105    }
106
107    /// Get the underlying object handle.
108    pub fn id(&self) -> ObjID {
109        self.id
110    }
111
112    pub fn load_addr(&self) -> usize {
113        self.start as usize
114    }
115
116    pub(crate) fn slice(&self) -> &[u8] {
117        let data = self.data();
118        // Safety: a loaded library may have a slice constructed of its backing data.
119        unsafe { core::slice::from_raw_parts(data.0, data.1) }
120    }
121
122    /// Get the ELF file for this backing.
123    pub(crate) fn get_elf(&self) -> Result<elf::ElfBytes<'_, NativeEndian>, ParseError> {
124        elf::ElfBytes::minimal_parse(self.slice())
125    }
126}