Merge branch 'direct'

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

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

@ -4,14 +4,26 @@ use std::{
fmt::{Display, Formatter}, fmt::{Display, Formatter},
}; };
pub type SectionDataIterator<'data> = Box<dyn Iterator<Item = u8> + '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())
// }
// }
// pub type SectionDataIterator<'data> = Box<dyn CBI<'data, u8> + 'data>;
#[derive(Clone)]
pub struct SectionInfo<'data> { pub struct SectionInfo<'data> {
pub size: u64, pub size: u64,
pub data: Option<SectionDataIterator<'data>>, pub data: Option<&'data [u8]>,
pub offset: u64, pub offset: u64,
} }
#[derive(Clone)]
pub enum Section<'data> { pub enum Section<'data> {
Text(SectionInfo<'data>), Text(SectionInfo<'data>),
Data(SectionInfo<'data>, bool), // readonly bool Data(SectionInfo<'data>, bool), // readonly bool

@ -10,6 +10,7 @@ pub enum Error {
InvalidSectionName, InvalidSectionName,
InvalidSectionData, InvalidSectionData,
ParseError(Box<dyn std::error::Error>), ParseError(Box<dyn std::error::Error>),
TryFromIntError, //
LinkingError(Trace), LinkingError(Trace),
} }
@ -33,6 +34,12 @@ impl From<std::io::Error> for Error {
} }
} }
impl From<std::num::TryFromIntError> for Error {
fn from(err: std::num::TryFromIntError) -> Self {
Self::TryFromIntError
}
}
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "TODO!") write!(f, "TODO!")

@ -18,7 +18,7 @@ impl Linker<'_> {
} }
impl<'data> Lazy<&'data str, ELF64> for Symbol<'data> { impl<'data> Lazy<&'data str, ELF64> for Symbol<'data> {
fn value(&self, src: &ELF64) -> Result<&'data str, Error> { fn value(&self, _src: &ELF64) -> Result<&'data str, Error> {
Err(Error::InvalidSectionData) // TODO Err(Error::InvalidSectionData) // TODO
} }

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

