master
Ales Katona 4 years ago
parent 970bbf65bb
commit a75186f3cf
Signed by: almindor
GPG Key ID: 2F773149BF38B48F

@ -9,7 +9,7 @@ where
{
fn process_section(&mut self, section: Section<R::Index>) -> Result<(), Error>;
fn finalize(self, objects: &Vec<R>) -> Result<PathBuf, Error>;
fn finalize(self, objects: &[R]) -> Result<PathBuf, Error>;
}
pub struct DummyOutput;
@ -23,7 +23,7 @@ where
Ok(())
}
fn finalize(self, objects: &Vec<R>) -> Result<PathBuf, Error> {
fn finalize(self, _objects: &[R]) -> Result<PathBuf, Error> {
todo!();
}
}

@ -1,5 +1,5 @@
use std::path::Path;
use std::{convert::TryFrom, fmt::Display, path::PathBuf};
use std::{fmt::Display, path::PathBuf};
use crate::error::Error;
@ -8,12 +8,15 @@ use super::Section;
pub type BSI<'iter, I> = Box<dyn Iterator<Item = Result<Section<I>, Error>> + 'iter>;
/// Contains all the needed getters to construct a final
/// mushed and relocated executable from an object file
pub trait Relocatable: Display + TryFrom<PathBuf, Error = Error> {
pub trait Relocatable: Display + Sized {
// + TryFrom<PathBuf, Error = Error> {
type Index; // index into the data, e.g. usize
fn new(origin: PathBuf, object_index: usize) -> Result<Self, Error>;
fn origin(&self) -> &Path; // not same as section's path since this one's supposed to be cannonical
fn sections<'iter>(self: &'iter Self) -> BSI<'iter, Self::Index>;
fn sections(&self) -> BSI<Self::Index>;
fn section_data(&self, section_index: Self::Index) -> Result<&[u8], Error>;
}

@ -19,24 +19,6 @@ pub enum Section<I> {
Bss(SectionInfo<I>),
}
impl<I> Section<I> {
pub fn file_size(&self) -> Result<u64, Error> {
match self {
Section::Text(s) => Ok(s.file_size),
Section::Data(s, _) => Ok(s.file_size),
Section::Bss(s) => Ok(s.file_size),
}
}
pub fn data_size(&self) -> Result<u64, Error> {
match self {
Section::Text(s) => Ok(s.data_size),
Section::Data(s, _) => Ok(s.data_size),
Section::Bss(s) => Ok(s.data_size),
}
}
}
impl<'data, I> TryFrom<(&str, SectionInfo<I>)> for Section<I> {
type Error = Error;

