From f5ae47bf4259148b81fc72f50dbcbbf42b598b53 Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Thu, 7 Jan 2021 10:25:39 -0800 Subject: [PATCH] WIP --- src/common/section.rs | 26 ++++++++++++++- src/error.rs | 7 ++++ src/formats/elf/output.rs | 66 ++++++++++++++++++++++++++------------ src/formats/elf/segment.rs | 20 ++++++++++-- src/linker.rs | 2 +- 5 files changed, 96 insertions(+), 25 deletions(-) diff --git a/src/common/section.rs b/src/common/section.rs index 23e2a37..47dbfaf 100644 --- a/src/common/section.rs +++ b/src/common/section.rs @@ -4,7 +4,17 @@ use std::{ fmt::{Display, Formatter}, }; -pub type SectionDataIterator<'data> = Box + 'data>; +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>; pub struct SectionInfo<'data> { pub size: u64, @@ -12,12 +22,26 @@ pub struct SectionInfo<'data> { pub offset: u64, } +#[derive(Clone)] pub enum Section<'data> { Text(SectionInfo<'data>), Data(SectionInfo<'data>, bool), // readonly bool Bss(SectionInfo<'data>), } +impl<'data> Clone for SectionInfo<'data> { + fn clone(&self) -> Self { + Self { + size: self.size, + data: match self.data.as_ref() { + Some(iter) => Some(iter.clone_to_box()), + None => None, + }, + offset: self.offset, + } + } +} + impl Section<'_> { pub fn size(&self) -> Result { match self { diff --git a/src/error.rs b/src/error.rs index 73a185f..bb96a56 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,6 +10,7 @@ pub enum Error { InvalidSectionName, InvalidSectionData, ParseError(Box), + TryFromIntError, // LinkingError(Trace), } @@ -33,6 +34,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: std::num::TryFromIntError) -> Self { + Self::TryFromIntError + } +} + impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "TODO!") diff --git a/src/formats/elf/output.rs b/src/formats/elf/output.rs index a9de61d..cbc7e61 100644 --- a/src/formats/elf/output.rs +++ b/src/formats/elf/output.rs @@ -1,4 +1,11 @@ -use std::{fs::File, io::BufWriter, io::Write, mem::size_of, path::{Path, PathBuf}}; +use std::{ + convert::TryInto, + fs::File, + io::BufWriter, + io::{Seek, SeekFrom, Write}, + mem::size_of, + path::{Path, PathBuf}, +}; use elf_utilities::{ file::ELF64, @@ -56,7 +63,7 @@ impl<'data> ElfOutput<'data> { let mut name_idx = 0usize; let mut result = 0u64; - for (name, sections) in self.segment_data.iter_mut() { + for (name, sections) in self.segment_data.sections_mut() { let mut data = Vec::new(); for t in sections.iter_mut() { @@ -94,9 +101,9 @@ impl<'data> ElfOutput<'data> { Ok(result) } - fn populate_segment(&mut self, offset: &mut u64, size: u64, which: SegmentType) -> u64 { + fn populate_segment(&mut self, offset: &mut u64, size: u64, which: SegmentType) { if size == 0 { - return 0; + return; } let mut segment = Segment64 { @@ -120,32 +127,28 @@ impl<'data> ElfOutput<'data> { self.file.ehdr.e_phnum += 1; self.file.ehdr.e_phentsize = size_of::() as u16; - *offset += size; - - size + *offset += next_page(size); } fn populate_segments(&mut self) -> Result { let mut offset = 0u64; - let mut result = 0u64; // program header/segments // contains .text + .rodata as one segment - result += self.populate_segment( + self.populate_segment( &mut offset, self.segment_data.program_size(), SegmentType::Text, ); // contains .data as one segment - result += self.populate_segment( + self.populate_segment( &mut offset, self.segment_data.data_size(), SegmentType::Data, ); // contains .bss as one segment - result += - self.populate_segment(&mut offset, self.segment_data.bss_size(), SegmentType::Bss); + self.populate_segment(&mut offset, self.segment_data.bss_size(), SegmentType::Bss); - Ok(result) + Ok(offset) } } @@ -160,18 +163,18 @@ impl<'data> Output<'data> for ElfOutput<'data> { fn finalize(mut self) -> Result { const EHS: u64 = size_of::() as u64; - const PHS: u64 = size_of::() as u64; + const PHS: u16 = size_of::() as u16; const SHS: u16 = size_of::() as u16; - let segment_data_size = self.populate_sections()?; - self.populate_segments()?; + self.populate_sections()?; + let page_size = self.populate_segments()?; - self.file.ehdr.e_phentsize = PHS as u16; + self.file.ehdr.e_phentsize = PHS; self.file.ehdr.e_shentsize = SHS; self.file.ehdr.e_phoff = EHS; // TODO: align self.file.ehdr.e_shoff = self.file.ehdr.e_phoff + u64::from(self.file.ehdr.e_phnum * self.file.ehdr.e_phentsize) - + segment_data_size; + + page_size; self.file.ehdr.e_shnum = self.file.sections.len() as u16; self.file.ehdr.e_entry = 0x100; // TODO @@ -191,9 +194,10 @@ impl<'data> Output<'data> for ElfOutput<'data> { // write section/segment data for sec in self.file.sections.iter_mut() { sec.header.sh_offset = offset as u64; - offset += writer.write(&sec.to_le_bytes())?; + offset += write_padded(&mut writer, offset, &sec.to_le_bytes())?; } + eprintln!("SHT: {}", offset); // write section header table for sec in self.file.sections.iter() { offset += writer.write(&sec.header.to_le_bytes())?; @@ -237,7 +241,7 @@ fn make_section_header(name_idx: usize, stype: ShType, size: usize) -> Shdr64 { // section index used for name and section indexing (currently same) let idx = 1 + (name_idx as u32); // add 0 at start - // name index + // name index h.sh_name = idx; // link index h.sh_link = 0; @@ -257,4 +261,24 @@ fn expand_path(path: &Path) -> Result<&str, Error> { let boxed = Box::new(ioe); Error::IOError(boxed) }) -} \ No newline at end of file +} + +fn next_page(size: u64) -> u64 { + let page_size: u64 = page_size::get() as u64; + + let pages_needed = (size / page_size) + 1; + + page_size * pages_needed +} + +fn write_padded(writer: &mut BufWriter, offset: usize, data: &[u8]) -> Result { + let page_size = page_size::get(); + let mut written = 0usize; + + written += writer.write(data)?; + let padding = page_size - (page_size % offset); + + written += writer.get_mut().seek(SeekFrom::Current(padding as i64))? as usize; + + Ok(written) +} diff --git a/src/formats/elf/segment.rs b/src/formats/elf/segment.rs index 241b467..4ad8d22 100644 --- a/src/formats/elf/segment.rs +++ b/src/formats/elf/segment.rs @@ -1,5 +1,5 @@ -use crate::common::Section; use crate::common::SectionInfo; +use crate::common::{Section, SectionDataIterator}; use crate::error::Error; const SI_TEXT: usize = 0; @@ -33,7 +33,7 @@ impl<'data> SegmentData<'data> { Ok(()) } - pub fn iter_mut( + pub fn sections_mut( &mut self, ) -> impl Iterator>)> { self.0 @@ -42,6 +42,22 @@ impl<'data> SegmentData<'data> { .map(|(i, s)| (SEGMENT_NAMES[i], s)) } + pub fn program_data<'local>(&'local self) -> Box + 'local> { + let text_iter = self.0[SI_TEXT].iter(); + let rodata_iter = self.0[SI_RODATA].iter(); + + let data1 = text_iter.filter_map(|si| match si.data.as_ref() { + Some(iter) => Some(iter.clone_to_box()), + None => None, + }); + let data2 = rodata_iter.filter_map(|si| match si.data.as_ref() { + Some(iter) => Some(iter.clone_to_box()), + None => None, + }); + + Box::new(data1.chain(data2).flatten()) + } + // .text + .rodata pub fn program_size(&self) -> u64 { let text_iter = self.0[SI_TEXT].iter(); diff --git a/src/linker.rs b/src/linker.rs index 39e8453..a3bf6f6 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -18,7 +18,7 @@ impl<'data> Linker<'data> { self.relocatables.push(relocatable); } - pub fn link<'l: 'data>(&'l self, output: &mut dyn Output<'data>) -> Result { + pub fn link(&'data self, output: &mut dyn Output<'data>) -> Result { let allocated = output.allocate(self.total_size()?)?; for r in self.relocatables.iter() {