use indexes instead of references

master
Ales Katona 4 years ago
parent e52e3a2761
commit 818e0a53f3
Signed by: almindor
GPG Key ID: 2F773149BF38B48F

@ -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<R>
where
R: Relocatable
{
fn process_section(&mut self, section: Section) -> Result<(), Error>;
fn finalize(self) -> Result<PathBuf, Error>;
fn finalize(self, objects: &Vec<R>) -> Result<PathBuf, Error>;
}
pub struct DummyOutput;
impl<'data> Output<'data> for DummyOutput {
fn process_section(&mut self, section: Section<'data>) -> Result<(), Error> {
impl<R> Output<R> for DummyOutput
where
R: Relocatable
{
fn process_section(&mut self, section: Section) -> Result<(), Error> {
eprintln!("Appending section: {}", section);
Ok(())
}
fn finalize(self) -> Result<PathBuf, Error> {
fn finalize(self, objects: &Vec<R>) -> Result<PathBuf, Error> {
todo!();
}
}

@ -5,11 +5,13 @@ use crate::error::Error;
use super::Section;
pub type BSI<'iter, 'data> = Box<dyn Iterator<Item = Result<Section<'data>, Error>> + 'iter>;
pub type BSI<'iter> = Box<dyn Iterator<Item = Result<Section, Error>> + 'iter>;
/// Contains all the needed getters to construct a final
/// mushed and relocated executable from an object file
pub trait Relocatable<'data>: Display + TryFrom<PathBuf, Error = Error> {
pub trait Relocatable: Display + TryFrom<PathBuf, Error = Error> {
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>;
}

@ -4,46 +4,43 @@ use std::{
fmt::{Display, Formatter},
};
// 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 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<u64, Error> {
impl Section {
pub fn file_size(&self) -> Result<u64, Error> {
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<u64, Error> {
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<Self, Self::Error> {
fn try_from(value: (&str, SectionInfo)) -> Result<Self, Self::Error> {
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),

@ -12,7 +12,7 @@ use elf_utilities::file::ELF64;
pub use object::*;
pub use output::*;
impl<'data> Linker<'data, ElfObject, ElfOutput<'data>> {
impl Linker<ElfObject, ElfOutput> {
// shortcut to avoid turbofish
pub fn elf(destination: PathBuf) -> Result<Self, Error> {
Ok(Self::new(ElfOutput::new(destination)?))

@ -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 &section.contents {
Contents64::Raw(v) => Ok(&v),
_ => Err(Error::InvalidSectionData)
}
}
}
impl Display for ElfObject {

@ -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<File>,
}
impl<'data> ElfOutput<'data> {
impl ElfOutput {
pub fn new(destination: PathBuf) -> Result<Self, Error> {
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<ElfObject> for ElfOutput {
fn process_section(&mut self, section: Section) -> Result<(), Error> {
self.input_data.append_section(section)
}
fn finalize(mut self) -> Result<PathBuf, Error> {
fn finalize(mut self, objects: &Vec<ElfObject>) -> Result<PathBuf, Error> {
const EHS: u64 = size_of::<Ehdr64>() as u64;
const PHS: u16 = size_of::<Phdr64>() as u16;
const SHS: u16 = size_of::<Shdr64>() 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;

@ -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<SectionInfo<'data>>; 4]);
pub struct OutputData([Vec<SectionInfo>; 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<Item = (&'static str, &mut Vec<SectionInfo<'data>>)> {
) -> impl Iterator<Item = (&'static str, &mut Vec<SectionInfo>)> {
self.0
.iter_mut()
.enumerate()
.map(|(i, s)| (SEGMENT_NAMES[i], s))
}
pub fn program_bytes<'local>(&'local self) -> impl Iterator<Item = &'local [u8]> {
pub fn program_bytes<'l>(&'l self, objects: &'l Vec<ElfObject>) -> impl Iterator<Item = Result<&'l [u8], Error>> {
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<Item = &'local [u8]> {
self.0[SI_DATA].iter().filter_map(|si| si.data)
pub fn data_bytes<'l>(&'l self, objects: &'l Vec<ElfObject>) -> impl Iterator<Item = Result<&'l [u8], Error>> {
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()
}

@ -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<R, O>
where
R: Relocatable<'data>,
O: Output<'data>,
R: Relocatable,
O: Output<R>,
{
relocatables: Vec<R>,
output: O,
_p: PhantomData<&'data ()>,
}
impl<'data, R, O> Linker<'data, R, O>
impl<R, O> Linker<R, O>
where
R: Relocatable<'data>,
O: Output<'data>,
R: Relocatable,
O: Output<R>,
{
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<PathBuf, Error> {
pub fn link(mut self) -> Result<PathBuf, Error> {
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<PathBuf, Error> {
@ -56,10 +54,10 @@ where
}
}
impl<'data, R, O> Display for Linker<'data, R, O>
impl<R, O> Display for Linker<R, O>
where
R: Relocatable<'data>,
O: Output<'data>,
R: Relocatable,
O: Output<R>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "===Relocatables===")?;

@ -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");

Loading…
Cancel
Save