first file output

master
Ales Katona 4 years ago
parent 0e1c83bbed
commit 54adb8559d
Signed by: almindor
GPG Key ID: 2F773149BF38B48F

@ -7,6 +7,11 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
xmas-elf = "0.7.0"
elf-utilities = "0.2.8"
page_size = "0.4.2"
page_size = "0.4.2"
elf-utilities = { version = "0.2.8", optional = true }
xmas-elf = { version = "0.7.0", optional = true }
[features]
default = ["elf"]
elf = ["elf-utilities"]
xelf = ["xmas-elf"]

@ -1,24 +1,32 @@
use std::path::PathBuf;
use super::Section;
use crate::error::Error;
pub trait Output {
pub trait Output<'data> {
fn allocate(&mut self, size: u64) -> Result<u64, Error>;
fn append_section(&mut self, section: &Section) -> Result<(), Error>;
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 finalize(self) -> Result<PathBuf, Error>;
}
pub struct DummyOutput;
impl Output for DummyOutput {
impl<'data> Output<'data> for DummyOutput {
fn allocate(&mut self, size: u64) -> Result<u64, Error> {
eprintln!("Allocating: {}", size);
Ok(size)
}
fn append_section(&mut self, section: &Section) -> Result<(), Error> {
fn append_section(&mut self, section: Section<'data>) -> Result<(), Error> {
eprintln!("Appending section: {}", section);
Ok(())
}
fn finalize(self) -> Result<PathBuf, Error> {
todo!();
}
}

@ -1,4 +1,5 @@
use std::path::PathBuf;
use std::{fs::canonicalize, io::ErrorKind};
use crate::error::Error;
@ -16,7 +17,18 @@ impl Storage {
}
pub fn origin(&self) -> Result<PathBuf, Error> {
std::fs::canonicalize(&self.origin).map_err(|e| e.into())
canonicalize(&self.origin).map_err(|e| e.into())
}
pub fn destination(&self) -> Result<PathBuf, Error> {
let mut dest = canonicalize(&self.origin).map_err(|e| Error::from(e))?;
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> {

@ -5,11 +5,9 @@ use std::{
#[derive(Debug)]
pub enum Error {
IOError(std::io::Error),
IOError(Box<dyn std::error::Error>),
InvalidObjectType(u32),
InvalidSectionName,
MissingSectionHeader(&'static str),
MissingSectionData(&'static str),
InvalidSectionData,
ParseError(Box<dyn std::error::Error>),
LinkingError(Trace),
@ -31,7 +29,7 @@ pub trait SourceInfo: Debug + Display {
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Self::IOError(err)
Self::IOError(Box::new(err))
}
}

@ -1,5 +1,9 @@
#[cfg(feature = "elf")]
mod elf;
#[cfg(feature = "xelf")]
mod xelf;
#[cfg(feature = "elf")]
pub use elf::*;
#[cfg(feature = "xelf")]
pub use xelf::*;

@ -3,9 +3,11 @@ use crate::error::Error;
use crate::linker::Linker;
mod object;
mod output;
use elf_utilities::file::ELF64;
pub use object::ElfObject;
pub use object::*;
pub use output::*;
impl Linker<'_> {
// shortcut to avoid turbofish

@ -30,6 +30,10 @@ impl ElfObject {
Ok(result)
}
pub fn elf(&self) -> &ELF64 {
&self.elf
}
}
impl Relocatable for ElfObject {

@ -0,0 +1,128 @@
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<SectionInfo<'data>>,
data: Vec<SectionInfo<'data>>,
bss: Vec<SectionInfo<'data>>,
}
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<u64, Error> {
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<u64, Error> {
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<PathBuf, Error> {
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)
}
}

@ -6,8 +6,11 @@ use std::{
use crate::common::{Relocatable, Section, SectionInfo, Storage};
use crate::{common::BSI, error::Error};
use xmas_elf::{ElfFile, sections::{SectionData, SectionHeader}};
use xmas_elf::{header::Type as ElfType, sections::ShType};
use xmas_elf::{
sections::{SectionData, SectionHeader},
ElfFile,
};
pub struct XElfObject<'data> {
origin: PathBuf,
@ -55,7 +58,7 @@ impl Relocatable for XElfObject<'_> {
data: Some(Box::new(data_iter.copied())),
offset: h.offset(),
};
match Section::try_from((s_name, si)) {
Ok(s) => Some(Ok(s)),
Err(Error::InvalidSectionName) => None, // skip

@ -18,12 +18,12 @@ impl<'data> Linker<'data> {
self.relocatables.push(relocatable);
}
pub fn link(&self, output: &mut dyn Output) -> Result<u64, Error> {
pub fn link<'l: 'data>(&'l self, output: &mut dyn Output<'data>) -> Result<u64, Error> {
let allocated = output.allocate(self.total_size()?)?;
for r in self.relocatables.iter() {
for s in r.sections() {
output.append_section(&s?)?;
output.append_section(s?)?;
}
}

@ -3,8 +3,8 @@ mod error;
mod formats;
mod linker;
use common::{DummyOutput, Storage};
use formats::ElfObject;
use common::{Output, Storage};
use formats::{ElfObject, ElfOutput};
use linker::Linker;
fn main() {
@ -15,7 +15,7 @@ fn main() {
let mut contents: Vec<Storage> = Vec::new();
let mut linker = Linker::elf();
let mut output = DummyOutput;
let mut maybe_out = None;
while args.peek().is_some() {
let fpath = args.next().expect("Unexpected peek-a-boo");
@ -25,8 +25,19 @@ fn main() {
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));
}
linker.add_relocatable(Box::new(relocatable));
}
linker.link(&mut output).expect("Linking");
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");
}
}

Loading…
Cancel
Save