@ -1,6 +1,18 @@
use std::path::PathBuf; use std::{
convert::TryInto,
fs::File,
io::BufWriter,
io::{Seek, SeekFrom, Write},
mem::size_of,
path::{Path, PathBuf},
};
use elf_utilities::{file::{ELF64Dumper, ELF64}, section::{Contents64, Section64, Shdr64, build_string_table}}; use elf_utilities::{
file::ELF64,
header::Ehdr64,
section::{build_string_table, Contents64, Section64, Shdr64, Type as ShType},
segment::{Phdr64, Segment64, Type as SeType, PF_R, PF_W, PF_X},
};
use crate::{ use crate::{
common::{Output, Section}, common::{Output, Section},
@ -13,7 +25,7 @@ use super::ElfObject;
pub struct ElfOutput<'data> { pub struct ElfOutput<'data> {
destination: PathBuf, destination: PathBuf,
file: ELF64, file: ELF64,
segment_data: SegmentData<'data>, input_data: InputData<'data>,
} }
impl<'data> ElfOutput<'data> { impl<'data> ElfOutput<'data> {
@ -32,7 +44,7 @@ impl<'data> ElfOutput<'data> {
Self { Self {
destination, destination,
file: elf, file: elf,
segment_data: SegmentData::new(), input_data: InputData::new(),
} }
} }
@ -42,110 +54,183 @@ impl<'data> ElfOutput<'data> {
Self { Self {
destination, destination,
file: elf_bin_from_object(other), 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 names = Vec::new();
let mut name_idx = 0usize;
for (name, sections) in self.segment_data.iter_mut() { for (name, sections) in self.input_data.sections_mut() {
let mut data = Vec::new(); let mut data_size = 0;
for t in sections.iter_mut() { for t in sections.iter() {
if let Some(iter) = &mut t.data { if let Some(bytes) = t.data {
data.extend(iter.as_mut()); data_size += bytes.len();
} }
} }
if data_size == 0{
continue;
}
names.push(name); names.push(name);
let section = Section64 { let section = Section64 {
name: name.into(), name: name.into(),
header: make_section_header(&names, data.len()), header: make_section_header(name_idx, ShType::ProgBits, data_size),
contents: Contents64::Raw(data), contents: Contents64::Raw(Vec::new()), // placeholder only
}; };
name_idx += name.len() + 1;
self.file.add_section(section); self.file.add_section(section);
} }
let name = ".shstrtab"; let name = ".shstrtab";
names.push(name); names.push(name);
let string_table = build_string_table(&names, true); let string_table = build_string_table(names, true);
let section = Section64 { let section = Section64 {
name: name.into(), name: name.into(),
header: make_section_header(&names, string_table.len()), header: make_section_header(name_idx, ShType::StrTab, string_table.len()),
contents: Contents64::Raw(string_table), contents: Contents64::Raw(string_table),
}; };
self.file.add_section(section); self.file.add_section(section);
Ok(0) Ok(())
} }
fn populate_segment(&mut self, offset: &mut u64, size: u64) { fn populate_segment(&mut self, offset: &mut u64, size: u64, which: SegmentType) {
use elf_utilities::segment::{Phdr64, Segment64, Type}; if size == 0 {
use std::mem::size_of; return;
}
let mut segment = Segment64 { let mut segment = Segment64 {
header: Phdr64::default(), header: Phdr64::default(),
}; };
segment.header.set_type(Type::Load); segment.header.set_type(SeType::Load);
segment.header.p_filesz = size; segment.header.p_filesz = size;
segment.header.p_memsz = size; segment.header.p_memsz = size;
segment.header.p_offset = *offset; segment.header.p_offset = *offset;
// TODO: elfix - add to elf-utilities as add_segment 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;
}
}
self.file.segments.push(segment); self.file.segments.push(segment);
self.file.ehdr.e_phnum += 1; self.file.ehdr.e_phnum += 1;
self.file.ehdr.e_phentsize = size_of::<Phdr64>() as u16; self.file.ehdr.e_phentsize = size_of::<Phdr64>() as u16;
*offset += size; *offset += page_size;
} }
fn populate_segments(&mut self) -> Result<u64, Error> { fn populate_segments(&mut self) -> Result<u64, Error> {
let mut offset = 0u64; let mut offset = 0u64;
// program header/segments // program header/segments
// contains .text + .rodata as one segment // contains .text + .rodata as one segment
self.populate_segment(&mut offset, self.segment_data.program_size()); self.populate_segment(
&mut offset,
self.input_data.program_size(),
SegmentType::Text,
);
// contains .data as one segment // contains .data as one segment
self.populate_segment(&mut offset, self.segment_data.data_size()); self.populate_segment(
&mut offset,
self.input_data.data_size(),
SegmentType::Data,
);
// contains .bss as one segment // contains .bss as one segment
self.populate_segment(&mut offset, self.segment_data.bss_size()); self.populate_segment(&mut offset, self.input_data.bss_size(), SegmentType::Bss);
Ok(0) Ok(offset)
} }
} }
impl<'data> Output<'data> for ElfOutput<'data> { 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> { 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> { fn finalize(mut self) -> Result<PathBuf, Error> {
use std::io::Error as IOError; const EHS: u64 = size_of::<Ehdr64>() as u64;
use std::io::ErrorKind; const PHS: u16 = size_of::<Phdr64>() as u16;
const SHS: u16 = size_of::<Shdr64>() as u16;
self.populate_sections()?; self.populate_sections()?;
self.populate_segments()?; let page_size = self.populate_segments()?;
self.file.finalize();
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;
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 str_path = self.destination.to_str().ok_or_else(|| { let mut writer = file_writer(str_path, 0o755)?;
let ioe = IOError::new(ErrorKind::Other, "Path expansion fail"); let mut offset = 0;
let boxed = Box::new(ioe);
Error::IOError(boxed) // write ELF header
})?; offset += writer.write(&self.file.ehdr.to_le_bytes())?;
// write program header table
for seg in self.file.segments.iter_mut() {
seg.header.p_offset = offset as u64;
offset += writer.write(&seg.header.to_le_bytes())?;
}
ELF64Dumper::new(self.file) eprintln!("SH start: {}", offset);
.generate_elf_file(str_path, 0o755) // write section header table
.map_err(|e| Error::IOError(e))?; for sec in self.file.sections.iter_mut() {
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())?;
}
}
// 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) Ok(self.destination)
} }
} }
fn file_writer(output_filename: &str, permission: u32) -> Result<BufWriter<File>, Error> {
use std::os::unix::fs::OpenOptionsExt;
let file = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.mode(permission)
.open(output_filename)?;
Ok(BufWriter::new(file))
}
// init new ELF64 from an object file meant as executable output // init new ELF64 from an object file meant as executable output
fn elf_bin_from_object(other: &ELF64) -> ELF64 { fn elf_bin_from_object(other: &ELF64) -> ELF64 {
use elf_utilities::header::Type; use elf_utilities::header::Type;
@ -160,29 +245,49 @@ fn elf_bin_from_object(other: &ELF64) -> ELF64 {
elf elf
} }
fn make_section_header(names: &Vec<&str>, size: usize) -> Shdr64 { fn make_section_header(name_idx: usize, stype: ShType, size: usize) -> Shdr64 {
use elf_utilities::section::Type;
let mut h = Shdr64::default(); let mut h = Shdr64::default();
if let Some(name) = names.last() { h.set_type(stype);
if *name == ".shstrtab" {
h.set_type(Type::StrTab); // section index used for name and section indexing (currently same)
} else { let idx = 1 + (name_idx as u32); // add 0 at start
h.set_type(Type::ProgBits); // name index
} h.sh_name = idx;
// link index
h.sh_link = 0;
h.sh_size = size as u64;
// filled at finalize()
// h.sh_offset = offset;
h
}
// section index used for name and section indexing (currently same) fn expand_path(path: &Path) -> Result<&str, Error> {
let idx = (names.len() - 1) as u32; use std::io::Error as IOError;
// name index use std::io::ErrorKind;
h.sh_name = idx;
// link index path.to_str().ok_or_else(|| {
h.sh_link = idx; let ioe = IOError::new(ErrorKind::Other, "Path expansion fail");
h.sh_size = size as u64; let boxed = Box::new(ioe);
// TODO Error::IOError(boxed)
// h.sh_offset = offset; })
}
h
} else { fn next_page(size: u64) -> u64 {
panic!("Unexpected nameless section"); let page_size: u64 = page_size::get() as u64;
}
let pages_needed = (size / page_size) + 1;
page_size * pages_needed
}
fn pad_to_next_page(writer: &mut BufWriter<File>, offset: usize) -> Result<usize, Error> {
let page_size = page_size::get();
let padding = page_size - (offset % page_size);
eprintln!("Padding from: {} with: {}", offset, padding);
writer.seek(SeekFrom::Current(padding.try_into()?))?;
Ok(padding)
} }

