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

@ -3,7 +3,7 @@ use std::iter::once;
use crate::error::Error; use crate::error::Error;
use crate::{ use crate::{
common::{Relocatable, Section, SectionInfo, SymbolIndex}, common::{Relocatable, Section, SectionInfo, SymbolIndex, Symbols},
error::LinkError, error::LinkError,
}; };
@ -42,7 +42,7 @@ pub struct Loadable {
rodata: SegmentSections, rodata: SegmentSections,
data: SegmentSections, data: SegmentSections,
bss: SegmentSections, bss: SegmentSections,
symbol_map: HashMap<String, Vec<SymbolIndex>>, symbol_map: HashMap<String, Symbols>,
} }
impl Loadable { impl Loadable {
@ -57,30 +57,36 @@ impl Loadable {
Ok(()) Ok(())
} }
pub fn process_symbol<R>(&mut self, index: usize, object: &R) -> Result<(), Error> pub fn process_symbol<R>(&mut self, si: SymbolIndex, objects: &[R]) -> Result<(), Error>
where where
R: Relocatable, R: Relocatable,
{ {
if !object.symbol_needs_resolving(index) { let object = objects
.get(si.object_index)
.ok_or(Error::InvalidSectionIndex)?;
if !object.symbol_needs_resolving(si.symbol_index) {
return Ok(()); // local symbols are not stored return Ok(()); // local symbols are not stored
} }
let name = object.symbol_name(index)?; let name = object.symbol_name(si.symbol_index)?;
eprintln!("NAME: {}", name); eprintln!("NAME: {}/{:?}", name, object.symbol_value(si.symbol_index)?);
let si = SymbolIndex { let si = SymbolIndex {
object_index: object.object_index(), object_index: object.object_index(),
symbol_index: index, symbol_index: si.symbol_index,
}; };
if let Some(existing) = self.symbol_map.get_mut(name) { if let Some(existing) = self.symbol_map.get_mut(name) {
existing.push(si); existing.push(si, objects)
} else { } else {
self.symbol_map.insert(name.to_owned(), vec![si]); let mut symbols = Symbols::default();
} symbols.push(si, objects)?;
self.symbol_map.insert(name.to_owned(), symbols);
Ok(()) Ok(())
} }
}
pub fn segment_sections(&self) -> impl Iterator<Item = &SegmentSections> { pub fn segment_sections(&self) -> impl Iterator<Item = &SegmentSections> {
let text = once(&self.text); let text = once(&self.text);

@ -23,6 +23,10 @@ pub trait Relocatable: Display + Sized {
fn symbol_name(&self, index: usize) -> Result<&str, Error>; fn symbol_name(&self, index: usize) -> Result<&str, Error>;
fn symbol_value(&self, index: usize) -> Result<&[u8], Error>;
fn symbol_file_offset(&self, index: usize) -> Result<usize, Error>;
fn symbol_needs_resolving(&self, index: usize) -> bool; fn symbol_needs_resolving(&self, index: usize) -> bool;
fn bytes(&self, offset: u64, size: u64) -> Result<&[u8], Error>; fn bytes(&self, offset: u64, size: u64) -> Result<&[u8], Error>;

@ -1,7 +1,92 @@
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Default, Debug)] use crate::error::{Error, LinkError, Trace, LE_GLOBAL_SYMBOL_DUPLICATE};
use super::Relocatable;
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct SymbolIndex { pub struct SymbolIndex {
pub object_index: usize, pub object_index: usize,
pub symbol_index: usize, pub symbol_index: usize,
} }
#[derive(Default)]
pub struct Symbols {
indexes: Vec<SymbolIndex>,
value_index: Option<usize>,
}
impl Symbols {
pub fn push<R>(&mut self, si: SymbolIndex, objects: &[R]) -> Result<(), Error>
where
R: Relocatable,
{
let object = objects
.get(si.object_index)
.ok_or(Error::InvalidSymbolIndex)?;
let value = object.symbol_value(si.symbol_index)?;
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);
Ok(())
}
} else {
Ok(())
}
}
pub fn value<'o, R>(&self, object: &'o R) -> Result<&'o [u8], Error>
where
R: Relocatable,
{
self.value_index.map_or(Ok(&[]), |v| {
object.symbol_value(self.indexes[v].symbol_index)
})
}
fn duplicate_symbol_error<R>(
si: SymbolIndex,
osi: SymbolIndex,
objects: &[R],
) -> Result<(), Error>
where
R: Relocatable,
{
let object = objects
.get(si.object_index)
.ok_or(Error::InvalidSymbolIndex)?;
let other = objects
.get(osi.object_index)
.ok_or(Error::InvalidObjectIndex)?;
let mut traces = Vec::new();
traces.push(Trace {
origin: object.origin().into(),
offset: object.symbol_file_offset(si.symbol_index)?,
source_info: None,
});
traces.push(Trace {
origin: other.origin().into(),
offset: other.symbol_file_offset(osi.symbol_index)?,
source_info: None,
});
let link_error = LinkError {
code: LE_GLOBAL_SYMBOL_DUPLICATE,
message: "duplicate global symbol found".into(),
traces,
};
Err(Error::LinkingError(link_error))
}
}

