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 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::*;

@ -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<V, S>(&mut self, symbol: impl Lazy<V, S>) -> Result<&mut Self, Error>;
fn process_section(&mut self, section: Section<'data>) -> Result<(), Error>;
fn finalize(self) -> Result<PathBuf, Error>;
}
@ -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(())
}

@ -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<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
/// 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 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::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<Self, Error> {
Ok(Self::new(ElfOutput::new(destination)?))
}
}

@ -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<Self, Error> {
let origin = storage.origin()?;
pub fn new(origin: PathBuf) -> Result<Self, Error> {
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<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> {
use elf_utilities::header::Type;

@ -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<File>,
}
@ -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;

@ -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<SectionInfo<'data>>; 4]);
pub struct OutputData<'data>([Vec<SectionInfo<'data>>; 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()
}

@ -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<Box<dyn Relocatable + 'data>>,
pub struct Linker<'data, R, O>
where
R: Relocatable<'data>,
O: Output<'data>,
{
relocatables: Vec<R>,
output: O,
_p: PhantomData<&'data ()>,
}
impl<'data> Linker<'data> {
pub fn new(relocatables: Vec<Box<dyn Relocatable + 'data>>) -> 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<dyn Relocatable + 'data>) {
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<u64, Error> {
pub fn link(&mut self) -> Result<PathBuf, Error> {
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<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 {
writeln!(f, "===Relocatables===")?;

@ -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<Storage> = 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);
}

Loading…
Cancel
Save