elfloader/
lib.rs

1#![no_std]
2#![crate_name = "elfloader"]
3#![crate_type = "lib"]
4
5#[cfg(test)]
6#[macro_use]
7extern crate std;
8#[cfg(test)]
9extern crate env_logger;
10
11mod binary;
12pub use binary::ElfBinary;
13
14pub mod arch;
15pub use arch::RelocationType;
16
17use core::fmt;
18use core::iter::Filter;
19
20use bitflags::bitflags;
21use xmas_elf::dynamic::*;
22use xmas_elf::program::ProgramIter;
23
24pub use xmas_elf::header::Machine;
25pub use xmas_elf::program::{Flags, ProgramHeader, ProgramHeader64};
26pub use xmas_elf::sections::{Rel, Rela};
27pub use xmas_elf::symbol_table::{Entry, Entry64};
28pub use xmas_elf::{P32, P64};
29
30/// An iterator over [`ProgramHeader`] whose type is `LOAD`.
31pub type LoadableHeaders<'a, 'b> = Filter<ProgramIter<'a, 'b>, fn(&ProgramHeader) -> bool>;
32pub type PAddr = u64;
33pub type VAddr = u64;
34
35// Abstract relocation entries to be passed to the
36// trait's relocate method. Library user can decide
37// how to handle each relocation
38#[allow(dead_code)]
39pub struct RelocationEntry {
40    pub rtype: RelocationType,
41    pub offset: u64,
42    pub index: u32,
43    pub addend: Option<u64>,
44}
45
46#[derive(PartialEq, Clone, Debug)]
47pub enum ElfLoaderErr {
48    ElfParser { source: &'static str },
49    OutOfMemory,
50    SymbolTableNotFound,
51    UnsupportedElfFormat,
52    UnsupportedElfVersion,
53    UnsupportedEndianness,
54    UnsupportedAbi,
55    UnsupportedElfType,
56    UnsupportedSectionData,
57    UnsupportedArchitecture,
58    UnsupportedRelocationEntry,
59}
60
61impl From<&'static str> for ElfLoaderErr {
62    fn from(source: &'static str) -> Self {
63        ElfLoaderErr::ElfParser { source }
64    }
65}
66
67impl fmt::Display for ElfLoaderErr {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        match self {
70            ElfLoaderErr::ElfParser { source } => write!(f, "Error in ELF parser: {}", source),
71            ElfLoaderErr::OutOfMemory => write!(f, "Out of memory"),
72            ElfLoaderErr::SymbolTableNotFound => write!(f, "No symbol table in the ELF file"),
73            ElfLoaderErr::UnsupportedElfFormat => write!(f, "ELF format not supported"),
74            ElfLoaderErr::UnsupportedElfVersion => write!(f, "ELF version not supported"),
75            ElfLoaderErr::UnsupportedEndianness => write!(f, "ELF endianness not supported"),
76            ElfLoaderErr::UnsupportedAbi => write!(f, "ELF ABI not supported"),
77            ElfLoaderErr::UnsupportedElfType => write!(f, "ELF type not supported"),
78            ElfLoaderErr::UnsupportedSectionData => write!(f, "Can't handle this section data"),
79            ElfLoaderErr::UnsupportedArchitecture => write!(f, "Unsupported Architecture"),
80            ElfLoaderErr::UnsupportedRelocationEntry => {
81                write!(f, "Can't handle relocation entry")
82            }
83        }
84    }
85}
86
87bitflags! {
88    #[derive(Default)]
89    pub struct DynamicFlags1: u64 {
90        const NOW = FLAG_1_NOW;
91        const GLOBAL = FLAG_1_GLOBAL;
92        const GROUP = FLAG_1_GROUP;
93        const NODELETE = FLAG_1_NODELETE;
94        const LOADFLTR = FLAG_1_LOADFLTR;
95        const INITFIRST = FLAG_1_INITFIRST;
96        const NOOPEN = FLAG_1_NOOPEN;
97        const ORIGIN = FLAG_1_ORIGIN;
98        const DIRECT = FLAG_1_DIRECT;
99        const TRANS = FLAG_1_TRANS;
100        const INTERPOSE = FLAG_1_INTERPOSE;
101        const NODEFLIB = FLAG_1_NODEFLIB;
102        const NODUMP = FLAG_1_NODUMP;
103        const CONFALT = FLAG_1_CONFALT;
104        const ENDFILTEE = FLAG_1_ENDFILTEE;
105        const DISPRELDNE = FLAG_1_DISPRELDNE;
106        const DISPRELPND = FLAG_1_DISPRELPND;
107        const NODIRECT = FLAG_1_NODIRECT;
108        const IGNMULDEF = FLAG_1_IGNMULDEF;
109        const NOKSYMS = FLAG_1_NOKSYMS;
110        const NOHDR = FLAG_1_NOHDR;
111        const EDITED = FLAG_1_EDITED;
112        const NORELOC = FLAG_1_NORELOC;
113        const SYMINTPOSE = FLAG_1_SYMINTPOSE;
114        const GLOBAUDIT = FLAG_1_GLOBAUDIT;
115        const SINGLETON = FLAG_1_SINGLETON;
116        const STUB = FLAG_1_STUB;
117        const PIE = FLAG_1_PIE;
118    }
119}
120
121/// Information parse from the .dynamic section
122pub struct DynamicInfo {
123    pub flags1: DynamicFlags1,
124    pub rela: u64,
125    pub rela_size: u64,
126}
127
128/// Implement this trait for customized ELF loading.
129///
130/// The flow of ElfBinary is that it first calls `allocate` for all regions
131/// that need to be allocated (i.e., the LOAD program headers of the ELF binary),
132/// then `load` will be called to fill the allocated regions, and finally
133/// `relocate` is called for every entry in the RELA table.
134pub trait ElfLoader {
135    /// Allocates a virtual region specified by `load_headers`.
136    fn allocate(&mut self, load_headers: LoadableHeaders) -> Result<(), ElfLoaderErr>;
137
138    /// Copies `region` into memory starting at `base`.
139    /// The caller makes sure that there was an `allocate` call previously
140    /// to initialize the region.
141    fn load(&mut self, flags: Flags, base: VAddr, region: &[u8]) -> Result<(), ElfLoaderErr>;
142
143    /// Request for the client to relocate the given `entry`
144    /// within the loaded ELF file.
145    fn relocate(&mut self, entry: RelocationEntry) -> Result<(), ElfLoaderErr>;
146
147    /// Inform client about where the initial TLS data is located.
148    fn tls(
149        &mut self,
150        _tdata_start: VAddr,
151        _tdata_length: u64,
152        _total_size: u64,
153        _align: u64,
154    ) -> Result<(), ElfLoaderErr> {
155        Ok(())
156    }
157
158    /// In case there is a `.data.rel.ro` section we instruct the loader
159    /// to change the passed offset to read-only (this is called after
160    /// the relocate calls are completed).
161    ///
162    /// Note: The default implementation is a no-op since this is
163    /// not strictly necessary to implement.
164    fn make_readonly(&mut self, _base: VAddr, _size: usize) -> Result<(), ElfLoaderErr> {
165        Ok(())
166    }
167}
168
169#[cfg(doctest)]
170mod test_readme {
171    macro_rules! external_doc_test {
172        ($x:expr) => {
173            #[doc = $x]
174            extern "C" {}
175        };
176    }
177
178    external_doc_test!(include_str!("../README.md"));
179}