From dd255aa67f0264d75ea467ab37273fdddff8768d Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Fri, 1 Jan 2021 15:47:07 -0800 Subject: [PATCH] WIP --- src/common/section.rs | 13 ++-- src/common/storage.rs | 2 +- src/formats/elf.rs | 1 + src/formats/elf/output.rs | 125 ++++++++++++++++++++++---------------- 4 files changed, 83 insertions(+), 58 deletions(-) diff --git a/src/common/section.rs b/src/common/section.rs index e362456..23e2a37 100644 --- a/src/common/section.rs +++ b/src/common/section.rs @@ -14,7 +14,7 @@ pub struct SectionInfo<'data> { pub enum Section<'data> { Text(SectionInfo<'data>), - Data(SectionInfo<'data>), + Data(SectionInfo<'data>, bool), // readonly bool Bss(SectionInfo<'data>), } @@ -22,7 +22,7 @@ impl Section<'_> { pub fn size(&self) -> Result { match self { Section::Text(s) => Ok(s.size), - Section::Data(s) => Ok(s.size), + Section::Data(s, _) => Ok(s.size), Section::Bss(s) => Ok(s.size), } } @@ -34,8 +34,10 @@ impl<'data> TryFrom<(&str, SectionInfo<'data>)> for Section<'data> { fn try_from(value: (&str, SectionInfo<'data>)) -> Result { if value.0.starts_with(".text") { Ok(Section::Text(value.1)) - } else if value.0.starts_with(".rodata") || value.0.starts_with(".data") { - Ok(Section::Data(value.1)) + } else if value.0.starts_with(".rodata") { + Ok(Section::Data(value.1, true)) + } else if value.0.starts_with(".data") { + Ok(Section::Data(value.1, false)) } else if value.0.starts_with(".bss") { Ok(Section::Bss(value.1)) } else { @@ -60,7 +62,8 @@ impl Display for Section<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Section::Text(s) => writeln!(f, "TEXT {}", s), - Section::Data(s) => writeln!(f, "DATA {}", s), + Section::Data(s, false) => writeln!(f, "DATA {}", s), + Section::Data(s, true) => writeln!(f, "RO-DATA {}", s), Section::Bss(s) => writeln!(f, "BSS {}", s), } } diff --git a/src/common/storage.rs b/src/common/storage.rs index 97d4d75..99ebd83 100644 --- a/src/common/storage.rs +++ b/src/common/storage.rs @@ -21,7 +21,7 @@ impl Storage { } pub fn destination(&self) -> Result { - let mut dest = canonicalize(&self.origin).map_err(|e| Error::from(e))?; + let mut dest = canonicalize(&self.origin)?; if !dest.pop() { let err = std::io::Error::new(ErrorKind::Other, "Destination path invalid"); Err(Error::IOError(Box::new(err))) diff --git a/src/formats/elf.rs b/src/formats/elf.rs index 4cfdb88..b262d5e 100644 --- a/src/formats/elf.rs +++ b/src/formats/elf.rs @@ -4,6 +4,7 @@ use crate::linker::Linker; mod object; mod output; +mod segment; use elf_utilities::file::ELF64; pub use object::*; diff --git a/src/formats/elf/output.rs b/src/formats/elf/output.rs index 2004c64..cf7a36b 100644 --- a/src/formats/elf/output.rs +++ b/src/formats/elf/output.rs @@ -1,27 +1,22 @@ use std::path::PathBuf; -use elf_utilities::{ - file::{ELF64Dumper, ELF64}, - section::Section64, - segment::{Segment64, Type}, -}; +use elf_utilities::file::{ELF64Dumper, ELF64}; use crate::{ - common::{Output, Section, SectionInfo}, + common::{Output, Section}, error::Error, }; +use super::segment::*; use super::ElfObject; pub struct ElfOutput<'data> { destination: PathBuf, - dump: ELF64Dumper, - text: Vec>, - data: Vec>, - bss: Vec>, + file: ELF64, + segment_data: SegmentData<'data>, } -impl ElfOutput<'_> { +impl<'data> ElfOutput<'data> { pub fn new(destination: PathBuf) -> Self { use elf_utilities::header::{Class, Data, Machine, Type, Version, OSABI}; @@ -36,53 +31,73 @@ impl ElfOutput<'_> { Self { destination, - dump: ELF64Dumper::new(elf), - text: Vec::new(), - data: Vec::new(), - bss: Vec::new(), + file: elf, + segment_data: SegmentData::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(), + file: elf_bin_from_object(other), + segment_data: SegmentData::new(), } } - fn populate_section_data(&mut self) -> Result { - use elf_utilities::section::{Contents64, Shdr64, Type}; + fn populate_sections(&mut self) -> Result { + use elf_utilities::section::{Contents64, Section64, Shdr64}; - let mut data = Vec::new(); + for (name, sections) in self.segment_data.iter_mut() { + let mut data = Vec::new(); - for t in self.text.iter_mut() { - if let Some(iter) = &mut t.data { - data.extend(iter.as_mut()); + for t in sections.iter_mut() { + if let Some(iter) = &mut t.data { + data.extend(iter.as_mut()); + } } + + let section = Section64 { + name: name.into(), + header: Shdr64::default(), + contents: Contents64::Raw(data), + }; + self.file.add_section(section); } - let mut header = Shdr64::default(); - header.set_type(Type::ProgBits); - header.sh_entsize = data.len() as u64; + Ok(0) + } - let sec64 = Section64 { - name: ".text".into(), - header, - contents: Contents64::Raw(data), + fn populate_segment(&mut self, offset: &mut u64, size: u64) { + use elf_utilities::segment::{Phdr64, Segment64, Type}; + use std::mem::size_of; + + let mut segment = Segment64 { + header: Phdr64::default(), }; + segment.header.set_type(Type::Load); + segment.header.p_filesz = size; + segment.header.p_memsz = size; + segment.header.p_offset = *offset; - self.dump.file.add_section(sec64); + // TODO: elfix - add to elf-utilities as add_segment + self.file.segments.push(segment); + self.file.ehdr.e_phnum += 1; + self.file.ehdr.e_phentsize = size_of::() as u16; + + *offset += size; + } + + fn populate_segments(&mut self) -> Result { + let mut offset = 0u64; + // program header/segments + // contains .text + .rodata as one segment + self.populate_segment(&mut offset, self.segment_data.program_size()); + // contains .data as one segment + self.populate_segment(&mut offset, self.segment_data.data_size()); + // contains .bss as one segment + self.populate_segment(&mut offset, self.segment_data.bss_size()); Ok(0) } @@ -94,24 +109,16 @@ impl<'data> Output<'data> for ElfOutput<'data> { } 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(()) + self.segment_data.append_section(section) } 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(); + self.populate_sections()?; + self.populate_segments()?; + self.file.finalize(); let str_path = self.destination.to_str().ok_or_else(|| { let ioe = IOError::new(ErrorKind::Other, "Path expansion fail"); @@ -119,10 +126,24 @@ impl<'data> Output<'data> for ElfOutput<'data> { Error::IOError(boxed) })?; - self.dump + ELF64Dumper::new(self.file) .generate_elf_file(str_path, 0o755) .map_err(|e| Error::IOError(e))?; Ok(self.destination) } } + +// init new ELF64 from an object file meant as executable output +fn elf_bin_from_object(other: &ELF64) -> ELF64 { + use elf_utilities::header::Type; + + let mut elf = ELF64::default(); + elf.ehdr.set_elf_type(Type::Exec); + elf.ehdr.e_ehsize = other.ehdr.e_ehsize; + elf.ehdr.e_version = other.ehdr.e_version; + elf.ehdr.e_ident = other.ehdr.e_ident; + elf.ehdr.e_machine = other.ehdr.e_machine; + + elf +} \ No newline at end of file