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 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; pub struct DummyOutput;
@ -23,7 +23,7 @@ where
Ok(()) Ok(())
} }
fn finalize(self, objects: &Vec<R>) -> Result<PathBuf, Error> { fn finalize(self, _objects: &[R]) -> Result<PathBuf, Error> {
todo!(); todo!();
} }
} }

@ -1,5 +1,5 @@
use std::path::Path; use std::path::Path;
use std::{convert::TryFrom, fmt::Display, path::PathBuf}; use std::{fmt::Display, path::PathBuf};
use crate::error::Error; 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>; pub type BSI<'iter, I> = Box<dyn Iterator<Item = Result<Section<I>, 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 + TryFrom<PathBuf, Error = Error> { pub trait Relocatable: Display + Sized {
// + TryFrom<PathBuf, Error = Error> {
type Index; // index into the data, e.g. usize 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 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>; fn section_data(&self, section_index: Self::Index) -> Result<&[u8], Error>;
} }

@ -19,24 +19,6 @@ pub enum Section<I> {
Bss(SectionInfo<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> { impl<'data, I> TryFrom<(&str, SectionInfo<I>)> for Section<I> {
type Error = Error; type Error = Error;

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

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

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

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

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

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

Loading…
Cancel
Save