@ -9,7 +9,9 @@ pub const LE_GLOBAL_SYMBOL_DUPLICATE: u32 = 10001;
pub enum Error { pub enum Error {
IOError(Box<dyn std::error::Error>), IOError(Box<dyn std::error::Error>),
DataError(PathBuf), // generic "something wrong with data" error, not specific to parsing DataError(PathBuf), // generic "something wrong with data" error, not specific to parsing
InvalidObjectIndex,
InvalidObjectType(u32), InvalidObjectType(u32),
InvalidSectionIndex,
InvalidSectionName, InvalidSectionName,
InvalidSymbolIndex, InvalidSymbolIndex,
InvalidSymbolName, InvalidSymbolName,
@ -23,7 +25,7 @@ pub enum Error {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Trace { pub struct Trace {
pub origin: PathBuf, pub origin: PathBuf,
pub offset: u64, // 0 indicates unknown/invalid pub offset: usize, // 0 indicates unknown/invalid
pub source_info: Option<Box<dyn SourceInfo>>, pub source_info: Option<Box<dyn SourceInfo>>,
} }
@ -41,11 +43,13 @@ impl Error {
match self { match self {
Error::IOError(_) => 100, Error::IOError(_) => 100,
Error::DataError(_) => 800, Error::DataError(_) => 800,
Error::InvalidObjectType(_) => 200, Error::InvalidObjectIndex => 200,
Error::InvalidSectionName => 300, Error::InvalidObjectType(_) => 201,
Error::InvalidSymbolIndex => 325, Error::InvalidSectionIndex => 300,
Error::InvalidSymbolName => 350, Error::InvalidSectionName => 301,
Error::InvalidSectionData => 400, Error::InvalidSectionData => 302,
Error::InvalidSymbolIndex => 400,
Error::InvalidSymbolName => 401,
Error::ParseError(_) => 500, Error::ParseError(_) => 500,
Error::TryFromIntError => 600, Error::TryFromIntError => 600,
Error::InvalidInput => 700, Error::InvalidInput => 700,
@ -79,11 +83,13 @@ impl Display for Error {
match self { match self {
Error::IOError(err) => write!(f, "IO error: {}", err), Error::IOError(err) => write!(f, "IO error: {}", err),
Error::DataError(origin) => write!(f, "Data error in {:?}", origin), Error::DataError(origin) => write!(f, "Data error in {:?}", origin),
Error::InvalidObjectIndex => write!(f, "Invalid section index"),
Error::InvalidObjectType(ot) => write!(f, "Invalid object type: {}", ot), Error::InvalidObjectType(ot) => write!(f, "Invalid object type: {}", ot),
Error::InvalidSectionIndex => write!(f, "Invalid section index"),
Error::InvalidSectionName => write!(f, "Invalid section name"), Error::InvalidSectionName => write!(f, "Invalid section name"),
Error::InvalidSectionData => write!(f, "Invalid section data"),
Error::InvalidSymbolIndex => write!(f, "Invalid symbol index"), Error::InvalidSymbolIndex => write!(f, "Invalid symbol index"),
Error::InvalidSymbolName => write!(f, "Invalid symbol name"), Error::InvalidSymbolName => write!(f, "Invalid symbol name"),
Error::InvalidSectionData => write!(f, "Invalid section data"),
Error::ParseError(err) => write!(f, "Parse error: {}", err), Error::ParseError(err) => write!(f, "Parse error: {}", err),
Error::TryFromIntError => write!(f, "Integer conversion error"), Error::TryFromIntError => write!(f, "Integer conversion error"),
Error::InvalidInput => write!(f, "Input object invalid"), Error::InvalidInput => write!(f, "Input object invalid"),

@ -48,6 +48,23 @@ impl ElfObject {
Ok(result) 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])
} else {
Err(Error::InvalidSectionIndex)
}
} else {
Err(Error::InvalidSymbolIndex)
}
}
fn resolve_name(&self, name_idx: usize, sh_index: usize) -> Result<&str, Error> { fn resolve_name(&self, name_idx: usize, sh_index: usize) -> Result<&str, Error> {
if name_idx == 0 { if name_idx == 0 {
let error = if sh_index == self.ehdr.e_shstrndx.into() { let error = if sh_index == self.ehdr.e_shstrndx.into() {
@ -194,6 +211,22 @@ impl Relocatable for ElfObject {
} }
} }
fn symbol_value(&self, index: usize) -> Result<&[u8], 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)?;
let shdr = self
.shdrs
.get(*sh_index)
.ok_or(Error::InvalidSectionIndex)?;
let sh_offset: usize = shdr.sh_offset as usize;
Ok(sh_offset)
}
fn symbol_needs_resolving(&self, index: usize) -> bool { fn symbol_needs_resolving(&self, index: usize) -> bool {
match self.symbols[index].1.get_bind() { match self.symbols[index].1.get_bind() {
Bind::Global | Bind::Weak => true, Bind::Global | Bind::Weak => true,

@ -10,7 +10,7 @@ where
R: Relocatable, R: Relocatable,
O: Output<R>, O: Output<R>,
{ {
relocatables: Vec<R>, objects: Vec<R>,
loadable: Loadable, loadable: Loadable,
output: O, output: O,
} }
@ -22,21 +22,21 @@ where
{ {
pub fn new(output: O) -> Self { pub fn new(output: O) -> Self {
Self { Self {
relocatables: Vec::new(), objects: Vec::new(),
loadable: Loadable::default(), loadable: Loadable::default(),
output, output,
} }
} }
pub fn add_relocatable(&mut self, origin: PathBuf) -> Result<(), Error> { pub fn add_relocatable(&mut self, origin: PathBuf) -> Result<(), Error> {
let r = R::new(origin, self.relocatables.len())?; let r = R::new(origin, self.objects.len())?;
// TODO: parallelize? // TODO: parallelize?
for section in r.sections() { for section in r.sections() {
self.loadable.process_section(section?)?; self.loadable.process_section(section?)?;
} }
self.relocatables.push(r); self.objects.push(r);
Ok(()) Ok(())
} }
@ -45,15 +45,19 @@ where
self.process_symbols()?; self.process_symbols()?;
self.loadable.set_start_offset(4096); // TODO: get from .start symbol location self.loadable.set_start_offset(4096); // TODO: get from .start symbol location
self.output.finalize(&self.relocatables, &self.loadable) self.output.finalize(&self.objects, &self.loadable)
} }
fn process_symbols(&mut self) -> Result<(), Error> { fn process_symbols(&mut self) -> Result<(), Error> {
for r in &self.relocatables { for r in &self.objects {
let symbol_count = r.symbol_count(); let symbol_count = r.symbol_count();
for i in 0..symbol_count { for i in 0..symbol_count {
self.loadable.process_symbol(i, r)?; let si = SymbolIndex {
object_index: r.object_index(),
symbol_index: i,
};
self.loadable.process_symbol(si, &self.objects)?;
} }
} }
@ -69,7 +73,7 @@ where
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===")?;
for r in self.relocatables.iter() { for r in self.objects.iter() {
write!(f, "{}", r)?; write!(f, "{}", r)?;
} }

Loading…
Cancel
Save