master
Ales Katona 4 years ago
parent 77b97859df
commit e52e3a2761
Signed by: almindor
GPG Key ID: 2F773149BF38B48F

@ -2,12 +2,10 @@ mod lazy;
mod output; mod output;
mod relocatable; mod relocatable;
mod section; mod section;
mod storage;
mod symbol; mod symbol;
pub use lazy::*; pub use lazy::*;
pub use output::*; pub use output::*;
pub use relocatable::*; pub use relocatable::*;
pub use section::*; pub use section::*;
pub use storage::*;
pub use symbol::*; pub use symbol::*;

@ -4,9 +4,7 @@ use super::Section;
use crate::error::Error; use crate::error::Error;
pub trait Output<'data> { pub trait Output<'data> {
fn append_section(&mut self, section: Section<'data>) -> Result<(), Error>; fn process_section(&mut self, section: Section<'data>) -> Result<(), Error>;
// fn prepare_symbol<V, S>(&mut self, symbol: impl Lazy<V, S>) -> Result<&mut Self, Error>;
fn finalize(self) -> Result<PathBuf, Error>; fn finalize(self) -> Result<PathBuf, Error>;
} }
@ -14,7 +12,7 @@ pub trait Output<'data> {
pub struct DummyOutput; pub struct DummyOutput;
impl<'data> Output<'data> for 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); eprintln!("Appending section: {}", section);
Ok(()) Ok(())
} }

@ -1,15 +1,15 @@
use std::fmt::Display;
use std::path::Path; use std::path::Path;
use std::{convert::TryFrom, fmt::Display, path::PathBuf};
use crate::error::Error; use crate::error::Error;
use super::Section; use super::Section;
pub type BSI<'data> = Box<dyn Iterator<Item = Result<Section<'data>, Error>> + 'data>; pub type BSI<'iter, 'data> = Box<dyn Iterator<Item = Result<Section<'data>, Error>> + 'iter>;
/// Contains all the needed getters to construct a final /// Contains all the needed getters to construct a final
/// mushed and relocated executable from an object file /// mushed and relocated executable from an object file
pub trait Relocatable: Display { pub trait Relocatable<'data>: Display + TryFrom<PathBuf, Error = Error> {
fn origin(&self) -> &Path; // not same as section's path since this one's supposed to be cannonical 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>;
} }

@ -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<u8>, // for storing the total if needed
}
impl Storage {
pub fn new(origin: PathBuf) -> Self {
Self {
origin,
bytes: Vec::new(),
}
}
pub fn origin(&self) -> Result<PathBuf, Error> {
canonicalize(&self.origin).map_err(|e| e.into())
}
pub fn destination(&self) -> Result<PathBuf, Error> {
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<impl Iterator<Item = &u8>, 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)
}
}

@ -1,3 +1,5 @@
use std::path::PathBuf;
use crate::common::{Lazy, Symbol}; use crate::common::{Lazy, Symbol};
use crate::error::Error; use crate::error::Error;
use crate::linker::Linker; use crate::linker::Linker;
@ -10,10 +12,10 @@ use elf_utilities::file::ELF64;
pub use object::*; pub use object::*;
pub use output::*; pub use output::*;
impl Linker<'_> { impl<'data> Linker<'data, ElfObject, ElfOutput<'data>> {
// shortcut to avoid turbofish // shortcut to avoid turbofish
pub fn elf() -> Self { pub fn elf(destination: PathBuf) -> Result<Self, Error> {
Self::new(Vec::new()) Ok(Self::new(ElfOutput::new(destination)?))
} }
} }

@ -1,10 +1,6 @@
use std::{ use std::{convert::TryFrom, fmt::Display, path::{Path, PathBuf}};
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 crate::{common::BSI, error::Error};
use elf_utilities::{file::ELF64, parser::read_elf64}; use elf_utilities::{file::ELF64, parser::read_elf64};
@ -14,8 +10,7 @@ pub struct ElfObject {
} }
impl ElfObject { impl ElfObject {
pub fn new(storage: &mut Storage) -> Result<Self, Error> { pub fn new(origin: PathBuf) -> Result<Self, Error> {
let origin = storage.origin()?;
let str_origin = origin let str_origin = origin
.as_path() .as_path()
.to_str() .to_str()
@ -36,12 +31,12 @@ impl ElfObject {
} }
} }
impl Relocatable for ElfObject { impl<'data> Relocatable<'data> for ElfObject {
fn origin(&self) -> &Path { fn origin(&self) -> &Path {
&self.origin &self.origin
} }
fn sections(&self) -> BSI<'_> { fn sections<'sections>(self: &'sections Self) -> BSI<'sections, 'data> {
use elf_utilities::section::{Contents64, Type}; use elf_utilities::section::{Contents64, Type};
let iter = self let iter = self
@ -104,6 +99,14 @@ impl Display for ElfObject {
} }
} }
impl TryFrom<PathBuf> for ElfObject {
type Error = Error;
fn try_from(path: PathBuf) -> Result<Self, Self::Error> {
Self::new(path)
}
}
fn is_relocatable(elf: &ELF64) -> Result<(), Error> { fn is_relocatable(elf: &ELF64) -> Result<(), Error> {
use elf_utilities::header::Type; use elf_utilities::header::Type;

@ -24,8 +24,8 @@ use super::ElfObject;
pub struct ElfOutput<'data> { pub struct ElfOutput<'data> {
destination: PathBuf, destination: PathBuf,
file: ELF64, file: ELF64,
input_data: InputData<'data>, input_data: OutputData<'data>,
writer: BufWriter<File>, writer: BufWriter<File>,
} }
@ -48,7 +48,7 @@ impl<'data> ElfOutput<'data> {
let result = Self { let result = Self {
destination, destination,
file: elf, file: elf,
input_data: InputData::new(), input_data: OutputData::new(),
writer, writer,
}; };
@ -64,7 +64,7 @@ impl<'data> ElfOutput<'data> {
let result = Self { let result = Self {
destination, destination,
file: elf_bin_from_object(other), file: elf_bin_from_object(other),
input_data: InputData::new(), input_data: OutputData::new(),
writer, writer,
}; };
@ -84,7 +84,7 @@ impl<'data> ElfOutput<'data> {
} }
} }
if data_size == 0{ if data_size == 0 {
continue; continue;
} }
@ -153,11 +153,7 @@ impl<'data> ElfOutput<'data> {
SegmentType::Text, SegmentType::Text,
); );
// contains .data as one segment // contains .data as one segment
self.populate_segment( self.populate_segment(&mut offset, self.input_data.data_size(), SegmentType::Data);
&mut offset,
self.input_data.data_size(),
SegmentType::Data,
);
// contains .bss as one segment // contains .bss as one segment
self.populate_segment(&mut offset, self.input_data.bss_size(), SegmentType::Bss); 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> { 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) 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_phentsize = PHS;
self.file.ehdr.e_shentsize = SHS; self.file.ehdr.e_shentsize = SHS;
self.file.ehdr.e_phoff = EHS; 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; let mut offset = 0;

