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

@ -5,11 +5,13 @@ use crate::error::Error;
use super::Section; 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 /// Contains all the needed getters to construct a final
/// mushed and relocated executable from an object file /// 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 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}, 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)] #[derive(Clone)]
pub struct SectionInfo<'data> { pub struct SectionInfo {
pub size: u64, pub file_size: u64,
pub data: Option<&'data [u8]>, pub data_size: u64,
pub data_index: Option<(usize, usize)>, // object/section
pub offset: u64, pub offset: u64,
} }
#[derive(Clone)] #[derive(Clone)]
pub enum Section<'data> { pub enum Section {
Text(SectionInfo<'data>), Text(SectionInfo),
Data(SectionInfo<'data>, bool), // readonly bool Data(SectionInfo, bool), // readonly bool
Bss(SectionInfo<'data>), Bss(SectionInfo),
} }
impl Section<'_> { impl Section {
pub fn size(&self) -> Result<u64, Error> { 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 { match self {
Section::Text(s) => Ok(s.size), Section::Text(s) => Ok(s.data_size),
Section::Data(s, _) => Ok(s.size), Section::Data(s, _) => Ok(s.data_size),
Section::Bss(s) => Ok(s.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; 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") { if value.0.starts_with(".text") {
Ok(Section::Text(value.1)) Ok(Section::Text(value.1))
} else if value.0.starts_with(".rodata") { } 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 { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!( write!(
f, f,
"size: {}, data: {}, offset: {}", "file_size: {}, data_size: {}, data: {}, offset: {}",
self.size, self.file_size,
self.data.is_some(), self.data_size,
self.data_index.is_some(),
self.offset, self.offset,
) )
} }
} }
impl Display for Section<'_> { 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),

@ -12,7 +12,7 @@ use elf_utilities::file::ELF64;
pub use object::*; pub use object::*;
pub use output::*; pub use output::*;
impl<'data> Linker<'data, ElfObject, ElfOutput<'data>> { impl Linker<ElfObject, ElfOutput> {
// shortcut to avoid turbofish // shortcut to avoid turbofish
pub fn elf(destination: PathBuf) -> Result<Self, Error> { pub fn elf(destination: PathBuf) -> Result<Self, Error> {
Ok(Self::new(ElfOutput::new(destination)?)) 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 { fn origin(&self) -> &Path {
&self.origin &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}; use elf_utilities::section::{Contents64, Type};
let iter = self let iter = self
.elf .elf
.sections .sections
.iter() .iter()
.filter_map(|s| match s.header.get_type() { .enumerate()
.filter_map(|(i, s)| match s.header.get_type() {
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 {
@ -51,8 +52,9 @@ impl<'data> Relocatable<'data> for ElfObject {
_ => None, _ => None,
} { } {
let si = SectionInfo { let si = SectionInfo {
size: s.header.sh_size, file_size: s.header.sh_size,
data: Some(di), data_size: s.header.sh_size,
data_index: Some((0, i)), // TODO
offset: s.header.sh_offset, offset: s.header.sh_offset,
}; };
let s_name: &str = &s.name; let s_name: &str = &s.name;
@ -70,8 +72,9 @@ impl<'data> Relocatable<'data> for ElfObject {
} }
} }
Type::NoBits => Some(Ok(Section::Bss(SectionInfo { Type::NoBits => Some(Ok(Section::Bss(SectionInfo {
size: 0, file_size: 0,
data: None, data_size: s.header.sh_size,
data_index: None,
offset: s.header.sh_offset, offset: s.header.sh_offset,
}))), }))),
_ => None, _ => None,
@ -79,6 +82,16 @@ impl<'data> Relocatable<'data> for ElfObject {
Box::new(iter) 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 { impl Display for ElfObject {

@ -22,21 +22,21 @@ use crate::{
use super::segment::*; use super::segment::*;
use super::ElfObject; use super::ElfObject;
pub struct ElfOutput<'data> { pub struct ElfOutput {
destination: PathBuf, destination: PathBuf,
file: ELF64, file: ELF64,
input_data: OutputData<'data>, input_data: OutputData,
writer: BufWriter<File>, writer: BufWriter<File>,
} }
impl<'data> ElfOutput<'data> { impl ElfOutput {
pub fn new(destination: PathBuf) -> Result<Self, Error> { pub fn new(destination: PathBuf) -> Result<Self, Error> {
use elf_utilities::header::{Class, Data, Machine, Type, Version, OSABI}; use elf_utilities::header::{Class, Data, Machine, Type, Version, OSABI};
let mut elf = ELF64::default(); let mut elf = ELF64::default();
elf.ehdr.set_elf_type(Type::Exec); elf.ehdr.set_elf_type(Type::Exec);
elf.ehdr.set_class(Class::Bit64); 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_object_version(Version::Current);
elf.ehdr.set_file_version(Version::Current); elf.ehdr.set_file_version(Version::Current);
elf.ehdr.set_osabi(OSABI::Linux); elf.ehdr.set_osabi(OSABI::Linux);
@ -79,9 +79,7 @@ impl<'data> ElfOutput<'data> {
let mut data_size = 0; let mut data_size = 0;
for t in sections.iter() { for t in sections.iter() {
if let Some(bytes) = t.data { data_size += t.data_size;
data_size += bytes.len();
}
} }
if data_size == 0 { if data_size == 0 {
@ -103,7 +101,7 @@ impl<'data> ElfOutput<'data> {
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(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), contents: Contents64::Raw(string_table),
}; };
self.file.add_section(section); self.file.add_section(section);
@ -131,7 +129,7 @@ impl<'data> ElfOutput<'data> {
SegmentType::Data => segment.header.p_flags = PF_R | PF_W, SegmentType::Data => segment.header.p_flags = PF_R | PF_W,
SegmentType::Bss => { SegmentType::Bss => {
segment.header.p_flags = PF_R; segment.header.p_flags = PF_R;
segment.header.p_memsz = 0; segment.header.p_filesz = 0;
page_size = 0; page_size = 0;
} }
} }
@ -161,12 +159,12 @@ impl<'data> ElfOutput<'data> {
} }
} }
impl<'data> Output<'data> for ElfOutput<'data> { impl Output<ElfObject> for ElfOutput {
fn process_section(&mut self, section: Section<'data>) -> Result<(), Error> { fn process_section(&mut self, section: Section) -> Result<(), Error> {
self.input_data.append_section(section) 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 EHS: u64 = size_of::<Ehdr64>() as u64;
const PHS: u16 = size_of::<Phdr64>() as u16; const PHS: u16 = size_of::<Phdr64>() as u16;
const SHS: u16 = size_of::<Shdr64>() 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)?; offset += pad_to_next_page(&mut self.writer, offset)?;
eprintln!("Prog start: {}", offset); eprintln!("Prog start: {}", offset);
// write section/segment data // write section/segment data
for bytes in self.input_data.program_bytes() { for bytes in self.input_data.program_bytes(objects) {
offset += self.writer.write(bytes)?; offset += self.writer.write(bytes?)?;
} }
offset += pad_to_next_page(&mut self.writer, offset)?; offset += pad_to_next_page(&mut self.writer, offset)?;
eprintln!("Data start: {}", offset); eprintln!("Data start: {}", offset);
for bytes in self.input_data.data_bytes() { for bytes in self.input_data.data_bytes(objects) {
offset += self.writer.write(bytes)?; offset += self.writer.write(bytes?)?;
} }
self.writer.flush()?; self.writer.flush()?;
@ -252,7 +250,7 @@ fn elf_bin_from_object(other: &ELF64) -> ELF64 {
elf 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(); let mut h = Shdr64::default();
h.set_type(stype); h.set_type(stype);
@ -262,7 +260,7 @@ fn make_section_header(name_idx: usize, stype: ShType, size: usize) -> Shdr64 {
h.sh_name = idx; h.sh_name = idx;
// link index // link index
h.sh_link = 0; h.sh_link = 0;
h.sh_size = size as u64; h.sh_size = size;
// filled at finalize() // filled at finalize()
// h.sh_offset = offset; // h.sh_offset = offset;

@ -1,7 +1,9 @@
use crate::common::Section; use crate::common::{Relocatable, Section};
use crate::common::SectionInfo; use crate::common::SectionInfo;
use crate::error::Error; use crate::error::Error;
use super::ElfObject;
const SI_TEXT: usize = 0; const SI_TEXT: usize = 0;
const SI_RODATA: usize = 1; const SI_RODATA: usize = 1;
const SI_DATA: usize = 2; const SI_DATA: usize = 2;
@ -15,14 +17,14 @@ pub enum SegmentType {
const SEGMENT_NAMES: [&str; 4] = [".text", ".rodata", ".data", ".bss"]; 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 { pub fn new() -> Self {
Self([Vec::new(), Vec::new(), Vec::new(), Vec::new()]) 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 { match section {
Section::Text(si) => self.0[SI_TEXT].push(si), Section::Text(si) => self.0[SI_TEXT].push(si),
Section::Data(si, false) => self.0[SI_DATA].push(si), Section::Data(si, false) => self.0[SI_DATA].push(si),
@ -35,25 +37,38 @@ impl<'data> OutputData<'data> {
pub fn sections_mut( pub fn sections_mut(
&mut self, &mut self,
) -> impl Iterator<Item = (&'static str, &mut Vec<SectionInfo<'data>>)> { ) -> impl Iterator<Item = (&'static str, &mut Vec<SectionInfo>)> {
self.0 self.0
.iter_mut() .iter_mut()
.enumerate() .enumerate()
.map(|(i, s)| (SEGMENT_NAMES[i], s)) .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 text_iter = self.0[SI_TEXT].iter();
let rodata_iter = self.0[SI_RODATA].iter(); let rodata_iter = self.0[SI_RODATA].iter();
let data1 = text_iter.filter_map(|si| si.data); let data1 = text_iter.filter_map(move |si| match si.data_index {
let data2 = rodata_iter.filter_map(|si| si.data); 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]> { pub fn data_bytes<'l>(&'l self, objects: &'l Vec<ElfObject>) -> impl Iterator<Item = Result<&'l [u8], Error>> {
self.0[SI_DATA].iter().filter_map(|si| si.data) 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 // .text + .rodata
@ -63,7 +78,7 @@ impl<'data> OutputData<'data> {
let mut result = 0u64; let mut result = 0u64;
for section in text_iter.chain(rodata_iter) { for section in text_iter.chain(rodata_iter) {
result += section.size result += section.data_size
} }
result result
@ -73,7 +88,7 @@ impl<'data> OutputData<'data> {
pub fn data_size(&self) -> u64 { pub fn data_size(&self) -> u64 {
let mut result = 0u64; let mut result = 0u64;
for section in self.0[SI_DATA].iter() { for section in self.0[SI_DATA].iter() {
result += section.size result += section.data_size
} }
result result
@ -83,14 +98,14 @@ impl<'data> OutputData<'data> {
pub fn bss_size(&self) -> u64 { pub fn bss_size(&self) -> u64 {
let mut result = 0u64; let mut result = 0u64;
for section in self.0[SI_BSS].iter() { for section in self.0[SI_BSS].iter() {
result += section.size result += section.data_size
} }
result result
} }
} }
impl Default for OutputData<'_> { impl Default for OutputData {
fn default() -> Self { fn default() -> Self {
Self::new() 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::{ use crate::{
common::{Output, Relocatable}, common::{Output, Relocatable},
error::Error, error::Error,
}; };
pub struct Linker<'data, R, O> pub struct Linker<R, O>
where where
R: Relocatable<'data>, R: Relocatable,
O: Output<'data>, O: Output<R>,
{ {
relocatables: Vec<R>, relocatables: Vec<R>,
output: O, output: O,
_p: PhantomData<&'data ()>,
} }
impl<'data, R, O> Linker<'data, R, O> impl<R, O> Linker<R, O>
where where
R: Relocatable<'data>, R: Relocatable,
O: Output<'data>, O: Output<R>,
{ {
pub fn new(output: O) -> Self { pub fn new(output: O) -> Self {
Self { Self {
relocatables: Vec::new(), relocatables: Vec::new(),
output, output,
_p: PhantomData::default(),
} }
} }
@ -34,14 +32,14 @@ where
Ok(()) Ok(())
} }
pub fn link(&mut self) -> Result<PathBuf, Error> { pub fn link(mut self) -> Result<PathBuf, Error> {
for r in self.relocatables.iter() { for r in self.relocatables.iter() {
for s in r.sections() { for s in r.sections() {
self.output.process_section(s?)?; self.output.process_section(s?)?;
} }
} }
self.output.finalize() self.output.finalize(&self.relocatables)
} }
pub fn object_path(origin: &Path) -> Result<PathBuf, Error> { 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 where
R: Relocatable<'data>, R: Relocatable,
O: Output<'data>, O: Output<R>,
{ {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "===Relocatables===")?; writeln!(f, "===Relocatables===")?;

@ -11,15 +11,15 @@ fn main() {
let mut args = std::env::args().peekable(); let mut args = std::env::args().peekable();
// can this miss? // 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"); let mut linker = Linker::elf(destination).expect("Linker init");
while args.peek().is_some() { while let Some(path) = args.next() {
let path = PathBuf::from(args.next().expect("Argument expansion")); let path = PathBuf::from(path);
linker.add_relocatable(path); linker.add_relocatable(path).expect("Data input");
} }
let outpath = linker.link().expect("Linking"); let outpath = linker.link().expect("Linking");

Loading…
Cancel
Save