master
Ales Katona 4 years ago
parent 54adb8559d
commit dd255aa67f
Signed by: almindor
GPG Key ID: 2F773149BF38B48F

@ -14,7 +14,7 @@ pub struct SectionInfo<'data> {
pub enum Section<'data> { pub enum Section<'data> {
Text(SectionInfo<'data>), Text(SectionInfo<'data>),
Data(SectionInfo<'data>), Data(SectionInfo<'data>, bool), // readonly bool
Bss(SectionInfo<'data>), Bss(SectionInfo<'data>),
} }
@ -22,7 +22,7 @@ impl Section<'_> {
pub fn size(&self) -> Result<u64, Error> { pub fn size(&self) -> Result<u64, Error> {
match self { match self {
Section::Text(s) => Ok(s.size), Section::Text(s) => Ok(s.size),
Section::Data(s) => Ok(s.size), Section::Data(s, _) => Ok(s.size),
Section::Bss(s) => Ok(s.size), Section::Bss(s) => Ok(s.size),
} }
} }
@ -34,8 +34,10 @@ impl<'data> TryFrom<(&str, SectionInfo<'data>)> for Section<'data> {
fn try_from(value: (&str, SectionInfo<'data>)) -> Result<Self, Self::Error> { fn try_from(value: (&str, SectionInfo<'data>)) -> Result<Self, Self::Error> {
if value.0.starts_with(".text") { if value.0.starts_with(".text") {
Ok(Section::Text(value.1)) Ok(Section::Text(value.1))
} else if value.0.starts_with(".rodata") || value.0.starts_with(".data") { } else if value.0.starts_with(".rodata") {
Ok(Section::Data(value.1)) Ok(Section::Data(value.1, true))
} else if value.0.starts_with(".data") {
Ok(Section::Data(value.1, false))
} else if value.0.starts_with(".bss") { } else if value.0.starts_with(".bss") {
Ok(Section::Bss(value.1)) Ok(Section::Bss(value.1))
} else { } else {
@ -60,7 +62,8 @@ impl Display for Section<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
Section::Text(s) => writeln!(f, "TEXT {}", s), Section::Text(s) => writeln!(f, "TEXT {}", s),
Section::Data(s) => writeln!(f, "DATA {}", s), Section::Data(s, false) => writeln!(f, "DATA {}", s),
Section::Data(s, true) => writeln!(f, "RO-DATA {}", s),
Section::Bss(s) => writeln!(f, "BSS {}", s), Section::Bss(s) => writeln!(f, "BSS {}", s),
} }
} }

