master
Ales Katona 4 years ago
parent f5ae47bf42
commit c3fbd3ed22
Signed by: almindor
GPG Key ID: 2F773149BF38B48F

@ -4,8 +4,6 @@ use super::Section;
use crate::error::Error;
pub trait Output<'data> {
fn allocate(&mut self, size: u64) -> Result<u64, 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>;
@ -16,11 +14,6 @@ pub trait Output<'data> {
pub struct 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<'data>) -> Result<(), Error> {
eprintln!("Appending section: {}", section);
Ok(())

@ -4,21 +4,22 @@ use std::{
fmt::{Display, Formatter},
};
pub trait CBI<'data, T>: Iterator<Item = T> {
fn clone_to_box(&self) -> Box<dyn CBI<'data, T> + 'data>;
}
// pub trait CBI<'data, T>: Iterator<Item = T> {
// fn clone_to_box(&self) -> Box<dyn CBI<'data, T> + 'data>;
// }
impl<'data, T, X: 'data + Iterator<Item = T> + Clone> CBI<'data, T> for X {
fn clone_to_box(&self) -> Box<dyn CBI<'data, T> + 'data> {
Box::new(self.clone())
}
}
// impl<'data, T, X: 'data + Iterator<Item = T> + Clone> CBI<'data, T> for X {
// fn clone_to_box(&self) -> Box<dyn CBI<'data, T> + 'data> {
// Box::new(self.clone())
// }
// }
pub type SectionDataIterator<'data> = Box<dyn CBI<'data, u8> + 'data>;
// pub type SectionDataIterator<'data> = Box<dyn CBI<'data, u8> + 'data>;
#[derive(Clone)]
pub struct SectionInfo<'data> {
pub size: u64,
pub data: Option<SectionDataIterator<'data>>,
pub data: Option<&'data [u8]>,
pub offset: u64,
}
@ -29,19 +30,6 @@ pub enum Section<'data> {
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<u64, Error> {
match self {

@ -52,12 +52,12 @@ impl Relocatable for ElfObject {
Type::ProgBits => {
if s.header.sh_size > 0 {
if let Some(di) = match &s.contents {
Contents64::Raw(v) => Some(v.iter()),
Contents64::Raw(v) => Some(v),
_ => None,
} {
let si = SectionInfo {
size: s.header.sh_size,
data: Some(Box::new(di.copied())),
data: Some(di),
offset: s.header.sh_offset,
};
let s_name: &str = &s.name;

@ -25,7 +25,7 @@ use super::ElfObject;
pub struct ElfOutput<'data> {
destination: PathBuf,
file: ELF64,
segment_data: SegmentData<'data>,
input_data: InputData<'data>,
}
impl<'data> ElfOutput<'data> {
@ -44,7 +44,7 @@ impl<'data> ElfOutput<'data> {
Self {
destination,
file: elf,
segment_data: SegmentData::new(),
input_data: InputData::new(),
}
}
@ -54,34 +54,32 @@ impl<'data> ElfOutput<'data> {
Self {
destination,
file: elf_bin_from_object(other),
segment_data: SegmentData::new(),
input_data: InputData::new(),
}
}
fn populate_sections(&mut self) -> Result<u64, Error> {
fn populate_sections(&mut self) -> Result<(), Error> {
let mut names = Vec::new();
let mut name_idx = 0usize;
let mut result = 0u64;
for (name, sections) in self.segment_data.sections_mut() {
let mut data = Vec::new();
for (name, sections) in self.input_data.sections_mut() {
let mut data_size = 0;
for t in sections.iter_mut() {
if let Some(iter) = &mut t.data {
data.extend(iter.as_mut());
for t in sections.iter() {
if let Some(bytes) = t.data {
data_size += bytes.len();
}
}
if data.is_empty() {
if data_size == 0{
continue;
}
result += data.len() as u64;
names.push(name);
let section = Section64 {
name: name.into(),
header: make_section_header(name_idx, ShType::ProgBits, data.len()),
contents: Contents64::Raw(data),
header: make_section_header(name_idx, ShType::ProgBits, data_size),
contents: Contents64::Raw(Vec::new()), // placeholder only
};
name_idx += name.len() + 1;
self.file.add_section(section);
@ -90,7 +88,6 @@ impl<'data> ElfOutput<'data> {
let name = ".shstrtab";
names.push(name);
let string_table = build_string_table(names, true);
result += string_table.len() as u64;
let section = Section64 {
name: name.into(),
header: make_section_header(name_idx, ShType::StrTab, string_table.len()),
@ -98,7 +95,7 @@ impl<'data> ElfOutput<'data> {
};
self.file.add_section(section);
Ok(result)
Ok(())
}
fn populate_segment(&mut self, offset: &mut u64, size: u64, which: SegmentType) {
@ -114,12 +111,15 @@ impl<'data> ElfOutput<'data> {
segment.header.p_memsz = size;
segment.header.p_offset = *offset;
let mut page_size = next_page(size);
match which {
SegmentType::Text => segment.header.p_flags = PF_R | PF_X,
SegmentType::Data => segment.header.p_flags = PF_R | PF_W,
SegmentType::Bss => {
segment.header.p_flags = PF_R;
segment.header.p_memsz = 0;
page_size = 0;
}
}
@ -127,7 +127,7 @@ impl<'data> ElfOutput<'data> {
self.file.ehdr.e_phnum += 1;
self.file.ehdr.e_phentsize = size_of::<Phdr64>() as u16;
*offset += next_page(size);
*offset += page_size;
}
fn populate_segments(&mut self) -> Result<u64, Error> {
@ -136,29 +136,25 @@ impl<'data> ElfOutput<'data> {
// contains .text + .rodata as one segment
self.populate_segment(
&mut offset,
self.segment_data.program_size(),
self.input_data.program_size(),
SegmentType::Text,
);
// contains .data as one segment
self.populate_segment(
&mut offset,
self.segment_data.data_size(),
self.input_data.data_size(),
SegmentType::Data,
);
// contains .bss as one segment
self.populate_segment(&mut offset, self.segment_data.bss_size(), SegmentType::Bss);
self.populate_segment(&mut offset, self.input_data.bss_size(), SegmentType::Bss);
Ok(offset)
}
}
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> {
self.segment_data.append_section(section)
self.input_data.append_section(section)
}
fn finalize(mut self) -> Result<PathBuf, Error> {
@ -169,20 +165,19 @@ impl<'data> Output<'data> for ElfOutput<'data> {
self.populate_sections()?;
let page_size = self.populate_segments()?;
self.file.ehdr.e_shnum = self.file.sections.len() as u16;
self.file.ehdr.e_entry = 4096; // TODO
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)
+ page_size;
self.file.ehdr.e_shnum = self.file.sections.len() as u16;
self.file.ehdr.e_entry = 0x100; // TODO
self.file.ehdr.e_phoff = EHS;
self.file.ehdr.e_shoff = self.file.ehdr.e_phoff + (usize::from(self.file.ehdr.e_phentsize) * self.file.segments.len()) as u64;
let str_path = expand_path(&self.destination)?;
let mut writer = file_writer(str_path, 0o755)?;
let mut offset = 0;
// write ELF header
offset += writer.write(&self.file.ehdr.to_le_bytes())?;
// write program header table
@ -191,17 +186,32 @@ impl<'data> Output<'data> for ElfOutput<'data> {
offset += writer.write(&seg.header.to_le_bytes())?;
}
// write section/segment data
eprintln!("SH start: {}", offset);
// write section header table
for sec in self.file.sections.iter_mut() {
sec.header.sh_offset = offset as u64;
offset += write_padded(&mut writer, offset, &sec.to_le_bytes())?;
if sec.header.get_type() == ShType::StrTab {
sec.header.sh_offset = offset as u64 + u64::from(SHS);
}
offset += writer.write(&sec.header.to_le_bytes())?;
if sec.header.get_type() == ShType::StrTab {
offset += writer.write(&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())?;
// program data (segments)
offset += pad_to_next_page(&mut writer, offset)?;
eprintln!("Prog start: {}", offset);
// write section/segment data
for bytes in self.input_data.program_bytes() {
offset += writer.write(bytes)?;
}
offset += pad_to_next_page(&mut writer, offset)?;
eprintln!("Data start: {}", offset);
for bytes in self.input_data.data_bytes() {
offset += writer.write(bytes)?;
}
writer.flush()?;
Ok(self.destination)
@ -213,7 +223,7 @@ fn file_writer(output_filename: &str, permission: u32) -> Result<BufWriter<File>
let file = std::fs::OpenOptions::new()
.create(true)
.read(true)
.truncate(true)
.write(true)
.mode(permission)
.open(output_filename)?;
@ -271,14 +281,13 @@ fn next_page(size: u64) -> u64 {
page_size * pages_needed
}
fn write_padded(writer: &mut BufWriter<File>, offset: usize, data: &[u8]) -> Result<usize, Error> {
fn pad_to_next_page(writer: &mut BufWriter<File>, offset: usize) -> Result<usize, Error> {
let page_size = page_size::get();
let mut written = 0usize;
written += writer.write(data)?;
let padding = page_size - (page_size % offset);
let padding = page_size - (offset % page_size);
written += writer.get_mut().seek(SeekFrom::Current(padding as i64))? as usize;
eprintln!("Padding from: {} with: {}", offset, padding);
writer.seek(SeekFrom::Current(padding.try_into()?))?;
Ok(written)
Ok(padding)
}

@ -1,5 +1,5 @@
use crate::common::SectionInfo;
use crate::common::{Section, SectionDataIterator};
use crate::common::{Section};
use crate::error::Error;
const SI_TEXT: usize = 0;
@ -15,9 +15,9 @@ pub enum SegmentType {
const SEGMENT_NAMES: [&str; 4] = [".text", ".rodata", ".data", ".bss"];
pub struct SegmentData<'data>([Vec<SectionInfo<'data>>; 4]);
pub struct InputData<'data>([Vec<SectionInfo<'data>>; 4]);
impl<'data> SegmentData<'data> {
impl<'data> InputData<'data> {
pub fn new() -> Self {
Self([Vec::new(), Vec::new(), Vec::new(), Vec::new()])
}
@ -42,20 +42,18 @@ impl<'data> SegmentData<'data> {
.map(|(i, s)| (SEGMENT_NAMES[i], s))
}
pub fn program_data<'local>(&'local self) -> Box<dyn Iterator<Item = u8> + 'local> {
pub fn program_bytes<'local>(&'local self) -> impl Iterator<Item = &'local [u8]> {
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,
});
let data1 = text_iter.filter_map(|si| si.data);
let data2 = rodata_iter.filter_map(|si| si.data);
Box::new(data1.chain(data2).flatten())
data1.chain(data2)
}
pub fn data_bytes<'local>(&'local self) -> impl Iterator<Item = &'local [u8]> {
self.0[SI_DATA].iter().filter_map(|si| si.data)
}
// .text + .rodata
@ -92,7 +90,7 @@ impl<'data> SegmentData<'data> {
}
}
impl Default for SegmentData<'_> {
impl Default for InputData<'_> {
fn default() -> Self {
Self::new()
}

@ -19,27 +19,13 @@ impl<'data> Linker<'data> {
}
pub fn link(&'data 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?)?;
}
}
Ok(allocated)
}
fn total_size(&self) -> Result<u64, Error> {
let mut result = 0u64;
for o in self.relocatables.iter() {
for s in o.sections() {
result += s?.size()?;
}
}
Ok(result)
Ok(0)
}
}

Loading…
Cancel
Save