@ -1,5 +1,5 @@
use crate::common::Section;
use crate::common::SectionInfo; use crate::common::SectionInfo;
use crate::common::{Section};
use crate::error::Error; use crate::error::Error;
const SI_TEXT: usize = 0; const SI_TEXT: usize = 0;
@ -15,9 +15,9 @@ pub enum SegmentType {
const SEGMENT_NAMES: [&str; 4] = [".text", ".rodata", ".data", ".bss"]; const SEGMENT_NAMES: [&str; 4] = [".text", ".rodata", ".data", ".bss"];
pub struct InputData<'data>([Vec<SectionInfo<'data>>; 4]); pub struct OutputData<'data>([Vec<SectionInfo<'data>>; 4]);
impl<'data> InputData<'data> { impl<'data> OutputData<'data> {
pub fn new() -> Self { pub fn new() -> Self {
Self([Vec::new(), Vec::new(), Vec::new(), Vec::new()]) 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 { fn default() -> Self {
Self::new() Self::new()
} }

@ -1,35 +1,66 @@
use std::fmt::Display; use std::{fmt::Display, io::ErrorKind, marker::PhantomData, path::{Path, PathBuf}};
use crate::{ use crate::{
common::{Output, Relocatable}, common::{Output, Relocatable},
error::Error, error::Error,
}; };
pub struct Linker<'data> { pub struct Linker<'data, R, O>
relocatables: Vec<Box<dyn Relocatable + 'data>>, where
R: Relocatable<'data>,
O: Output<'data>,
{
relocatables: Vec<R>,
output: O,
_p: PhantomData<&'data ()>,
} }
impl<'data> Linker<'data> { impl<'data, R, O> Linker<'data, R, O>
pub fn new(relocatables: Vec<Box<dyn Relocatable + 'data>>) -> Self { where
Self { relocatables } 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<dyn Relocatable + 'data>) { pub fn add_relocatable(&mut self, path: PathBuf) -> Result<(), Error> {
self.relocatables.push(relocatable); self.relocatables.push(R::try_from(path)?);
Ok(())
} }
pub fn link(&'data self, output: &mut dyn Output<'data>) -> Result<u64, Error> { pub fn link(&mut self) -> Result<PathBuf, Error> {
for r in self.relocatables.iter() { for r in self.relocatables.iter() {
for s in r.sections() { 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<PathBuf, Error> {
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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "===Relocatables===")?; writeln!(f, "===Relocatables===")?;

@ -3,8 +3,8 @@ mod error;
mod formats; mod formats;
mod linker; mod linker;
use common::{Output, Storage}; use std::path::PathBuf;
use formats::{ElfObject, ElfOutput};
use linker::Linker; use linker::Linker;
fn main() { fn main() {
@ -13,31 +13,15 @@ fn main() {
// can this miss? // can this miss?
args.next().unwrap(); args.next().unwrap();
let mut contents: Vec<Storage> = Vec::new(); let destination = PathBuf::new(); // TODO
let mut linker = Linker::elf(); let mut linker = Linker::elf(destination).expect("Linker init");
let mut maybe_out = None;
while args.peek().is_some() { while args.peek().is_some() {
let fpath = args.next().expect("Unexpected peek-a-boo"); let path = PathBuf::from(args.next().expect("Argument expansion"));
let stored = Storage::new(fpath.into());
contents.push(stored);
}
for storage in contents.iter_mut() { linker.add_relocatable(path);
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));
} }
if let Some(mut output) = maybe_out { let outpath = linker.link().expect("Linking");
let linked = linker.link(&mut output).expect("Linking"); eprintln!("Done {:?}", outpath);
let outpath = output.finalize().expect("Finalization");
eprintln!("Done {:?}, linked {} bytes", outpath, linked);
} else {
eprintln!("Nothing to do");
}
} }

Loading…
Cancel
Save