diff --git a/src/common.rs b/src/common.rs index 143634f..899073c 100644 --- a/src/common.rs +++ b/src/common.rs @@ -2,12 +2,10 @@ mod lazy; mod output; mod relocatable; mod section; -mod storage; mod symbol; pub use lazy::*; pub use output::*; pub use relocatable::*; pub use section::*; -pub use storage::*; pub use symbol::*; diff --git a/src/common/output.rs b/src/common/output.rs index 46532f7..492034f 100644 --- a/src/common/output.rs +++ b/src/common/output.rs @@ -4,9 +4,7 @@ use super::Section; use crate::error::Error; pub trait Output<'data> { - fn append_section(&mut self, section: Section<'data>) -> Result<(), Error>; - - // fn prepare_symbol(&mut self, symbol: impl Lazy) -> Result<&mut Self, Error>; + fn process_section(&mut self, section: Section<'data>) -> Result<(), Error>; fn finalize(self) -> Result; } @@ -14,7 +12,7 @@ pub trait Output<'data> { pub struct DummyOutput; impl<'data> Output<'data> for DummyOutput { - fn append_section(&mut self, section: Section<'data>) -> Result<(), Error> { + fn process_section(&mut self, section: Section<'data>) -> Result<(), Error> { eprintln!("Appending section: {}", section); Ok(()) } diff --git a/src/common/relocatable.rs b/src/common/relocatable.rs index c7bdb9f..77f4ad9 100644 --- a/src/common/relocatable.rs +++ b/src/common/relocatable.rs @@ -1,15 +1,15 @@ -use std::fmt::Display; use std::path::Path; +use std::{convert::TryFrom, fmt::Display, path::PathBuf}; use crate::error::Error; use super::Section; -pub type BSI<'data> = Box, Error>> + 'data>; +pub type BSI<'iter, 'data> = Box, Error>> + 'iter>; /// Contains all the needed getters to construct a final /// mushed and relocated executable from an object file -pub trait Relocatable: Display { +pub trait Relocatable<'data>: Display + TryFrom { fn origin(&self) -> &Path; // not same as section's path since this one's supposed to be cannonical - fn sections(&self) -> BSI<'_>; + fn sections<'sections>(self: &'sections Self) -> BSI<'sections, 'data>; } diff --git a/src/common/storage.rs b/src/common/storage.rs deleted file mode 100644 index 99ebd83..0000000 --- a/src/common/storage.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::path::PathBuf; -use std::{fs::canonicalize, io::ErrorKind}; - -use crate::error::Error; - -pub struct Storage { - origin: PathBuf, - bytes: Vec, // for storing the total if needed -} - -impl Storage { - pub fn new(origin: PathBuf) -> Self { - Self { - origin, - bytes: Vec::new(), - } - } - - pub fn origin(&self) -> Result { - canonicalize(&self.origin).map_err(|e| e.into()) - } - - pub fn destination(&self) -> Result { - 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))) - } else { - dest.push("rld.out"); - Ok(dest) - } - } - - pub fn iter(&mut self) -> Result, Error> { - self.bytes = std::fs::read(&self.origin)?; - - Ok(self.bytes.iter()) - } - - pub fn bytes(&mut self) -> Result<&[u8], Error> { - self.bytes = std::fs::read(&self.origin)?; - - Ok(&self.bytes) - } -} diff --git a/src/formats/elf.rs b/src/formats/elf.rs index ddd8ade..b40d322 100644 --- a/src/formats/elf.rs +++ b/src/formats/elf.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use crate::common::{Lazy, Symbol}; use crate::error::Error; use crate::linker::Linker; @@ -10,10 +12,10 @@ use elf_utilities::file::ELF64; pub use object::*; pub use output::*; -impl Linker<'_> { +impl<'data> Linker<'data, ElfObject, ElfOutput<'data>> { // shortcut to avoid turbofish - pub fn elf() -> Self { - Self::new(Vec::new()) + pub fn elf(destination: PathBuf) -> Result { + Ok(Self::new(ElfOutput::new(destination)?)) } } diff --git a/src/formats/elf/object.rs b/src/formats/elf/object.rs index 1389f58..537e0e8 100644 --- a/src/formats/elf/object.rs +++ b/src/formats/elf/object.rs @@ -1,10 +1,6 @@ -use std::{ - convert::TryFrom, - fmt::Display, - path::{Path, PathBuf}, -}; +use std::{convert::TryFrom, fmt::Display, path::{Path, PathBuf}}; -use crate::common::{Relocatable, Section, SectionInfo, Storage}; +use crate::common::{Relocatable, Section, SectionInfo}; use crate::{common::BSI, error::Error}; use elf_utilities::{file::ELF64, parser::read_elf64}; @@ -14,8 +10,7 @@ pub struct ElfObject { } impl ElfObject { - pub fn new(storage: &mut Storage) -> Result { - let origin = storage.origin()?; + pub fn new(origin: PathBuf) -> Result { let str_origin = origin .as_path() .to_str() @@ -36,12 +31,12 @@ impl ElfObject { } } -impl Relocatable for ElfObject { +impl<'data> Relocatable<'data> for ElfObject { fn origin(&self) -> &Path { &self.origin } - fn sections(&self) -> BSI<'_> { + fn sections<'sections>(self: &'sections Self) -> BSI<'sections, 'data> { use elf_utilities::section::{Contents64, Type}; let iter = self @@ -104,6 +99,14 @@ impl Display for ElfObject { } } +impl TryFrom for ElfObject { + type Error = Error; + + fn try_from(path: PathBuf) -> Result { + Self::new(path) + } +} + fn is_relocatable(elf: &ELF64) -> Result<(), Error> { use elf_utilities::header::Type; diff --git a/src/formats/elf/output.rs b/src/formats/elf/output.rs index 1f43099..addcc5f 100644 --- a/src/formats/elf/output.rs +++ b/src/formats/elf/output.rs @@ -24,8 +24,8 @@ use super::ElfObject; pub struct ElfOutput<'data> { destination: PathBuf, - file: ELF64, - input_data: InputData<'data>, + file: ELF64, + input_data: OutputData<'data>, writer: BufWriter, } @@ -48,7 +48,7 @@ impl<'data> ElfOutput<'data> { let result = Self { destination, file: elf, - input_data: InputData::new(), + input_data: OutputData::new(), writer, }; @@ -64,7 +64,7 @@ impl<'data> ElfOutput<'data> { let result = Self { destination, file: elf_bin_from_object(other), - input_data: InputData::new(), + input_data: OutputData::new(), writer, }; @@ -84,7 +84,7 @@ impl<'data> ElfOutput<'data> { } } - if data_size == 0{ + if data_size == 0 { continue; } @@ -153,11 +153,7 @@ impl<'data> ElfOutput<'data> { SegmentType::Text, ); // contains .data as one segment - self.populate_segment( - &mut offset, - self.input_data.data_size(), - SegmentType::Data, - ); + self.populate_segment(&mut offset, self.input_data.data_size(), SegmentType::Data); // contains .bss as one segment self.populate_segment(&mut offset, self.input_data.bss_size(), SegmentType::Bss); @@ -166,7 +162,7 @@ impl<'data> ElfOutput<'data> { } impl<'data> Output<'data> for ElfOutput<'data> { - fn append_section(&mut self, section: Section<'data>) -> Result<(), Error> { + fn process_section(&mut self, section: Section<'data>) -> Result<(), Error> { self.input_data.append_section(section) } @@ -183,7 +179,8 @@ impl<'data> Output<'data> for ElfOutput<'data> { self.file.ehdr.e_phentsize = PHS; self.file.ehdr.e_shentsize = SHS; self.file.ehdr.e_phoff = EHS; - self.file.ehdr.e_shoff = self.file.ehdr.e_phoff + (usize::from(self.file.ehdr.e_phentsize) * self.file.segments.len()) as u64; + self.file.ehdr.e_shoff = self.file.ehdr.e_phoff + + (usize::from(self.file.ehdr.e_phentsize) * self.file.segments.len()) as u64; let mut offset = 0; diff --git a/src/formats/elf/segment.rs b/src/formats/elf/segment.rs index 56a3ff6..ae6cd4e 100644 --- a/src/formats/elf/segment.rs +++ b/src/formats/elf/segment.rs @@ -1,5 +1,5 @@ +use crate::common::Section; use crate::common::SectionInfo; -use crate::common::{Section}; use crate::error::Error; const SI_TEXT: usize = 0; @@ -15,9 +15,9 @@ pub enum SegmentType { const SEGMENT_NAMES: [&str; 4] = [".text", ".rodata", ".data", ".bss"]; -pub struct InputData<'data>([Vec>; 4]); +pub struct OutputData<'data>([Vec>; 4]); -impl<'data> InputData<'data> { +impl<'data> OutputData<'data> { pub fn new() -> Self { Self([Vec::new(), Vec::new(), Vec::new(), Vec::new()]) } @@ -90,7 +90,7 @@ impl<'data> InputData<'data> { } } -impl Default for InputData<'_> { +impl Default for OutputData<'_> { fn default() -> Self { Self::new() } diff --git a/src/linker.rs b/src/linker.rs index 3a9cd94..3a8cf8b 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -1,35 +1,66 @@ -use std::fmt::Display; +use std::{fmt::Display, io::ErrorKind, marker::PhantomData, path::{Path, PathBuf}}; use crate::{ common::{Output, Relocatable}, error::Error, }; -pub struct Linker<'data> { - relocatables: Vec>, +pub struct Linker<'data, R, O> +where + R: Relocatable<'data>, + O: Output<'data>, +{ + relocatables: Vec, + output: O, + _p: PhantomData<&'data ()>, } -impl<'data> Linker<'data> { - pub fn new(relocatables: Vec>) -> Self { - Self { relocatables } +impl<'data, R, O> Linker<'data, R, O> +where + R: Relocatable<'data>, + O: Output<'data>, +{ + pub fn new(output: O) -> Self { + Self { + relocatables: Vec::new(), + output, + _p: PhantomData::default(), + } } - pub fn add_relocatable(&mut self, relocatable: Box) { - self.relocatables.push(relocatable); + pub fn add_relocatable(&mut self, path: PathBuf) -> Result<(), Error> { + self.relocatables.push(R::try_from(path)?); + + Ok(()) } - pub fn link(&'data self, output: &mut dyn Output<'data>) -> Result { + pub fn link(&mut self) -> Result { for r in self.relocatables.iter() { for s in r.sections() { - output.append_section(s?)?; + self.output.process_section(s?)?; } } - Ok(0) + self.output.finalize() + } + + pub fn object_path(origin: &Path) -> Result { + let mut dest = std::fs::canonicalize(origin)?; + if !dest.pop() { + let err = std::io::Error::new(ErrorKind::Other, "Destination path invalid"); + Err(Error::IOError(Box::new(err))) + } else { + dest.push("rld.out"); + Ok(dest) + } } } -impl Display for Linker<'_> { +impl<'data, R, O> Display for Linker<'data, R, O> +where + R: Relocatable<'data>, + O: Output<'data>, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "===Relocatables===")?; diff --git a/src/main.rs b/src/main.rs index 56b98c3..7949d0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,8 @@ mod error; mod formats; mod linker; -use common::{Output, Storage}; -use formats::{ElfObject, ElfOutput}; +use std::path::PathBuf; + use linker::Linker; fn main() { @@ -13,31 +13,15 @@ fn main() { // can this miss? args.next().unwrap(); - let mut contents: Vec = Vec::new(); - let mut linker = Linker::elf(); - let mut maybe_out = None; + let destination = PathBuf::new(); // TODO + let mut linker = Linker::elf(destination).expect("Linker init"); while args.peek().is_some() { - let fpath = args.next().expect("Unexpected peek-a-boo"); - let stored = Storage::new(fpath.into()); - contents.push(stored); - } + let path = PathBuf::from(args.next().expect("Argument expansion")); - for storage in contents.iter_mut() { - let relocatable = ElfObject::new(storage).expect("Parsing ELF"); - - if maybe_out.is_none() { - let dest = storage.destination().expect("Path resolution"); - maybe_out = Some(ElfOutput::from_object(&relocatable, dest).expect("Output file creation")); - } - linker.add_relocatable(Box::new(relocatable)); + linker.add_relocatable(path); } - if let Some(mut output) = maybe_out { - let linked = linker.link(&mut output).expect("Linking"); - let outpath = output.finalize().expect("Finalization"); - eprintln!("Done {:?}, linked {} bytes", outpath, linked); - } else { - eprintln!("Nothing to do"); - } + let outpath = linker.link().expect("Linking"); + eprintln!("Done {:?}", outpath); }