@ -35,7 +35,7 @@ impl From<std::io::Error> for Error {
}
impl From<std::num::TryFromIntError> for Error {
fn from(err: std::num::TryFromIntError) -> Self {
fn from(_: std::num::TryFromIntError) -> Self {
Self::TryFromIntError
}
}

@ -9,12 +9,13 @@ use crate::{common::BSI, error::Error};
use elf_utilities::{file::ELF64, parser::read_elf64};
pub struct ElfObject {
object_index: usize,
origin: PathBuf,
elf: ELF64,
}
impl ElfObject {
pub fn new(origin: PathBuf) -> Result<Self, Error> {
pub fn new(origin: PathBuf, object_index: usize) -> Result<Self, Error> {
let str_origin = origin
.as_path()
.to_str()
@ -25,7 +26,11 @@ impl ElfObject {
};
is_relocatable(&elf)?;
let result = ElfObject { origin, elf };
let result = ElfObject {
object_index,
origin,
elf,
};
Ok(result)
}
@ -38,53 +43,57 @@ impl ElfObject {
impl Relocatable for ElfObject {
type Index = (usize, usize); // object index, section index
fn new(origin: PathBuf, object_index: usize) -> Result<Self, Error> {
ElfObject::new(origin, object_index)
}
fn origin(&self) -> &Path {
&self.origin
}
fn sections<'iter>(self: &'iter Self) -> BSI<'iter, (usize, usize)> {
fn sections(&self) -> BSI<(usize, usize)> {
use elf_utilities::section::{Contents64, Type};
let iter =
self.elf
.sections
.iter()
.enumerate()
.filter_map(|(i, s)| match s.header.get_type() {
Type::ProgBits => {
if s.header.sh_size > 0 {
if let Some(di) = match &s.contents {
Contents64::Raw(v) => Some(v),
_ => None,
} {
let si = SectionInfo {
file_size: s.header.sh_size,
data_size: s.header.sh_size,
data_index: Some((0, i)), // TODO
offset: s.header.sh_offset,
};
let s_name: &str = &s.name;
match Section::try_from((s_name, si)) {
Ok(s) => Some(Ok(s)),
Err(Error::InvalidSectionName) => None, // skip
Err(err) => Some(Err(err)),
}
} else {
Some(Err(Error::InvalidSectionData))
let iter = self
.elf
.sections
.iter()
.enumerate()
.filter_map(move |(i, s)| match s.header.get_type() {
Type::ProgBits => {
if s.header.sh_size > 0 {
if match &s.contents {
Contents64::Raw(v) => Some(v),
_ => None,
}.is_some() {
let si = SectionInfo {
file_size: s.header.sh_size,
data_size: s.header.sh_size,
data_index: Some((self.object_index, i)),
offset: s.header.sh_offset,
};
let s_name: &str = &s.name;
match Section::try_from((s_name, si)) {
Ok(s) => Some(Ok(s)),
Err(Error::InvalidSectionName) => None, // skip
Err(err) => Some(Err(err)),
}
} else {
None
Some(Err(Error::InvalidSectionData))
}
} else {
None
}
Type::NoBits => Some(Ok(Section::Bss(SectionInfo {
file_size: 0,
data_size: s.header.sh_size,
data_index: None,
offset: s.header.sh_offset,
}))),
_ => None,
});
}
Type::NoBits => Some(Ok(Section::Bss(SectionInfo {
file_size: 0,
data_size: s.header.sh_size,
data_index: None,
offset: s.header.sh_offset,
}))),
_ => None,
});
Box::new(iter)
}
@ -118,13 +127,13 @@ impl Display for ElfObject {
}
}
impl TryFrom<PathBuf> for ElfObject {
type Error = Error;
// impl TryFrom<PathBuf> for ElfObject {
// type Error = Error;
fn try_from(path: PathBuf) -> Result<Self, Self::Error> {
Self::new(path)
}
}
// fn try_from(path: PathBuf) -> Result<Self, Self::Error> {
// Self::new(path)
// }
// }
fn is_relocatable(elf: &ELF64) -> Result<(), Error> {
use elf_utilities::header::Type;

@ -25,7 +25,7 @@ use super::ElfObject;
pub struct ElfOutput {
destination: PathBuf,
file: ELF64,
input_data: SegmentView,
segment_view: SegmentView,
writer: BufWriter<File>,
}
@ -48,23 +48,7 @@ impl ElfOutput {
let result = Self {
destination,
file: elf,
input_data: SegmentView::default(),
writer,
};
Ok(result)
}
pub fn from_object(object: &ElfObject, destination: PathBuf) -> Result<Self, Error> {
let other = object.elf();
let str_path = expand_path(&destination)?;
let writer = file_writer(str_path, 0o755)?;
let result = Self {
destination,
file: elf_bin_from_object(other),
input_data: SegmentView::default(),
segment_view: SegmentView::default(),
writer,
};
@ -75,7 +59,7 @@ impl ElfOutput {
let mut names = Vec::new();
let mut name_idx = 0usize;
for (name, sections) in self.input_data.sections_mut() {
for (name, sections) in self.segment_view.sections_mut() {
let mut data_size = 0;
for t in sections.iter() {
@ -147,13 +131,17 @@ impl ElfOutput {
// contains .text + .rodata as one segment
self.populate_segment(
&mut offset,
self.input_data.program_size(),
self.segment_view.program_size(),
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.segment_view.data_size(),
SegmentType::Data,
);
// contains .bss as one segment
self.populate_segment(&mut offset, self.input_data.bss_size(), SegmentType::Bss);
self.populate_segment(&mut offset, self.segment_view.bss_size(), SegmentType::Bss);
Ok(offset)
}
@ -161,10 +149,10 @@ impl ElfOutput {
impl Output<ElfObject> for ElfOutput {
fn process_section(&mut self, section: Section<(usize, usize)>) -> Result<(), Error> {
self.input_data.append_section(section)
self.segment_view.append_section(section)
}
fn finalize(mut self, objects: &Vec<ElfObject>) -> Result<PathBuf, Error> {
fn finalize(mut self, objects: &[ElfObject]) -> Result<PathBuf, Error> {
const EHS: u64 = size_of::<Ehdr64>() as u64;
const PHS: u16 = size_of::<Phdr64>() as u16;
const SHS: u16 = size_of::<Shdr64>() as u16;
@ -207,13 +195,13 @@ impl Output<ElfObject> for ElfOutput {
offset += pad_to_next_page(&mut self.writer, offset)?;
eprintln!("Prog start: {}", offset);
// write section/segment data
for bytes in self.input_data.program_bytes(objects) {
for bytes in self.segment_view.program_bytes(objects) {
offset += self.writer.write(bytes?)?;
}
offset += pad_to_next_page(&mut self.writer, offset)?;
eprintln!("Data start: {}", offset);
for bytes in self.input_data.data_bytes(objects) {
for bytes in self.segment_view.data_bytes(objects) {
offset += self.writer.write(bytes?)?;
}
@ -236,20 +224,6 @@ fn file_writer(output_filename: &str, permission: u32) -> Result<BufWriter<File>
Ok(BufWriter::new(file))
}
// 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
}
fn make_section_header(name_idx: usize, stype: ShType, size: u64) -> Shdr64 {
let mut h = Shdr64::default();
h.set_type(stype);

@ -34,9 +34,7 @@ impl<'data> SegmentView {
Ok(())
}
pub fn sections_mut(
&mut self,
) -> impl Iterator<Item = (&'static str, &mut SegmentSections)> {
pub fn sections_mut(&mut self) -> impl Iterator<Item = (&'static str, &mut SegmentSections)> {
let text = once(&mut self.text).map(|s| (".text", s));
let rodata = once(&mut self.rodata).map(|s| (".rodata", s));
let data = once(&mut self.data).map(|s| (".data", s));
@ -47,7 +45,7 @@ impl<'data> SegmentView {
pub fn program_bytes<'l>(
&'l self,
objects: &'l Vec<ElfObject>,
objects: &'l [ElfObject],
) -> impl Iterator<Item = Result<&'l [u8], Error>> {
let text_iter = self.text.iter();
let rodata_iter = self.rodata.iter();
@ -61,21 +59,17 @@ impl<'data> SegmentView {
Some(di) => Some(objects[di.0].section_data(di)),
});
let iter = data1.chain(data2);
iter
data1.chain(data2)
}
pub fn data_bytes<'l>(
&'l self,
objects: &'l Vec<ElfObject>,
objects: &'l [ElfObject],
) -> impl Iterator<Item = Result<&'l [u8], Error>> {
let iter = self.data
.iter()
.filter_map(move |si| match si.data_index {
None => None,
Some(di) => Some(objects[di.0].section_data(di)),
});
let iter = self.data.iter().filter_map(move |si| match si.data_index {
None => None,
Some(di) => Some(objects[di.0].section_data(di)),
});
iter
}

@ -30,8 +30,9 @@ where
}
}
pub fn add_relocatable(&mut self, path: PathBuf) -> Result<(), Error> {
self.relocatables.push(R::try_from(path)?);
pub fn add_relocatable(&mut self, origin: PathBuf) -> Result<(), Error> {
self.relocatables
.push(R::new(origin, self.relocatables.len())?);
Ok(())
}

@ -16,7 +16,7 @@ fn main() {
let destination = PathBuf::from("/home/ales/Programovanie/rust/linker/assets/rld.out"); // TODO
let mut linker = Linker::elf(destination).expect("Linker init");
while let Some(path) = args.next() {
for path in args {
let path = PathBuf::from(path);
linker.add_relocatable(path).expect("Data input");

Loading…
Cancel
Save