From 818e0a53f3da874a4bda5fc3924916b28d3b1876 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Mon, 11 Jan 2021 15:54:49 -0800 Subject: [PATCH] use indexes instead of references --- src/common/output.rs | 20 ++++++++----- src/common/relocatable.rs | 8 +++-- src/common/section.rs | 60 ++++++++++++++++++-------------------- src/formats/elf.rs | 2 +- src/formats/elf/object.rs | 27 ++++++++++++----- src/formats/elf/output.rs | 34 ++++++++++----------- src/formats/elf/segment.rs | 45 ++++++++++++++++++---------- src/linker.rs | 26 ++++++++--------- src/main.rs | 10 +++---- 9 files changed, 131 insertions(+), 101 deletions(-) diff --git a/src/common/output.rs b/src/common/output.rs index 492034f..9beedb4 100644 --- a/src/common/output.rs +++ b/src/common/output.rs @@ -1,23 +1,29 @@ use std::path::PathBuf; -use super::Section; +use super::{Relocatable, Section}; use crate::error::Error; -pub trait Output<'data> { - fn process_section(&mut self, section: Section<'data>) -> Result<(), Error>; +pub trait Output +where + R: Relocatable +{ + fn process_section(&mut self, section: Section) -> Result<(), Error>; - fn finalize(self) -> Result; + fn finalize(self, objects: &Vec) -> Result; } pub struct DummyOutput; -impl<'data> Output<'data> for DummyOutput { - fn process_section(&mut self, section: Section<'data>) -> Result<(), Error> { +impl Output for DummyOutput +where + R: Relocatable +{ + fn process_section(&mut self, section: Section) -> Result<(), Error> { eprintln!("Appending section: {}", section); Ok(()) } - fn finalize(self) -> Result { + fn finalize(self, objects: &Vec) -> Result { todo!(); } } diff --git a/src/common/relocatable.rs b/src/common/relocatable.rs index 77f4ad9..5b42a11 100644 --- a/src/common/relocatable.rs +++ b/src/common/relocatable.rs @@ -5,11 +5,13 @@ use crate::error::Error; use super::Section; -pub type BSI<'iter, 'data> = Box, Error>> + 'iter>; +pub type BSI<'iter> = Box> + 'iter>; /// Contains all the needed getters to construct a final /// mushed and relocated executable from an object file -pub trait Relocatable<'data>: Display + TryFrom { +pub trait Relocatable: Display + TryFrom { fn origin(&self) -> &Path; // not same as section's path since this one's supposed to be cannonical - fn sections<'sections>(self: &'sections Self) -> BSI<'sections, 'data>; + fn sections<'iter>(self: &'iter Self) -> BSI<'iter>; + + fn section_data(&self, section_index: usize) -> Result<&[u8], Error>; } diff --git a/src/common/section.rs b/src/common/section.rs index 5cab17d..6051130 100644 --- a/src/common/section.rs +++ b/src/common/section.rs @@ -4,46 +4,43 @@ use std::{ fmt::{Display, Formatter}, }; -// pub trait CBI<'data, T>: Iterator { -// fn clone_to_box(&self) -> Box + 'data>; -// } - -// impl<'data, T, X: 'data + Iterator + Clone> CBI<'data, T> for X { -// fn clone_to_box(&self) -> Box + 'data> { -// Box::new(self.clone()) -// } -// } - -// pub type SectionDataIterator<'data> = Box + 'data>; - #[derive(Clone)] -pub struct SectionInfo<'data> { - pub size: u64, - pub data: Option<&'data [u8]>, +pub struct SectionInfo { + pub file_size: u64, + pub data_size: u64, + pub data_index: Option<(usize, usize)>, // object/section pub offset: u64, } #[derive(Clone)] -pub enum Section<'data> { - Text(SectionInfo<'data>), - Data(SectionInfo<'data>, bool), // readonly bool - Bss(SectionInfo<'data>), +pub enum Section { + Text(SectionInfo), + Data(SectionInfo, bool), // readonly bool + Bss(SectionInfo), } -impl Section<'_> { - pub fn size(&self) -> Result { +impl Section { + pub fn file_size(&self) -> Result { + 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 { match self { - Section::Text(s) => Ok(s.size), - Section::Data(s, _) => Ok(s.size), - Section::Bss(s) => Ok(s.size), + Section::Text(s) => Ok(s.data_size), + Section::Data(s, _) => Ok(s.data_size), + Section::Bss(s) => Ok(s.data_size), } } } -impl<'data> TryFrom<(&str, SectionInfo<'data>)> for Section<'data> { +impl<'data> TryFrom<(&str, SectionInfo)> for Section { type Error = Error; - fn try_from(value: (&str, SectionInfo<'data>)) -> Result { + fn try_from(value: (&str, SectionInfo)) -> Result { if value.0.starts_with(".text") { Ok(Section::Text(value.1)) } else if value.0.starts_with(".rodata") { @@ -58,19 +55,20 @@ impl<'data> TryFrom<(&str, SectionInfo<'data>)> for Section<'data> { } } -impl Display for SectionInfo<'_> { +impl Display for SectionInfo { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, - "size: {}, data: {}, offset: {}", - self.size, - self.data.is_some(), + "file_size: {}, data_size: {}, data: {}, offset: {}", + self.file_size, + self.data_size, + self.data_index.is_some(), self.offset, ) } } -impl Display for Section<'_> { +impl Display for Section { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Section::Text(s) => writeln!(f, "TEXT {}", s), diff --git a/src/formats/elf.rs b/src/formats/elf.rs index b40d322..ce423ad 100644 --- a/src/formats/elf.rs +++ b/src/formats/elf.rs @@ -12,7 +12,7 @@ use elf_utilities::file::ELF64; pub use object::*; pub use output::*; -impl<'data> Linker<'data, ElfObject, ElfOutput<'data>> { +impl Linker { // shortcut to avoid turbofish pub fn elf(destination: PathBuf) -> Result { Ok(Self::new(ElfOutput::new(destination)?)) diff --git a/src/formats/elf/object.rs b/src/formats/elf/object.rs index 537e0e8..5689a7e 100644 --- a/src/formats/elf/object.rs +++ b/src/formats/elf/object.rs @@ -31,19 +31,20 @@ impl ElfObject { } } -impl<'data> Relocatable<'data> for ElfObject { +impl Relocatable for ElfObject { fn origin(&self) -> &Path { &self.origin } - fn sections<'sections>(self: &'sections Self) -> BSI<'sections, 'data> { + fn sections<'sections>(self: &'sections Self) -> BSI<'sections> { use elf_utilities::section::{Contents64, Type}; let iter = self .elf .sections .iter() - .filter_map(|s| match s.header.get_type() { + .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 { @@ -51,8 +52,9 @@ impl<'data> Relocatable<'data> for ElfObject { _ => None, } { let si = SectionInfo { - size: s.header.sh_size, - data: Some(di), + 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; @@ -70,8 +72,9 @@ impl<'data> Relocatable<'data> for ElfObject { } } Type::NoBits => Some(Ok(Section::Bss(SectionInfo { - size: 0, - data: None, + file_size: 0, + data_size: s.header.sh_size, + data_index: None, offset: s.header.sh_offset, }))), _ => None, @@ -79,6 +82,16 @@ impl<'data> Relocatable<'data> for ElfObject { Box::new(iter) } + + fn section_data(&self, section_index: usize) -> Result<&[u8], Error> { + use elf_utilities::section::Contents64; + let section = &self.elf.sections[section_index]; + + match §ion.contents { + Contents64::Raw(v) => Ok(&v), + _ => Err(Error::InvalidSectionData) + } + } } impl Display for ElfObject { diff --git a/src/formats/elf/output.rs b/src/formats/elf/output.rs index addcc5f..54b8e1d 100644 --- a/src/formats/elf/output.rs +++ b/src/formats/elf/output.rs @@ -22,21 +22,21 @@ use crate::{ use super::segment::*; use super::ElfObject; -pub struct ElfOutput<'data> { +pub struct ElfOutput { destination: PathBuf, file: ELF64, - input_data: OutputData<'data>, + input_data: OutputData, writer: BufWriter, } -impl<'data> ElfOutput<'data> { +impl ElfOutput { pub fn new(destination: PathBuf) -> Result { 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_machine(Machine::X8664); elf.ehdr.set_object_version(Version::Current); elf.ehdr.set_file_version(Version::Current); elf.ehdr.set_osabi(OSABI::Linux); @@ -79,9 +79,7 @@ impl<'data> ElfOutput<'data> { let mut data_size = 0; for t in sections.iter() { - if let Some(bytes) = t.data { - data_size += bytes.len(); - } + data_size += t.data_size; } if data_size == 0 { @@ -103,7 +101,7 @@ impl<'data> ElfOutput<'data> { let string_table = build_string_table(names, true); let section = Section64 { name: name.into(), - header: make_section_header(name_idx, ShType::StrTab, string_table.len()), + header: make_section_header(name_idx, ShType::StrTab, string_table.len() as u64), contents: Contents64::Raw(string_table), }; self.file.add_section(section); @@ -131,7 +129,7 @@ impl<'data> ElfOutput<'data> { SegmentType::Data => segment.header.p_flags = PF_R | PF_W, SegmentType::Bss => { segment.header.p_flags = PF_R; - segment.header.p_memsz = 0; + segment.header.p_filesz = 0; page_size = 0; } } @@ -161,12 +159,12 @@ impl<'data> ElfOutput<'data> { } } -impl<'data> Output<'data> for ElfOutput<'data> { - fn process_section(&mut self, section: Section<'data>) -> Result<(), Error> { +impl Output for ElfOutput { + fn process_section(&mut self, section: Section) -> Result<(), Error> { self.input_data.append_section(section) } - fn finalize(mut self) -> Result { + fn finalize(mut self, objects: &Vec) -> Result { const EHS: u64 = size_of::() as u64; const PHS: u16 = size_of::() as u16; const SHS: u16 = size_of::() as u16; @@ -209,14 +207,14 @@ impl<'data> Output<'data> for ElfOutput<'data> { 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() { - offset += self.writer.write(bytes)?; + for bytes in self.input_data.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() { - offset += self.writer.write(bytes)?; + for bytes in self.input_data.data_bytes(objects) { + offset += self.writer.write(bytes?)?; } self.writer.flush()?; @@ -252,7 +250,7 @@ fn elf_bin_from_object(other: &ELF64) -> ELF64 { elf } -fn make_section_header(name_idx: usize, stype: ShType, size: usize) -> Shdr64 { +fn make_section_header(name_idx: usize, stype: ShType, size: u64) -> Shdr64 { let mut h = Shdr64::default(); h.set_type(stype); @@ -262,7 +260,7 @@ fn make_section_header(name_idx: usize, stype: ShType, size: usize) -> Shdr64 { h.sh_name = idx; // link index h.sh_link = 0; - h.sh_size = size as u64; + h.sh_size = size; // filled at finalize() // h.sh_offset = offset; diff --git a/src/formats/elf/segment.rs b/src/formats/elf/segment.rs index ae6cd4e..d3087d2 100644 --- a/src/formats/elf/segment.rs +++ b/src/formats/elf/segment.rs @@ -1,7 +1,9 @@ -use crate::common::Section; +use crate::common::{Relocatable, Section}; use crate::common::SectionInfo; use crate::error::Error; +use super::ElfObject; + const SI_TEXT: usize = 0; const SI_RODATA: usize = 1; const SI_DATA: usize = 2; @@ -15,14 +17,14 @@ pub enum SegmentType { const SEGMENT_NAMES: [&str; 4] = [".text", ".rodata", ".data", ".bss"]; -pub struct OutputData<'data>([Vec>; 4]); +pub struct OutputData([Vec; 4]); -impl<'data> OutputData<'data> { +impl<'data> OutputData { pub fn new() -> Self { Self([Vec::new(), Vec::new(), Vec::new(), Vec::new()]) } - pub fn append_section(&mut self, section: Section<'data>) -> Result<(), Error> { + pub fn append_section(&mut self, section: Section) -> Result<(), Error> { match section { Section::Text(si) => self.0[SI_TEXT].push(si), Section::Data(si, false) => self.0[SI_DATA].push(si), @@ -35,25 +37,38 @@ impl<'data> OutputData<'data> { pub fn sections_mut( &mut self, - ) -> impl Iterator>)> { + ) -> impl Iterator)> { self.0 .iter_mut() .enumerate() .map(|(i, s)| (SEGMENT_NAMES[i], s)) } - pub fn program_bytes<'local>(&'local self) -> impl Iterator { + pub fn program_bytes<'l>(&'l self, objects: &'l Vec) -> impl Iterator> { let text_iter = self.0[SI_TEXT].iter(); let rodata_iter = self.0[SI_RODATA].iter(); - let data1 = text_iter.filter_map(|si| si.data); - let data2 = rodata_iter.filter_map(|si| si.data); + let data1 = text_iter.filter_map(move |si| match si.data_index { + None => None, + Some(di) => Some(objects[di.0].section_data(di.1)), + }); + let data2 = rodata_iter.filter_map(move |si| match si.data_index { + None => None, + Some(di) => Some(objects[di.0].section_data(di.1)), + }); + + let iter = data1.chain(data2); - data1.chain(data2) + iter } - pub fn data_bytes<'local>(&'local self) -> impl Iterator { - self.0[SI_DATA].iter().filter_map(|si| si.data) + pub fn data_bytes<'l>(&'l self, objects: &'l Vec) -> impl Iterator> { + let iter = self.0[SI_DATA].iter().filter_map(move |si| match si.data_index { + None => None, + Some(di) => Some(objects[di.0].section_data(di.1)), + }); + + iter } // .text + .rodata @@ -63,7 +78,7 @@ impl<'data> OutputData<'data> { let mut result = 0u64; for section in text_iter.chain(rodata_iter) { - result += section.size + result += section.data_size } result @@ -73,7 +88,7 @@ impl<'data> OutputData<'data> { pub fn data_size(&self) -> u64 { let mut result = 0u64; for section in self.0[SI_DATA].iter() { - result += section.size + result += section.data_size } result @@ -83,14 +98,14 @@ impl<'data> OutputData<'data> { pub fn bss_size(&self) -> u64 { let mut result = 0u64; for section in self.0[SI_BSS].iter() { - result += section.size + result += section.data_size } result } } -impl Default for OutputData<'_> { +impl Default for OutputData { fn default() -> Self { Self::new() } diff --git a/src/linker.rs b/src/linker.rs index 3a8cf8b..3c7d94e 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -1,30 +1,28 @@ -use std::{fmt::Display, io::ErrorKind, marker::PhantomData, path::{Path, PathBuf}}; +use std::{fmt::Display, io::ErrorKind, path::{Path, PathBuf}}; use crate::{ common::{Output, Relocatable}, error::Error, }; -pub struct Linker<'data, R, O> +pub struct Linker where - R: Relocatable<'data>, - O: Output<'data>, + R: Relocatable, + O: Output, { relocatables: Vec, output: O, - _p: PhantomData<&'data ()>, } -impl<'data, R, O> Linker<'data, R, O> +impl Linker where - R: Relocatable<'data>, - O: Output<'data>, + R: Relocatable, + O: Output, { pub fn new(output: O) -> Self { Self { relocatables: Vec::new(), output, - _p: PhantomData::default(), } } @@ -34,14 +32,14 @@ where Ok(()) } - pub fn link(&mut self) -> Result { + pub fn link(mut self) -> Result { for r in self.relocatables.iter() { for s in r.sections() { self.output.process_section(s?)?; } } - self.output.finalize() + self.output.finalize(&self.relocatables) } pub fn object_path(origin: &Path) -> Result { @@ -56,10 +54,10 @@ where } } -impl<'data, R, O> Display for Linker<'data, R, O> +impl Display for Linker where - R: Relocatable<'data>, - O: Output<'data>, + R: Relocatable, + O: Output, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "===Relocatables===")?; diff --git a/src/main.rs b/src/main.rs index 7949d0f..9de01cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,15 +11,15 @@ fn main() { let mut args = std::env::args().peekable(); // can this miss? - args.next().unwrap(); + args.next().expect("Argument expansion"); - let destination = PathBuf::new(); // TODO + let destination = PathBuf::from("/home/ales/Programovanie/rust/linker/assets/rld.out"); // TODO let mut linker = Linker::elf(destination).expect("Linker init"); - while args.peek().is_some() { - let path = PathBuf::from(args.next().expect("Argument expansion")); + while let Some(path) = args.next() { + let path = PathBuf::from(path); - linker.add_relocatable(path); + linker.add_relocatable(path).expect("Data input"); } let outpath = linker.link().expect("Linking");