master
Ales Katona 4 years ago
parent 056e7f8426
commit c65e504178
Signed by: almindor
GPG Key ID: 2F773149BF38B48F

@ -7,6 +7,8 @@ use crate::{
error::LinkError,
};
use super::SymbolValue;
pub enum SegmentType {
Text,
Data,
@ -62,11 +64,28 @@ impl SegmentSections {
pub fn data_size(&self) -> u64 {
self.data_size
}
pub fn unresolved_offsets<'s>(
&'s self,
symbols: &'s Symbols,
) -> impl Iterator<Item = usize> + 's {
symbols
.unresolved()
.map(move |si| {
self.sections_info.iter().filter_map(move |section| {
match section.si.section_index == si.section_index {
true => Some(section.output_offset + si.offsets.symbol_offset),
false => None,
}
})
})
.flatten()
}
}
#[derive(Default)]
pub struct Loadable {
start_offset: Option<u64>,
start_offset: Option<usize>,
text: SegmentSections,
rodata: SegmentSections,
@ -100,12 +119,8 @@ impl Loadable {
}
let name = object.symbol_name(si.symbol_index)?;
eprintln!("NAME: {}/{:?}", name, object.symbol_value(si.symbol_index)?);
let si = SymbolIndex {
object_index: object.object_index(),
symbol_index: si.symbol_index,
};
eprint!("OBJECT: {:?}\nNAME: {}/", object.origin(), name);
eprintln!("{:?}", object.symbol_value(si.symbol_index)?);
if let Some(existing) = self.symbol_map.get_mut(name) {
existing.push(si, objects)
@ -188,11 +203,11 @@ impl Loadable {
result
}
pub fn set_start_offset(&mut self, offset: u64) {
pub fn set_start_offset(&mut self, offset: usize) {
self.start_offset = Some(offset);
}
pub fn start_offset(&self) -> Result<u64, Error> {
pub fn start_offset(&self) -> Result<usize, Error> {
self.start_offset.ok_or_else(|| {
let link_error = LinkError {
message: "Program entrypoint not found".into(),
@ -202,4 +217,32 @@ impl Loadable {
Error::LinkingError(link_error)
})
}
pub fn symbol_resolutions<'o, R>(
&'o self,
objects: &'o [R],
) -> impl Iterator<Item = SymbolResolution<'o>>
where
R: Relocatable,
{
self.symbol_map.values().map(move |symbols| {
let value = symbols.value(objects).expect("value"); // TODO
let offsets = self.unresolved_offsets(symbols).collect();
SymbolResolution { value, offsets }
})
}
fn unresolved_offsets<'s>(&'s self, symbols: &'s Symbols) -> impl Iterator<Item = usize> + 's {
self.text
.unresolved_offsets(symbols)
.chain(self.rodata.unresolved_offsets(symbols))
.chain(self.data.unresolved_offsets(symbols))
.chain(self.bss.unresolved_offsets(symbols))
}
}
pub struct SymbolResolution<'b> {
pub value: SymbolValue<'b>,
pub offsets: Vec<usize>, // TODO: box iterator instead
}

@ -7,5 +7,9 @@ pub trait Output<R>
where
R: Relocatable,
{
fn finalize(self, objects: &[R], loadable: &mut Loadable) -> Result<PathBuf, Error>;
fn relocate_sections(&mut self, objects: &[R], loadable: &mut Loadable) -> Result<(), Error>;
fn resolve_symbols(&mut self, objects: &[R], loadable: &mut Loadable) -> Result<(), Error>;
fn finalize(self) -> Result<PathBuf, Error>;
}

@ -3,7 +3,7 @@ use std::{fmt::Display, path::PathBuf};
use crate::error::Error;
use super::Section;
use super::{Section, SymbolOffsets, SymbolValue};
pub type SectionIterBox<'iter> = Box<dyn Iterator<Item = Result<Section, Error>> + 'iter>;
@ -23,9 +23,11 @@ pub trait Relocatable: Display + Sized {
fn symbol_name(&self, index: usize) -> Result<&str, Error>;
fn symbol_value(&self, index: usize) -> Result<&[u8], Error>;
fn symbol_value(&self, index: usize) -> Result<SymbolValue, Error>;
fn symbol_file_offset(&self, index: usize) -> Result<usize, Error>;
fn symbol_offsets(&self, index: usize) -> Result<SymbolOffsets, Error>;
fn symbol_section_index(&self, index: usize) -> Result<usize, Error>;
fn symbol_needs_resolving(&self, index: usize) -> bool;

@ -9,6 +9,7 @@ use super::Relocatable;
#[derive(Clone)]
pub struct SectionInfo {
pub object_index: usize,
pub section_index: usize,
pub file_size: u64,
pub data_size: u64,
pub offset: u64,

@ -7,7 +7,28 @@ use super::Relocatable;
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct SymbolIndex {
pub object_index: usize,
pub section_index: usize,
pub symbol_index: usize,
pub offsets: SymbolOffsets,
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct SymbolOffsets {
pub section_offset: usize, // within the source relocatable
pub symbol_offset: usize, // within the section
}
impl SymbolOffsets {
pub fn file_offset(&self) -> usize {
self.section_offset + self.symbol_offset
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolValue<'o> {
Undefined,
Address(usize),
Value(&'o [u8]),
}
#[derive(Default)]
@ -28,38 +49,52 @@ impl Symbols {
self.indexes.push(si);
if value.len() > 0 {
if let Some(existing) = self.value_index {
let osi = self
.indexes
.get(existing)
.ok_or(Error::InvalidSymbolIndex)?;
Self::duplicate_symbol_error(si, *osi, objects)
} else {
self.value_index = Some(self.indexes.len() - 1);
// save "value index" if we found a value
match value {
SymbolValue::Value(_) | SymbolValue::Address(_) => {
if let Some(existing) = self.value_index {
let osi = self
.indexes
.get(existing)
.ok_or(Error::InvalidSymbolIndex)?;
Self::duplicate_symbol_error(si, *osi, objects)
} else {
self.value_index = Some(self.indexes.len() - 1);
Ok(())
Ok(())
}
}
} else {
Ok(())
SymbolValue::Undefined => Ok(()),
}
}
pub fn value<'o, R>(&self, object: &'o R) -> Result<&'o [u8], Error>
pub fn value<'o, R>(&self, objects: &'o [R]) -> Result<SymbolValue<'o>, Error>
where
R: Relocatable,
{
self.value_index.map_or(Ok(&[]), |v| {
self.value_index.map_or(Ok(SymbolValue::Undefined), |v| {
let si = self.indexes[v];
// can this be compile time checked??
if si.object_index != object.object_index() {
Err(Error::InvalidObjectIndex)
} else {
if let Some(object) = objects.get(si.object_index) {
object.symbol_value(si.symbol_index)
} else {
Err(Error::InvalidObjectIndex)
}
})
}
pub fn unresolved(&self) -> impl Iterator<Item = &SymbolIndex> {
let vi = self.value_index.unwrap_or(std::usize::MAX);
self.indexes
.iter()
.enumerate()
.filter_map(move |(i, s)| match i == vi {
true => None,
false => Some(s),
})
}
fn duplicate_symbol_error<R>(
si: SymbolIndex,
osi: SymbolIndex,
@ -78,12 +113,13 @@ impl Symbols {
traces.push(Trace {
origin: object.origin().into(),
offset: object.symbol_file_offset(si.symbol_index)?,
offset: object.symbol_offsets(si.symbol_index)?.file_offset(),
source_info: None,
});
traces.push(Trace {
origin: other.origin().into(),
offset: other.symbol_file_offset(osi.symbol_index)?,
offset: other.symbol_offsets(osi.symbol_index)?.file_offset(),
source_info: None,
});

@ -4,7 +4,7 @@ use std::{
path::{Path, PathBuf},
};
use crate::common::{Relocatable, Section, SectionInfo};
use crate::common::{Relocatable, Section, SectionInfo, SymbolOffsets, SymbolValue};
use crate::{common::SectionIterBox, error::Error};
use elf_utilities::{
header::Ehdr64,
@ -13,13 +13,19 @@ use elf_utilities::{
};
use memmap::Mmap;
struct ElfSymbol {
s64: Symbol64,
sh_index: usize,
rel_offset: usize,
}
pub struct ElfObject {
object_index: usize,
origin: PathBuf,
data: Mmap,
ehdr: Ehdr64,
shdrs: Vec<Shdr64>,
symbols: Vec<(usize, Symbol64)>,
symbols: Vec<ElfSymbol>,
}
impl ElfObject {
@ -48,15 +54,22 @@ impl ElfObject {
Ok(result)
}
fn resolve_symbol_value(&self, symbol_index: usize) -> Result<&[u8], Error> {
if let Some((_, s64)) = self.symbols.get(symbol_index) {
if s64.st_size == 0 {
Ok(&[])
} else if let Some(shdr) = self.shdrs.get(s64.st_shndx as usize) {
let start: usize = (shdr.sh_offset + s64.st_value) as usize;
let end: usize = start + s64.st_size as usize;
Ok(&self.data[start..end])
fn resolve_symbol_value(&self, symbol_index: usize) -> Result<SymbolValue, Error> {
if let Some(symbol) = self.symbols.get(symbol_index) {
let idx = symbol.s64.st_shndx as usize;
if idx == 0 {
Ok(SymbolValue::Undefined)
} else if let Some(shdr) = self.shdrs.get(idx) {
let sym_size = symbol.s64.st_size as usize;
let start: usize = (shdr.sh_offset + symbol.s64.st_value) as usize;
if sym_size > 0 {
let end: usize = start + sym_size;
Ok(SymbolValue::Value(&self.data[start..end]))
} else {
Ok(SymbolValue::Address(start))
}
} else {
Err(Error::InvalidSectionIndex)
}
@ -104,7 +117,8 @@ impl ElfObject {
}
fn populate(&mut self) -> Result<(), Error> {
for i in 0..self.ehdr.e_shnum {
for i in 1..self.ehdr.e_shnum {
// skip null section
let i_usize: usize = i.into();
let sh_start = self.ehdr.e_shoff as usize;
let sh_size = usize::from(self.ehdr.e_shentsize);
@ -113,24 +127,10 @@ impl ElfObject {
let shdr: Shdr64 = bincode::deserialize(&self.data[offset..offset + sh_size])
.map_err(|err| Error::ParseError(err))?;
if shdr.get_type() == Type::SymTab {
let ent_size = shdr.sh_entsize as usize;
let offset = shdr.sh_offset as usize;
let count = shdr.sh_size as usize / ent_size;
for s_i in 1..count {
// skip null-symbol
let start = offset + s_i * ent_size;
let s64 = Symbol64::deserialize(&self.data, start)
.map_err(|err| Error::ParseError(err))?;
match s64.get_type() {
SymType::Object | SymType::Func | SymType::NoType => {
self.symbols.push((shdr.sh_link as usize, s64))
}
_ => {}
}
}
match shdr.get_type() {
Type::SymTab => self.populate_symtab(&shdr, i as usize)?,
Type::Rel | Type::Rela => self.populate_rela(&shdr)?,
_ => {}
}
self.shdrs.push(shdr);
@ -139,7 +139,36 @@ impl ElfObject {
Ok(())
}
fn make_section(&self, shdr: &Shdr64) -> Option<Result<Section, Error>> {
fn populate_symtab(&mut self, shdr: &Shdr64, sh_index: usize) -> Result<(), Error> {
let ent_size = shdr.sh_entsize as usize;
let offset = shdr.sh_offset as usize;
let count = shdr.sh_size as usize / ent_size;
for s_i in 1..count {
// skip null-symbol
let start = offset + s_i * ent_size;
let s64 =
Symbol64::deserialize(&self.data, start).map_err(|err| Error::ParseError(err))?;
match s64.get_type() {
SymType::Object | SymType::Func | SymType::NoType => self.symbols.push(ElfSymbol {
sh_index,
s64,
rel_offset: 0,
}),
_ => {}
}
}
Ok(())
}
fn populate_rela(&mut self, shdr: &Shdr64) -> Result<(), Error> {
// TODO
Ok(())
}
fn make_section(&self, shdr: &Shdr64, section_index: usize) -> Option<Result<Section, Error>> {
let sh_index: usize = self.ehdr.e_shstrndx.into();
let name = match self.resolve_name(shdr.sh_name as usize, sh_index) {
Ok(n) => n,
@ -148,6 +177,7 @@ impl ElfObject {
let mut si = SectionInfo {
object_index: self.object_index,
section_index,
file_size: shdr.sh_size,
data_size: shdr.sh_size,
offset: shdr.sh_offset,
@ -182,13 +212,14 @@ impl Relocatable for ElfObject {
}
fn sections(&self) -> SectionIterBox {
let iter = self
.shdrs
.iter()
.filter_map(move |shdr| match shdr.get_type() {
Type::ProgBits | Type::NoBits => self.make_section(shdr),
_ => None,
});
let iter =
self.shdrs
.iter()
.enumerate()
.filter_map(move |(i, shdr)| match shdr.get_type() {
Type::ProgBits | Type::NoBits => self.make_section(shdr, i),
_ => None,
});
Box::new(iter)
}
@ -205,30 +236,39 @@ impl Relocatable for ElfObject {
fn symbol_name(&self, index: usize) -> Result<&str, Error> {
if let Some(symbol) = self.symbols.get(index) {
self.resolve_name(symbol.1.st_name as usize, symbol.0)
self.resolve_name(symbol.s64.st_name as usize, symbol.sh_index)
} else {
Err(Error::InvalidSymbolIndex)
}
}
fn symbol_value(&self, index: usize) -> Result<&[u8], Error> {
fn symbol_value(&self, index: usize) -> Result<SymbolValue, Error> {
self.resolve_symbol_value(index)
}
fn symbol_file_offset(&self, index: usize) -> Result<usize, Error> {
let (sh_index, s64) = self.symbols.get(index).ok_or(Error::InvalidSymbolIndex)?;
fn symbol_section_index(&self, index: usize) -> Result<usize, Error> {
let symbol = self.symbols.get(index).ok_or(Error::InvalidSymbolIndex)?;
Ok(symbol.sh_index)
}
fn symbol_offsets(&self, index: usize) -> Result<SymbolOffsets, Error> {
let symbol = self.symbols.get(index).ok_or(Error::InvalidSymbolIndex)?;
let shdr = self
.shdrs
.get(*sh_index)
.get(symbol.sh_index)
.ok_or(Error::InvalidSectionIndex)?;
let sh_offset: usize = shdr.sh_offset as usize;
Ok(sh_offset + s64.st_value as usize)
Ok(SymbolOffsets {
section_offset: sh_offset,
symbol_offset: symbol.rel_offset,
})
}
fn symbol_needs_resolving(&self, index: usize) -> bool {
match self.symbols[index].1.get_bind() {
match self.symbols[index].s64.get_bind() {
Bind::Global | Bind::Weak => true,
_ => false,
}

@ -1,4 +1,10 @@
use std::{fs::File, io::BufWriter, io::Write, mem::size_of, path::PathBuf};
use std::{
fs::File,
io::BufWriter,
io::{Seek, SeekFrom, Write},
mem::size_of,
path::PathBuf,
};
use elf_utilities::{
header::Ehdr64,
@ -7,7 +13,9 @@ use elf_utilities::{
};
use crate::{
common::{expand_path, pad_to_next_page, Loadable, Output, Relocatable, SegmentType},
common::{
expand_path, pad_to_next_page, Loadable, Output, Relocatable, SegmentType, SymbolValue,
},
error::Error,
};
@ -58,11 +66,11 @@ impl ElfOutput {
}
impl Output<ElfObject> for ElfOutput {
fn finalize(
mut self,
fn relocate_sections(
&mut self,
objects: &[ElfObject],
loadable: &mut Loadable,
) -> Result<PathBuf, Error> {
) -> Result<(), 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;
@ -72,7 +80,7 @@ impl Output<ElfObject> for ElfOutput {
ehdr.e_shnum = SECTION_NAMES.len() as u16;
ehdr.e_phnum = 3u16; // .text, .rodata + .data, .bss
ehdr.e_shstrndx = ehdr.e_shnum - 1; // .shstrab is always last
ehdr.e_entry = loadable.start_offset()?;
ehdr.e_entry = loadable.start_offset()? as u64;
ehdr.e_phentsize = PHS;
ehdr.e_shentsize = SHS;
ehdr.e_phoff = EHS;
@ -124,9 +132,7 @@ impl Output<ElfObject> for ElfOutput {
let bytes = object.bytes(si.offset, si.file_size)?;
offset += self.writer.write(bytes)?;
}
// for bytes in loadable.program_bytes(objects) {
// offset += self.writer.write(bytes?)?;
// }
offset += pad_to_next_page(&mut self.writer, offset)?;
eprintln!("Data start: {}", offset);
@ -139,6 +145,36 @@ impl Output<ElfObject> for ElfOutput {
offset += self.writer.write(bytes)?;
}
Ok(())
}
fn resolve_symbols(
&mut self,
objects: &[ElfObject],
loadable: &mut Loadable,
) -> Result<(), Error> {
for resolution in loadable.symbol_resolutions(objects) {
for offset in resolution.offsets {
match resolution.value {
SymbolValue::Value(v) => {
eprintln!("Writing value {:?} to {}", resolution.value, offset);
self.writer.seek(SeekFrom::Start(offset as u64))?;
self.writer.write(v)?;
}
SymbolValue::Address(a) => {
eprintln!("TODO");
}
SymbolValue::Undefined => {
eprintln!("TODO2");
}
}
}
}
Ok(())
}
fn finalize(mut self) -> Result<PathBuf, Error> {
self.writer.flush()?;
Ok(self.destination)

@ -44,8 +44,14 @@ where
pub fn link(mut self) -> Result<PathBuf, Error> {
self.process_symbols()?;
self.loadable.set_start_offset(4096); // TODO: get from .start symbol location
self.output.finalize(&self.objects, &mut self.loadable)
self.loadable.set_start_offset(4096); // TODO
self.output
.relocate_sections(&self.objects, &mut self.loadable)?;
self.output
.resolve_symbols(&self.objects, &mut self.loadable)?;
self.output.finalize()
}
fn process_symbols(&mut self) -> Result<(), Error> {
@ -55,7 +61,9 @@ where
for i in 0..symbol_count {
let si = SymbolIndex {
object_index: r.object_index(),
section_index: r.symbol_section_index(i)?,
symbol_index: i,
offsets: r.symbol_offsets(i)?,
};
self.loadable.process_symbol(si, &self.objects)?;
}

Loading…
Cancel
Save