neotron_loader/
lib.rs

1//! # Neotron Loader
2//!
3//! Handles loading Neotron Executables into the Neotron OS.
4
5#![no_std]
6
7// ============================================================================
8// Imports
9// ============================================================================
10
11pub mod sections;
12pub mod segments;
13pub mod traits;
14
15#[doc(inline)]
16pub use sections::Header as SectionHeader;
17
18#[doc(inline)]
19pub use segments::Header as ProgramHeader;
20
21#[doc(inline)]
22pub use traits::Source;
23
24// ============================================================================
25// Constants
26// ============================================================================
27
28// ============================================================================
29// Static Variables
30// ============================================================================
31
32// ============================================================================
33// Types
34// ============================================================================
35
36/// The ways this API can fail
37#[derive(Debug, Clone)]
38pub enum Error<E>
39where
40    E: core::fmt::Debug,
41{
42    /// The ELF file didn't look right
43    NotAnElfFile,
44    /// It was an ELF file, but not what Neotron can handle
45    WrongElfFile,
46    /// There was a problem with the data source.
47    Source(E),
48    /// Couldn't fit string into given buffer
49    NotEnoughSpace,
50    /// Section name wasn't UTF-8
51    InvalidString,
52}
53
54impl<E> From<E> for Error<E>
55where
56    E: core::fmt::Debug,
57{
58    fn from(value: E) -> Error<E> {
59        Error::Source(value)
60    }
61}
62
63/// An object that can load and parse an ELF file.
64pub struct Loader<DS> {
65    /// Where we get the bytes from
66    data_source: DS,
67    /// The memory address of the entry point
68    e_entry: u32,
69    /// The offset of the program header table
70    e_phoff: u32,
71    /// The offset of the section header table
72    e_shoff: u32,
73    /// The number of program header entries
74    e_phnum: u16,
75    /// The number of section header entries
76    e_shnum: u16,
77    /// The index of the section header containing section names.
78    e_shstrndx: u16,
79}
80
81impl<DS> Loader<DS>
82where
83    DS: Source,
84{
85    /// Indicates ARM machine
86    const EM_ARM: u16 = 0x0028;
87    /// For offset 0x10, indicates a binary
88    const ET_EXEC: u16 = 0x0002;
89    /// Standard ELF magic header
90    const ELF_MAGIC: u32 = 0x7F454C46;
91    /// 32-bit, little-endian, version 1, SysV
92    const DESIRED_ELF_VERSION: u32 = 0x01010100;
93
94    /// Make a new loader
95    pub fn new(data_source: DS) -> Result<Loader<DS>, Error<DS::Error>> {
96        let elf_header = data_source.read_u32_be(0x00)?;
97        if elf_header != Self::ELF_MAGIC {
98            // File doesn't start 0x7F E L F
99            return Err(Error::NotAnElfFile);
100        }
101        let class_endian_version_abi = data_source.read_u32_be(0x04)?;
102        if class_endian_version_abi != Self::DESIRED_ELF_VERSION {
103            return Err(Error::WrongElfFile);
104        }
105
106        // Ignore ABI version at 0x08..0x10
107
108        let elf_type = data_source.read_u16_le(0x10)?;
109        if elf_type != Self::ET_EXEC {
110            // File is not a binary
111            return Err(Error::WrongElfFile);
112        }
113
114        let elf_machine = data_source.read_u16_le(0x12)?;
115        if elf_machine != Self::EM_ARM {
116            // File is not a ARM
117            return Err(Error::WrongElfFile);
118        }
119
120        let elf_version = data_source.read_u32_le(0x14)?;
121        if elf_version != 1 {
122            // File is not a ELF
123            return Err(Error::WrongElfFile);
124        }
125
126        let e_entry = data_source.read_u32_le(0x18)?;
127        let e_phoff = data_source.read_u32_le(0x1C)?;
128        let e_shoff = data_source.read_u32_le(0x20)?;
129        let e_phentsize = data_source.read_u16_le(0x2A)?;
130
131        if e_phentsize != ProgramHeader::SIZE_IN_BYTES {
132            return Err(Error::WrongElfFile);
133        }
134
135        let e_phnum = data_source.read_u16_le(0x2C)?;
136        let e_shentsize = data_source.read_u16_le(0x2E)?;
137
138        if e_shentsize != SectionHeader::SIZE_IN_BYTES {
139            return Err(Error::WrongElfFile);
140        }
141
142        let e_shnum = data_source.read_u16_le(0x30)?;
143
144        let e_shstrndx = data_source.read_u16_le(0x32)?;
145
146        let loader = Loader {
147            data_source,
148            e_entry,
149            e_phoff,
150            e_shoff,
151            e_phnum,
152            e_shnum,
153            e_shstrndx,
154        };
155        Ok(loader)
156    }
157
158    /// Create a section header iterator.
159    pub fn iter_section_headers(&self) -> IterSectionHeaders<DS> {
160        IterSectionHeaders {
161            parent: self,
162            next_section: 0,
163        }
164    }
165
166    /// Create a program header iterator.
167    pub fn iter_program_headers(&self) -> IterProgramHeaders<DS> {
168        IterProgramHeaders {
169            parent: self,
170            next_program_header: 0,
171        }
172    }
173
174    /// The memory address of the entry point
175    pub fn e_entry(&self) -> u32 {
176        self.e_entry
177    }
178
179    /// The offset of the program header table
180    pub fn e_phoff(&self) -> u32 {
181        self.e_phoff
182    }
183
184    /// The offset of the section header table
185    pub fn e_shoff(&self) -> u32 {
186        self.e_shoff
187    }
188
189    /// The number of program header entries
190    pub fn e_phnum(&self) -> u16 {
191        self.e_phnum
192    }
193
194    /// The number of section header entries
195    pub fn e_shnum(&self) -> u16 {
196        self.e_shnum
197    }
198
199    /// Return the start offset for valid segments.
200    ///
201    /// Any segment with a `p_offset` less than this probably isn't valid.
202    pub fn segment_start_offset(&self) -> u32 {
203        self.e_phoff() + u32::from(self.e_phnum()) * u32::from(ProgramHeader::SIZE_IN_BYTES)
204    }
205}
206
207/// Allows you to iterate through the section headers.
208///
209/// Created with `loader.iter_section_headers()`.
210pub struct IterSectionHeaders<'a, DS> {
211    parent: &'a Loader<DS>,
212    next_section: u16,
213}
214
215impl<'a, DS> Iterator for IterSectionHeaders<'a, DS>
216where
217    DS: Source,
218{
219    type Item = Result<SectionHeader, Error<DS::Error>>;
220
221    fn next(&mut self) -> Option<Self::Item> {
222        if self.next_section == self.parent.e_shnum {
223            return None;
224        }
225
226        let current_section = self.next_section;
227        self.next_section = self.next_section.wrapping_add(1);
228
229        Some(SectionHeader::new(self.parent, current_section))
230    }
231}
232
233/// Allows you to iterate through the program headers.
234///
235/// Created with `loader.iter_program_headers()`.
236pub struct IterProgramHeaders<'a, DS> {
237    parent: &'a Loader<DS>,
238    next_program_header: u16,
239}
240
241impl<'a, DS> Iterator for IterProgramHeaders<'a, DS>
242where
243    DS: Source,
244{
245    type Item = Result<ProgramHeader, Error<DS::Error>>;
246
247    fn next(&mut self) -> Option<Self::Item> {
248        if self.next_program_header == self.parent.e_phnum {
249            return None;
250        }
251
252        let current_program_header = self.next_program_header;
253        self.next_program_header = self.next_program_header.wrapping_add(1);
254
255        Some(ProgramHeader::new(self.parent, current_program_header))
256    }
257}
258
259// ============================================================================
260// Functions
261// ============================================================================
262
263// ============================================================================
264// Tests
265// ============================================================================
266
267// ============================================================================
268// End of File
269// ============================================================================