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    fn add_name_map(&mut self, _name: &str, _id: ObjID) {}
34    fn remove_name_map(&mut self, _name: Option<&str>, _id: Option<ObjID>) {}
35}
36
37/// A single load directive, matching closely with an ELF program header.
38#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
39pub struct LoadDirective {
40    pub load_flags: LoadFlags,
41    pub vaddr: usize,
42    pub memsz: usize,
43    pub offset: usize,
44    pub align: usize,
45    pub filesz: usize,
46}
47
48bitflags::bitflags! {
49    /// Some flags for a load directive.
50    #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default)]
51    pub struct LoadFlags: u32 {
52        /// This load directive specifies a data (writable) segment.
53        const TARGETS_DATA = 1;
54    }
55}
56
57/// A backing type for the dynamic linker. Contains a handle to an object, and abstractions
58/// for treating Twizzler objects as object files.
59#[derive(Clone)]
60pub struct Backing {
61    _owner: Arc<dyn Any>,
62    start: *mut u8,
63    len: usize,
64    id: ObjID,
65    full_name: String,
66}
67
68unsafe impl Send for Backing {}
69unsafe impl Sync for Backing {}
70
71impl Backing {
72    pub fn new(inner: ObjectHandle, full_name: &str) -> Self {
73        unsafe {
74            Self::new_owned(
75                inner.start(),
76                MAX_SIZE - NULLPAGE_SIZE * 2,
77                inner.id(),
78                Arc::new(inner),
79                full_name.to_string(),
80            )
81        }
82    }
83
84    pub unsafe fn new_owned(
85        start: *mut u8,
86        len: usize,
87        id: ObjID,
88        owner: Arc<dyn Any>,
89        full_name: String,
90    ) -> Self {
91        Self {
92            _owner: owner,
93            start,
94            len,
95            id,
96            full_name,
97        }
98    }
99
100    pub fn full_name(&self) -> &str {
101        &self.full_name
102    }
103}
104
105impl Backing {
106    pub(crate) fn data(&self) -> (*mut u8, usize) {
107        (unsafe { self.start.add(NULLPAGE_SIZE) }, self.len)
108    }
109
110    /// Get the underlying object handle.
111    pub fn id(&self) -> ObjID {
112        self.id
113    }
114
115    pub fn load_addr(&self) -> usize {
116        self.start as usize
117    }
118
119    pub(crate) fn slice(&self) -> &[u8] {
120        let data = self.data();
121        // Safety: a loaded library may have a slice constructed of its backing data.
122        unsafe { core::slice::from_raw_parts(data.0, data.1) }
123    }
124
125    /// Get the ELF file for this backing.
126    pub(crate) fn get_elf(&self) -> Result<elf::ElfBytes<'_, NativeEndian>, ParseError> {
127        elf::ElfBytes::minimal_parse(self.slice())
128    }
129}