@ -0,0 +1,97 @@
use crate::common::SectionInfo;
use crate::common::{Section};
use crate::error::Error;
const SI_TEXT: usize = 0;
const SI_RODATA: usize = 1;
const SI_DATA: usize = 2;
const SI_BSS: usize = 3;
pub enum SegmentType {
Text = SI_TEXT as isize,
Data = SI_DATA as isize,
Bss = SI_BSS as isize,
}
const SEGMENT_NAMES: [&str; 4] = [".text", ".rodata", ".data", ".bss"];
pub struct InputData<'data>([Vec<SectionInfo<'data>>; 4]);
impl<'data> InputData<'data> {
pub fn new() -> Self {
Self([Vec::new(), Vec::new(), Vec::new(), Vec::new()])
}
pub fn append_section(&mut self, section: Section<'data>) -> Result<(), Error> {
match section {
Section::Text(si) => self.0[SI_TEXT].push(si),
Section::Data(si, false) => self.0[SI_DATA].push(si),
Section::Data(si, true) => self.0[SI_RODATA].push(si),
Section::Bss(si) => self.0[SI_BSS].push(si),
}
Ok(())
}
pub fn sections_mut(
&mut self,
) -> impl Iterator<Item = (&'static str, &mut Vec<SectionInfo<'data>>)> {
self.0
.iter_mut()
.enumerate()
.map(|(i, s)| (SEGMENT_NAMES[i], s))
}
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| si.data);
let data2 = rodata_iter.filter_map(|si| si.data);
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
pub fn program_size(&self) -> u64 {
let text_iter = self.0[SI_TEXT].iter();
let rodata_iter = self.0[SI_RODATA].iter();
let mut result = 0u64;
for section in text_iter.chain(rodata_iter) {
result += section.size
}
result
}
// data
pub fn data_size(&self) -> u64 {
let mut result = 0u64;
for section in self.0[SI_DATA].iter() {
result += section.size
}
result
}
// bss
pub fn bss_size(&self) -> u64 {
let mut result = 0u64;
for section in self.0[SI_BSS].iter() {
result += section.size
}
result
}
}
impl Default for InputData<'_> {
fn default() -> Self {
Self::new()
}
}

@ -18,28 +18,14 @@ impl<'data> Linker<'data> {
self.relocatables.push(relocatable); self.relocatables.push(relocatable);
} }
pub fn link<'l: 'data>(&'l self, output: &mut dyn Output<'data>) -> Result<u64, Error> { 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 r in self.relocatables.iter() {
for s in r.sections() { for s in r.sections() {
output.append_section(s?)?; output.append_section(s?)?;
} }
} }
Ok(allocated) Ok(0)
}
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)
} }
} }

Loading…
Cancel
Save