use std::path::PathBuf; use elf_utilities::{ file::{ELF64Dumper, ELF64}, section::Section64, segment::{Segment64, Type}, }; use crate::{ common::{Output, Section, SectionInfo}, error::Error, }; use super::ElfObject; pub struct ElfOutput<'data> { destination: PathBuf, dump: ELF64Dumper, text: Vec>, data: Vec>, bss: Vec>, } impl ElfOutput<'_> { pub fn new(destination: PathBuf) -> Self { use elf_utilities::header::{Class, Data, Machine, Type, Version, OSABI}; let mut elf = ELF64::default(); elf.ehdr.set_elf_type(Type::Exec); elf.ehdr.set_class(Class::Bit64); elf.ehdr.set_machine(Machine::Intel386); elf.ehdr.set_object_version(Version::Current); elf.ehdr.set_file_version(Version::Current); elf.ehdr.set_osabi(OSABI::Linux); elf.ehdr.set_data(Data::LSB2); Self { destination, dump: ELF64Dumper::new(elf), text: Vec::new(), data: Vec::new(), bss: Vec::new(), } } pub fn from_object(object: &ElfObject, destination: PathBuf) -> Self { use elf_utilities::header::Type; let other = object.elf(); let mut elf = ELF64::default(); elf.ehdr = other.ehdr.clone(); elf.ehdr.set_elf_type(Type::Exec); Self { destination, dump: ELF64Dumper::new(elf), text: Vec::new(), data: Vec::new(), bss: Vec::new(), } } fn populate_section_data(&mut self) -> Result { use elf_utilities::section::{Contents64, Shdr64, Type}; let mut data = Vec::new(); for t in self.text.iter_mut() { if let Some(iter) = &mut t.data { data.extend(iter.as_mut()); } } let mut header = Shdr64::default(); header.set_type(Type::ProgBits); header.sh_entsize = data.len() as u64; let sec64 = Section64 { name: ".text".into(), header, contents: Contents64::Raw(data), }; self.dump.file.add_section(sec64); Ok(0) } } impl<'data> Output<'data> for ElfOutput<'data> { fn allocate(&mut self, size: u64) -> Result { Ok(size) } fn append_section(&mut self, section: Section<'data>) -> Result<(), Error> { match section { Section::Text(si) => self.text.push(si), Section::Data(si) => self.data.push(si), Section::Bss(si) => self.bss.push(si), } Ok(()) } fn finalize(mut self) -> Result { use std::io::Error as IOError; use std::io::ErrorKind; self.populate_section_data()?; let mut segment = Segment64::default(); segment.header.set_type(Type::Load); self.dump.file.segments.push(segment); self.dump.file.finalize(); let str_path = self.destination.to_str().ok_or_else(|| { let ioe = IOError::new(ErrorKind::Other, "Path expansion fail"); let boxed = Box::new(ioe); Error::IOError(boxed) })?; self.dump .generate_elf_file(str_path, 0o755) .map_err(|e| Error::IOError(e))?; Ok(self.destination) } }