1use core::{ffi::CStr, fmt, mem, ops::Deref};
2
3use alloc::{string::String, vec, vec::Vec};
4
5use crate::{fs, memory_management::virtual_memory_mapper};
6
7#[derive(Debug)]
8pub enum ElfLoadError {
9 InvalidMagic,
10 #[allow(dead_code)]
11 FileSystemError(fs::FileSystemError),
12 InvalidElfOrNotSupported,
13 UnexpectedEndOfFile,
14}
15
16impl From<fs::FileSystemError> for ElfLoadError {
17 fn from(e: fs::FileSystemError) -> Self {
18 Self::FileSystemError(e)
19 }
20}
21
22#[allow(dead_code)]
23mod consts {
24 pub const ELF_MAGIC: &[u8; 4] = b"\x7fELF";
25 pub const ABI_SYSV: u8 = 0;
26 pub const BITS_32: u8 = 1;
27 pub const BITS_64: u8 = 2;
28 pub const ENDIANNESS_LITTLE: u8 = 1;
29 pub const ENDIANNESS_BIG: u8 = 2;
30
31 pub const ELF_TYPE_RELOCATABLE: u16 = 1;
32 pub const ELF_TYPE_EXECUTABLE: u16 = 2;
33 pub const ELF_TYPE_SHARED: u16 = 3;
34
35 pub const ELF_MACHINE_X86: u16 = 3;
36 pub const ELF_MACHINE_X86_64: u16 = 62;
37
38 pub const PROG_FLAG_EXE: u32 = 0x1;
39 pub const PROG_FLAG_WRITE: u32 = 0x2;
40 pub const PROG_FLAG_READ: u32 = 0x4;
41}
42
43pub fn to_virtual_memory_flags(flags: u32) -> u64 {
44 let mut vm_flags = 0;
46
47 if flags & consts::PROG_FLAG_WRITE != 0 {
48 vm_flags |= virtual_memory_mapper::flags::PTE_WRITABLE;
49 }
50 if flags & consts::PROG_FLAG_EXE != 0 {
51 }
53 vm_flags
54}
55
56#[repr(C, packed)]
57#[derive(Copy, Clone, Debug)]
58struct ElfHeaderBase {
59 magic: [u8; 4],
60 bits: u8,
61 endianness: u8,
62 version: u8,
63 abi: u8,
64 abi_version: u8,
65 _pad: [u8; 7],
66 elf_type: u16,
67 machine: u16,
68 elf_version: u32,
69}
70
71#[repr(C, packed)]
72#[derive(Copy, Clone, Debug)]
73struct ElfHeader32 {
74 entry: u32,
75 program_header_offset: u32,
76 section_header_offset: u32,
77 flags: u32,
78 header_size: u16,
79 program_header_entry_size: u16,
80 program_header_entry_count: u16,
81 section_header_entry_size: u16,
82 section_header_entry_count: u16,
83 section_header_string_table_index: u16,
84}
85#[repr(C, packed)]
86#[derive(Copy, Clone, Debug)]
87struct ElfHeader64 {
88 entry: u64,
89 program_header_offset: u64,
90 section_header_offset: u64,
91 flags: u32,
92 header_size: u16,
93 program_header_entry_size: u16,
94 program_header_entry_count: u16,
95 section_header_entry_size: u16,
96 section_header_entry_count: u16,
97 section_header_string_table_index: u16,
98}
99
100#[derive(Copy, Clone)]
101union ElfHeaderUnion {
102 header32: ElfHeader32,
103 header64: ElfHeader64,
104}
105
106#[repr(C, packed)]
107#[derive(Copy, Clone)]
108struct ElfHeader {
109 base: ElfHeaderBase,
110 header: ElfHeaderUnion,
111}
112
113#[allow(dead_code)]
114impl ElfHeader {
115 fn is_valid_and_supported(&self) -> bool {
116 if (self.base.bits != consts::BITS_32 && self.base.bits != consts::BITS_64)
117 || self.base.endianness != consts::ENDIANNESS_LITTLE
118 || self.base.version != 1
119 || self.base.abi != consts::ABI_SYSV
120 || self.base.abi_version != 0
121 || (self.base.elf_type != consts::ELF_TYPE_EXECUTABLE
122 && self.base.elf_type != consts::ELF_TYPE_SHARED)
123 || self.base.machine != consts::ELF_MACHINE_X86_64
124 || self.base.elf_version != 1
125 {
126 return false;
127 }
128 true
129 }
130
131 fn is_elf64(&self) -> bool {
132 self.base.bits == consts::BITS_64
133 }
134
135 fn is_little_endian(&self) -> bool {
136 self.base.endianness == consts::ENDIANNESS_LITTLE
137 }
138
139 fn entry(&self) -> u64 {
140 if self.is_elf64() {
141 unsafe { self.header.header64.entry }
142 } else {
143 unsafe { self.header.header32.entry as u64 }
144 }
145 }
146
147 fn program_header_offset(&self) -> u64 {
148 if self.is_elf64() {
149 unsafe { self.header.header64.program_header_offset }
150 } else {
151 unsafe { self.header.header32.program_header_offset as u64 }
152 }
153 }
154
155 fn program_header_entry_size(&self) -> u64 {
156 if self.is_elf64() {
157 unsafe { self.header.header64.program_header_entry_size as u64 }
158 } else {
159 unsafe { self.header.header32.program_header_entry_size as u64 }
160 }
161 }
162
163 fn program_header_entry_count(&self) -> u64 {
164 if self.is_elf64() {
165 unsafe { self.header.header64.program_header_entry_count as u64 }
166 } else {
167 unsafe { self.header.header32.program_header_entry_count as u64 }
168 }
169 }
170
171 fn section_header_offset(&self) -> u64 {
172 if self.is_elf64() {
173 unsafe { self.header.header64.section_header_offset }
174 } else {
175 unsafe { self.header.header32.section_header_offset as u64 }
176 }
177 }
178
179 fn section_header_entry_size(&self) -> u64 {
180 if self.is_elf64() {
181 unsafe { self.header.header64.section_header_entry_size as u64 }
182 } else {
183 unsafe { self.header.header32.section_header_entry_size as u64 }
184 }
185 }
186
187 fn section_header_entry_count(&self) -> u64 {
188 if self.is_elf64() {
189 unsafe { self.header.header64.section_header_entry_count as u64 }
190 } else {
191 unsafe { self.header.header32.section_header_entry_count as u64 }
192 }
193 }
194
195 fn section_header_string_table_index(&self) -> u64 {
196 if self.is_elf64() {
197 unsafe { self.header.header64.section_header_string_table_index as u64 }
198 } else {
199 unsafe { self.header.header32.section_header_string_table_index as u64 }
200 }
201 }
202
203 fn size_of_header(&self) -> u64 {
204 if self.is_elf64() {
205 unsafe { self.header.header64.header_size as u64 }
206 } else {
207 unsafe { self.header.header32.header_size as u64 }
208 }
209 }
210}
211
212impl fmt::Debug for ElfHeader {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 let mut s = f.debug_struct("ElfHeader");
215 s.field("base", &self.base);
216 if self.is_elf64() {
217 s.field("header64", unsafe { &self.header.header64 });
218 } else {
219 s.field("header32", unsafe { &self.header.header32 });
220 }
221 s.finish()
222 }
223}
224
225#[derive(Copy, Clone, Debug)]
226#[allow(dead_code)]
227pub enum ElfProgramType {
228 Null,
230 Load,
232 Dynamic,
234 Interpreter,
236 Note,
238 Shlib,
240 ProgramHeader,
242 ThreadLocalStorage,
244 OsSpecific(u32),
245 ProcessorSpecific(u32),
246}
247
248impl ElfProgramType {
249 pub fn from_u32(ty: u32) -> Self {
250 match ty {
251 0 => Self::Null,
252 1 => Self::Load,
253 2 => Self::Dynamic,
254 3 => Self::Interpreter,
255 4 => Self::Note,
256 5 => Self::Shlib,
257 6 => Self::ProgramHeader,
258 7 => Self::ThreadLocalStorage,
259 0x60000000..=0x6fffffff => Self::OsSpecific(ty),
260 0x70000000..=0x7fffffff => Self::ProcessorSpecific(ty),
261 _ => Self::Null,
262 }
263 }
264}
265
266#[repr(C, packed)]
267#[derive(Copy, Clone, Debug)]
268pub struct ElfProgram32 {
269 ty: u32,
271 offset: u32,
273 virtual_address: u32,
275 physical_address: u32,
277 file_size: u32,
279 mem_size: u32,
281 flags: u32,
283 alignment: u32,
285}
286
287#[repr(C, packed)]
288#[derive(Copy, Clone, Debug)]
289pub struct ElfProgram64 {
290 ty: u32,
292 flags: u32,
294 offset: u64,
296 virtual_address: u64,
298 physical_address: u64,
300 file_size: u64,
302 mem_size: u64,
304 alignment: u64,
306}
307
308#[derive(Clone, Copy)]
309pub enum ElfProgram {
310 Program32(ElfProgram32),
311 Program64(ElfProgram64),
312}
313
314impl ElfProgram {
315 pub fn load(
316 file: &mut fs::File,
317 is_elf64: bool,
318 entry_size: u64,
319 ) -> Result<Self, ElfLoadError> {
320 if is_elf64 {
321 if entry_size != mem::size_of::<ElfProgram64>() as u64 {
322 return Err(ElfLoadError::InvalidElfOrNotSupported);
323 }
324 let mut header_bytes = [0u8; mem::size_of::<ElfProgram64>()];
325 if file.read(&mut header_bytes)? != header_bytes.len() as u64 {
326 return Err(ElfLoadError::UnexpectedEndOfFile);
327 }
328 let program = unsafe { &*(header_bytes.as_ptr() as *const ElfProgram64) };
329 Ok(Self::Program64(*program))
330 } else {
331 if entry_size != mem::size_of::<ElfProgram32>() as u64 {
332 return Err(ElfLoadError::InvalidElfOrNotSupported);
333 }
334 let mut header_bytes = [0u8; mem::size_of::<ElfProgram32>()];
335 if file.read(&mut header_bytes)? != header_bytes.len() as u64 {
336 return Err(ElfLoadError::UnexpectedEndOfFile);
337 }
338 let program = unsafe { &*(header_bytes.as_ptr() as *const ElfProgram32) };
339 Ok(Self::Program32(*program))
340 }
341 }
342
343 pub fn ty(&self) -> ElfProgramType {
344 let ty_u32 = match self {
345 Self::Program32(p) => p.ty,
346 Self::Program64(p) => p.ty,
347 };
348
349 ElfProgramType::from_u32(ty_u32)
350 }
351
352 pub fn offset(&self) -> u64 {
353 match self {
354 Self::Program32(p) => p.offset as u64,
355 Self::Program64(p) => p.offset,
356 }
357 }
358
359 pub fn virtual_address(&self) -> u64 {
360 match self {
361 Self::Program32(p) => p.virtual_address as u64,
362 Self::Program64(p) => p.virtual_address,
363 }
364 }
365
366 pub fn physical_address(&self) -> u64 {
367 match self {
368 Self::Program32(p) => p.physical_address as u64,
369 Self::Program64(p) => p.physical_address,
370 }
371 }
372
373 pub fn file_size(&self) -> u64 {
374 match self {
375 Self::Program32(p) => p.file_size as u64,
376 Self::Program64(p) => p.file_size,
377 }
378 }
379
380 pub fn mem_size(&self) -> u64 {
381 match self {
382 Self::Program32(p) => p.mem_size as u64,
383 Self::Program64(p) => p.mem_size,
384 }
385 }
386
387 pub fn flags(&self) -> u32 {
388 match self {
389 Self::Program32(p) => p.flags,
390 Self::Program64(p) => p.flags,
391 }
392 }
393
394 pub fn alignment(&self) -> u64 {
395 match self {
396 Self::Program32(p) => p.alignment as u64,
397 Self::Program64(p) => p.alignment,
398 }
399 }
400}
401
402impl fmt::Debug for ElfProgram {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 f.debug_struct("ElfProgram")
405 .field("ty", &self.ty())
406 .field("flags", &self.flags())
407 .field("offset", &self.offset())
408 .field("virtual_address", &self.virtual_address())
409 .field("physical_address", &self.physical_address())
410 .field("file_size", &self.file_size())
411 .field("mem_size", &self.mem_size())
412 .field("alignment", &self.alignment())
413 .finish()
414 }
415}
416
417#[allow(dead_code)]
418#[derive(Copy, Clone, Debug)]
419pub enum ElfSectionType {
420 Null,
422 ProgramBits,
424 SymbolTable,
426 StringTable,
428 Rela,
430 Hash,
432 Dynamic,
434 Note,
436 NoBits,
438 Rel,
440 Shlib,
442 DynamicSymbols,
444 InitArray,
446 FiniArray,
448 PreInitArray,
450 Group,
452 ExtendedSymbolTableIndices,
454 Num,
456 Other(u32),
458}
459
460impl ElfSectionType {
461 pub fn from_u32(ty: u32) -> Self {
462 match ty {
463 0 => Self::Null,
464 1 => Self::ProgramBits,
465 2 => Self::SymbolTable,
466 3 => Self::StringTable,
467 4 => Self::Rela,
468 5 => Self::Hash,
469 6 => Self::Dynamic,
470 7 => Self::Note,
471 8 => Self::NoBits,
472 9 => Self::Rel,
473 10 => Self::Shlib,
474 11 => Self::DynamicSymbols,
475 14 => Self::InitArray,
476 15 => Self::FiniArray,
477 16 => Self::PreInitArray,
478 17 => Self::Group,
479 18 => Self::ExtendedSymbolTableIndices,
480 19 => Self::Num,
481 0x60000000..=0x6fffffff => Self::Other(ty),
482 _ => Self::Null,
483 }
484 }
485}
486
487#[repr(C, packed)]
488#[derive(Copy, Clone, Debug)]
489pub struct ElfSection32 {
490 name: u32,
492 ty: u32,
494 flags: u32,
496 address: u32,
498 offset: u32,
500 size: u32,
502 link: u32,
504 info: u32,
506 alignment: u32,
508 entry_size: u32,
510}
511
512#[repr(C, packed)]
513#[derive(Copy, Clone, Debug)]
514pub struct ElfSection64 {
515 name: u32,
517 ty: u32,
519 flags: u64,
521 address: u64,
523 offset: u64,
525 size: u64,
527 link: u32,
529 info: u32,
531 alignment: u64,
533 entry_size: u64,
535}
536
537#[derive(Clone, Copy)]
538pub enum ElfSectionInner {
539 Section32(ElfSection32),
540 Section64(ElfSection64),
541}
542
543impl ElfSectionInner {
544 pub fn load(
545 file: &mut fs::File,
546 is_elf64: bool,
547 entry_size: u64,
548 ) -> Result<Self, ElfLoadError> {
549 if is_elf64 {
550 if entry_size != mem::size_of::<ElfSection64>() as u64 {
551 return Err(ElfLoadError::InvalidElfOrNotSupported);
552 }
553 let mut header_bytes = [0u8; mem::size_of::<ElfSection64>()];
554 if file.read(&mut header_bytes)? != header_bytes.len() as u64 {
555 return Err(ElfLoadError::UnexpectedEndOfFile);
556 }
557 let section = unsafe { *(header_bytes.as_ptr() as *const ElfSection64) };
558 Ok(Self::Section64(section))
559 } else {
560 if entry_size != mem::size_of::<ElfSection32>() as u64 {
561 return Err(ElfLoadError::InvalidElfOrNotSupported);
562 }
563 let mut header_bytes = [0u8; mem::size_of::<ElfSection32>()];
564 if file.read(&mut header_bytes)? != header_bytes.len() as u64 {
565 return Err(ElfLoadError::UnexpectedEndOfFile);
566 }
567 let section = unsafe { *(header_bytes.as_ptr() as *const ElfSection32) };
568 Ok(Self::Section32(section))
569 }
570 }
571
572 pub fn name_index(&self) -> u32 {
573 match self {
574 Self::Section32(s) => s.name,
575 Self::Section64(s) => s.name,
576 }
577 }
578
579 pub fn ty(&self) -> ElfSectionType {
580 let ty_u32 = match self {
581 Self::Section32(s) => s.ty,
582 Self::Section64(s) => s.ty,
583 };
584
585 ElfSectionType::from_u32(ty_u32)
586 }
587
588 pub fn flags(&self) -> u64 {
589 match self {
590 Self::Section32(s) => s.flags as u64,
591 Self::Section64(s) => s.flags,
592 }
593 }
594
595 pub fn offset(&self) -> u64 {
596 match self {
597 Self::Section32(s) => s.offset as u64,
598 Self::Section64(s) => s.offset,
599 }
600 }
601
602 pub fn address(&self) -> u64 {
603 match self {
604 Self::Section32(s) => s.address as u64,
605 Self::Section64(s) => s.address,
606 }
607 }
608
609 pub fn size(&self) -> u64 {
610 match self {
611 Self::Section32(s) => s.size as u64,
612 Self::Section64(s) => s.size,
613 }
614 }
615
616 pub fn link(&self) -> u64 {
617 match self {
618 Self::Section32(s) => s.link as u64,
619 Self::Section64(s) => s.link as u64,
620 }
621 }
622
623 pub fn info(&self) -> u64 {
624 match self {
625 Self::Section32(s) => s.info as u64,
626 Self::Section64(s) => s.info as u64,
627 }
628 }
629
630 pub fn alignment(&self) -> u64 {
631 match self {
632 Self::Section32(s) => s.alignment as u64,
633 Self::Section64(s) => s.alignment,
634 }
635 }
636
637 pub fn entry_size(&self) -> u64 {
638 match self {
639 Self::Section32(s) => s.entry_size as u64,
640 Self::Section64(s) => s.entry_size,
641 }
642 }
643}
644
645#[derive(Clone)]
646pub struct ElfSection {
647 name: String,
648 inner: ElfSectionInner,
649}
650
651impl ElfSection {
652 pub fn new(inner: ElfSectionInner, string_table: &[u8]) -> Self {
653 let name_index = inner.name_index();
654 let name = String::from(
655 CStr::from_bytes_until_nul(&string_table[name_index as usize..])
656 .unwrap()
657 .to_str()
658 .unwrap(),
659 );
660 Self { name, inner }
661 }
662
663 pub fn name(&self) -> &str {
664 &self.name
665 }
666}
667
668impl fmt::Debug for ElfSection {
669 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
670 f.debug_struct("ElfSection")
671 .field("name", &self.name)
672 .field("type", &self.inner.ty())
673 .field("flags", &self.inner.flags())
674 .field("offset", &self.inner.offset())
675 .field("address", &self.inner.address())
676 .field("size", &self.inner.size())
677 .field("link", &self.inner.link())
678 .field("info", &self.inner.info())
679 .field("alignment", &self.inner.alignment())
680 .field("entry_size", &self.inner.entry_size())
681 .finish()
682 }
683}
684
685impl Deref for ElfSection {
686 type Target = ElfSectionInner;
687
688 fn deref(&self) -> &Self::Target {
689 &self.inner
690 }
691}
692
693#[derive(Debug)]
694pub struct Elf {
695 header: ElfHeader,
696 program_headers: Vec<ElfProgram>,
697 sections: Vec<ElfSection>,
698}
699
700impl Elf {
701 pub fn load(file: &mut fs::File) -> Result<Self, ElfLoadError> {
702 let mut header = [0u8; mem::size_of::<ElfHeader>()];
704 if file.read(&mut header)? != header.len() as u64 {
705 return Err(ElfLoadError::UnexpectedEndOfFile);
706 }
707 let header = unsafe { *(header.as_ptr() as *const ElfHeader) };
708
709 if &header.base.magic != consts::ELF_MAGIC {
710 return Err(ElfLoadError::InvalidMagic);
711 }
712 if !header.is_valid_and_supported() {
713 return Err(ElfLoadError::InvalidElfOrNotSupported);
714 }
715 file.seek(header.program_header_offset())?;
716 let mut program_headers = Vec::with_capacity(header.program_header_entry_count() as usize);
717
718 for _ in 0..header.program_header_entry_count() {
719 let program =
720 ElfProgram::load(file, header.is_elf64(), header.program_header_entry_size())?;
721 program_headers.push(program);
722 }
723
724 let string_table_index = header.section_header_string_table_index() as usize;
725 assert!(string_table_index < header.section_header_entry_count() as usize);
726 let string_table_position = header.section_header_offset()
727 + header.section_header_entry_size() * string_table_index as u64;
728 file.seek(string_table_position)?;
729 let string_table_section =
730 ElfSectionInner::load(file, header.is_elf64(), header.section_header_entry_size())?;
731 let mut string_table = vec![0u8; string_table_section.size() as usize];
732 file.seek(string_table_section.offset())?;
733 file.read(&mut string_table)?;
734
735 file.seek(header.section_header_offset())?;
736 let mut sections = Vec::with_capacity(header.section_header_entry_count() as usize);
737 for _ in 0..header.section_header_entry_count() {
738 let section_inner =
739 ElfSectionInner::load(file, header.is_elf64(), header.section_header_entry_size())?;
740 let section = ElfSection::new(section_inner, &string_table);
741 sections.push(section);
742 }
743
744 Ok(Self {
745 header,
746 program_headers,
747 sections,
748 })
749 }
750
751 pub fn entry_point(&self) -> u64 {
752 self.header.entry()
753 }
754
755 pub fn program_headers(&self) -> &[ElfProgram] {
756 &self.program_headers
757 }
758
759 pub fn sections(&self) -> &[ElfSection] {
760 &self.sections
761 }
762}