@ -21,7 +21,7 @@ impl Storage {
} }
pub fn destination(&self) -> Result<PathBuf, Error> { pub fn destination(&self) -> Result<PathBuf, Error> {
let mut dest = canonicalize(&self.origin).map_err(|e| Error::from(e))?; let mut dest = canonicalize(&self.origin)?;
if !dest.pop() { if !dest.pop() {
let err = std::io::Error::new(ErrorKind::Other, "Destination path invalid"); let err = std::io::Error::new(ErrorKind::Other, "Destination path invalid");
Err(Error::IOError(Box::new(err))) Err(Error::IOError(Box::new(err)))

@ -4,6 +4,7 @@ use crate::linker::Linker;
mod object; mod object;
mod output; mod output;
mod segment;
use elf_utilities::file::ELF64; use elf_utilities::file::ELF64;
pub use object::*; pub use object::*;

@ -1,27 +1,22 @@
use std::path::PathBuf; use std::path::PathBuf;
use elf_utilities::{ use elf_utilities::file::{ELF64Dumper, ELF64};
file::{ELF64Dumper, ELF64},
section::Section64,
segment::{Segment64, Type},
};
use crate::{ use crate::{
common::{Output, Section, SectionInfo}, common::{Output, Section},
error::Error, error::Error,
}; };
use super::segment::*;
use super::ElfObject; use super::ElfObject;
pub struct ElfOutput<'data> { pub struct ElfOutput<'data> {
destination: PathBuf, destination: PathBuf,
dump: ELF64Dumper, file: ELF64,
text: Vec<SectionInfo<'data>>, segment_data: SegmentData<'data>,
data: Vec<SectionInfo<'data>>,
bss: Vec<SectionInfo<'data>>,
} }
impl ElfOutput<'_> { impl<'data> ElfOutput<'data> {
pub fn new(destination: PathBuf) -> Self { pub fn new(destination: PathBuf) -> Self {
use elf_utilities::header::{Class, Data, Machine, Type, Version, OSABI}; use elf_utilities::header::{Class, Data, Machine, Type, Version, OSABI};
@ -36,53 +31,73 @@ impl ElfOutput<'_> {
Self { Self {
destination, destination,
dump: ELF64Dumper::new(elf), file: elf,
text: Vec::new(), segment_data: SegmentData::new(),
data: Vec::new(),
bss: Vec::new(),
} }
} }
pub fn from_object(object: &ElfObject, destination: PathBuf) -> Self { pub fn from_object(object: &ElfObject, destination: PathBuf) -> Self {
use elf_utilities::header::Type;
let other = object.elf(); let other = object.elf();
let mut elf = ELF64::default();
elf.ehdr = other.ehdr.clone();
elf.ehdr.set_elf_type(Type::Exec);
Self { Self {
destination, destination,
dump: ELF64Dumper::new(elf), file: elf_bin_from_object(other),
text: Vec::new(), segment_data: SegmentData::new(),
data: Vec::new(),
bss: Vec::new(),
} }
} }
fn populate_section_data(&mut self) -> Result<u64, Error> { fn populate_sections(&mut self) -> Result<u64, Error> {
use elf_utilities::section::{Contents64, Shdr64, Type}; use elf_utilities::section::{Contents64, Section64, Shdr64};
let mut data = Vec::new(); for (name, sections) in self.segment_data.iter_mut() {
let mut data = Vec::new();
for t in self.text.iter_mut() { for t in sections.iter_mut() {
if let Some(iter) = &mut t.data { if let Some(iter) = &mut t.data {
data.extend(iter.as_mut()); data.extend(iter.as_mut());
}
} }
let section = Section64 {
name: name.into(),
header: Shdr64::default(),
contents: Contents64::Raw(data),
};
self.file.add_section(section);
} }
let mut header = Shdr64::default(); Ok(0)
header.set_type(Type::ProgBits); }
header.sh_entsize = data.len() as u64;
let sec64 = Section64 { fn populate_segment(&mut self, offset: &mut u64, size: u64) {
name: ".text".into(), use elf_utilities::segment::{Phdr64, Segment64, Type};
header, use std::mem::size_of;
contents: Contents64::Raw(data),
let mut segment = Segment64 {
header: Phdr64::default(),
}; };
segment.header.set_type(Type::Load);
segment.header.p_filesz = size;
segment.header.p_memsz = size;
segment.header.p_offset = *offset;
self.dump.file.add_section(sec64); // TODO: elfix - add to elf-utilities as add_segment
self.file.segments.push(segment);
self.file.ehdr.e_phnum += 1;
self.file.ehdr.e_phentsize = size_of::<Phdr64>() as u16;
*offset += size;
}
fn populate_segments(&mut self) -> Result<u64, Error> {
let mut offset = 0u64;
// program header/segments
// contains .text + .rodata as one segment
self.populate_segment(&mut offset, self.segment_data.program_size());
// contains .data as one segment
self.populate_segment(&mut offset, self.segment_data.data_size());
// contains .bss as one segment
self.populate_segment(&mut offset, self.segment_data.bss_size());
Ok(0) Ok(0)
} }
@ -94,24 +109,16 @@ impl<'data> Output<'data> for ElfOutput<'data> {
} }
fn append_section(&mut self, section: Section<'data>) -> Result<(), Error> { fn append_section(&mut self, section: Section<'data>) -> Result<(), Error> {
match section { self.segment_data.append_section(section)
Section::Text(si) => self.text.push(si),
Section::Data(si) => self.data.push(si),
Section::Bss(si) => self.bss.push(si),
}
Ok(())
} }
fn finalize(mut self) -> Result<PathBuf, Error> { fn finalize(mut self) -> Result<PathBuf, Error> {
use std::io::Error as IOError; use std::io::Error as IOError;
use std::io::ErrorKind; use std::io::ErrorKind;
self.populate_section_data()?; self.populate_sections()?;
let mut segment = Segment64::default(); self.populate_segments()?;
segment.header.set_type(Type::Load); self.file.finalize();
self.dump.file.segments.push(segment);
self.dump.file.finalize();
let str_path = self.destination.to_str().ok_or_else(|| { let str_path = self.destination.to_str().ok_or_else(|| {
let ioe = IOError::new(ErrorKind::Other, "Path expansion fail"); let ioe = IOError::new(ErrorKind::Other, "Path expansion fail");
@ -119,10 +126,24 @@ impl<'data> Output<'data> for ElfOutput<'data> {
Error::IOError(boxed) Error::IOError(boxed)
})?; })?;
self.dump ELF64Dumper::new(self.file)
.generate_elf_file(str_path, 0o755) .generate_elf_file(str_path, 0o755)
.map_err(|e| Error::IOError(e))?; .map_err(|e| Error::IOError(e))?;
Ok(self.destination) Ok(self.destination)
} }
} }
// 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
}
Loading…
Cancel
Save