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