add basics of symbol processing

master
Ales Katona 4 years ago
parent 2183422e3d
commit 47e4104247
Signed by: almindor
GPG Key ID: 2F773149BF38B48F

@ -1,8 +1,12 @@
use std::iter::once; use std::{collections::HashMap, iter::once, rc::Rc};
use crate::common::SectionInfo;
use crate::common::{Relocatable, Section};
use crate::error::Error; use crate::error::Error;
use crate::{
common::{Relocatable, Section, SectionInfo, Symbol},
error::{LinkError, Trace, LE_GLOBAL_SYMBOL_DUPLICATE},
};
use super::Binding;
pub enum SegmentType { pub enum SegmentType {
Text, Text,
@ -40,6 +44,8 @@ pub struct Loadable {
rodata: SegmentSections, rodata: SegmentSections,
data: SegmentSections, data: SegmentSections,
bss: SegmentSections, bss: SegmentSections,
symbol_map: HashMap<Rc<str>, Symbol>,
} }
impl Loadable { impl Loadable {
@ -54,6 +60,38 @@ impl Loadable {
Ok(()) Ok(())
} }
pub fn process_symbol<R>(&mut self, symbol: Symbol, objects: &[R]) -> Result<(), Error>
where
R: Relocatable,
{
Ok(())
// if symbol.binding == Binding::Local {
// return Ok(()); // local symbols are not stored
// }
// let key = Rc::from(symbol.name.as_str());
// let object_index = symbol.object_index;
// if let Some(prev) = self.symbol_map.insert(key, symbol) {
// let prev_trace = Trace {
// origin: objects[prev.object_index].origin().into(),
// ..Default::default()
// };
// let symbol_trace = Trace {
// origin: objects[object_index].origin().into(),
// ..Default::default()
// };
// let link_error = LinkError {
// message: format!("Duplicate global symbol found: {}", prev.name),
// code: LE_GLOBAL_SYMBOL_DUPLICATE,
// traces: vec![prev_trace, symbol_trace],
// };
// Err(Error::LinkingError(link_error))
// } else {
// Ok(())
// }
}
pub const fn section_names() -> &'static [&'static str] { pub const fn section_names() -> &'static [&'static str] {
&[".text", ".rodata", ".data", ".bss"] &[".text", ".rodata", ".data", ".bss"]
} }

@ -1,4 +1,4 @@
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq, Eq)]
pub enum Binding { pub enum Binding {
Local, Local,
Global, Global,
@ -6,6 +6,7 @@ pub enum Binding {
} }
pub struct Symbol { pub struct Symbol {
pub object_index: usize,
pub name: String, pub name: String,
pub binding: Binding, pub binding: Binding,
pub address: u64, pub address: u64,

@ -3,6 +3,8 @@ use std::{
path::PathBuf, path::PathBuf,
}; };
pub const LE_GLOBAL_SYMBOL_DUPLICATE: u32 = 701;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
IOError(Box<dyn std::error::Error>), IOError(Box<dyn std::error::Error>),
@ -11,19 +13,24 @@ pub enum Error {
InvalidSectionData, InvalidSectionData,
ParseError(Box<dyn std::error::Error>), ParseError(Box<dyn std::error::Error>),
TryFromIntError, TryFromIntError,
LinkingError(Trace), LinkingError(LinkError),
} }
// "backtrace" for error origin
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Trace { pub struct Trace {
pub code: u32, // specific trace code, should be >= 700
pub message: &'static str,
pub origin: PathBuf, pub origin: PathBuf,
pub offset: u64, // 0 indicates unknown/invalid pub offset: u64, // 0 indicates unknown/invalid
pub source_info: Option<Box<dyn SourceInfo>>, pub source_info: Option<Box<dyn SourceInfo>>,
} }
// "backtrace" for error origin
#[derive(Debug, Default)]
pub struct LinkError {
pub code: u32, // specific trace code, should be >= 700
pub message: String,
pub traces: Vec<Trace>,
}
impl Error { impl Error {
// used for programmatic input/output handling, IDE's etc. // used for programmatic input/output handling, IDE's etc.
pub fn code(&self) -> u32 { pub fn code(&self) -> u32 {
@ -34,7 +41,7 @@ impl Error {
Error::InvalidSectionData => 400, Error::InvalidSectionData => 400,
Error::ParseError(_) => 500, Error::ParseError(_) => 500,
Error::TryFromIntError => 600, Error::TryFromIntError => 600,
Error::LinkingError(trace) => trace.code, Error::LinkingError(le) => le.code,
} }
} }
} }
@ -73,24 +80,26 @@ impl Display for Error {
} }
} }
impl Display for Trace { impl Display for LinkError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut new_line = ""; // new line in case of previous info only let mut new_line = ""; // new line in case of previous info only
if let Some(origin) = self.origin.to_str() { for trace in &self.traces {
if let Some(origin) = trace.origin.to_str() {
new_line = "\n"; new_line = "\n";
write!(f, "\n\t{}", origin)?; write!(f, "\n\t{}", origin)?;
} }
if self.offset > 0 { if trace.offset > 0 {
new_line = "\n"; new_line = "\n";
write!(f, "\n@offset: {}", self.offset)?; write!(f, "\n@offset: {}", trace.offset)?;
} }
if let Some(si) = &self.source_info { if let Some(si) = &trace.source_info {
new_line = "\n"; new_line = "\n";
write!(f, "\n{}", si)?; write!(f, "\n{}", si)?;
} }
}
write!(f, "{}{}", new_line, self.message) write!(f, "{}{}", new_line, self.message)
} }

@ -39,6 +39,23 @@ impl ElfObject {
Ok(result) Ok(result)
} }
fn make_symbol(&self, s64: &Symbol64, strtab: &[u8]) -> Symbol {
let binding = match s64.get_bind() {
Bind::Global => Binding::Global,
Bind::Local => Binding::Local,
Bind::Weak => Binding::Weak,
_ => panic!("Unexpected binding type encountered on symbol"), // this is screened!
};
Symbol {
object_index: self.object_index,
name: parse_strtab_name(&strtab, s64.st_name),
binding,
address: s64.st_value,
size: s64.st_size,
}
}
} }
impl Relocatable for ElfObject { impl Relocatable for ElfObject {
@ -124,7 +141,7 @@ impl Relocatable for ElfObject {
Contents64::Symbols(symbols) => { Contents64::Symbols(symbols) => {
Some(symbols.iter().filter_map(move |sym| match sym.get_bind() { Some(symbols.iter().filter_map(move |sym| match sym.get_bind() {
Bind::Global | Bind::Local | Bind::Weak => { Bind::Global | Bind::Local | Bind::Weak => {
Some(make_symbol(sym, strtab)) Some(self.make_symbol(sym, strtab))
} }
_ => None, _ => None,
})) }))
@ -158,23 +175,7 @@ impl Display for ElfObject {
} }
} }
fn make_symbol(s64: &Symbol64, strtab: &Vec<u8>) -> Symbol { fn parse_strtab_name(strtab: &[u8], idx: u32) -> String {
let binding = match s64.get_bind() {
Bind::Global => Binding::Global,
Bind::Local => Binding::Local,
Bind::Weak => Binding::Weak,
_ => panic!("Unexpected binding type encountered on symbol"), // this is screened!
};
Symbol {
name: parse_strtab_name(&strtab, s64.st_name),
binding,
address: s64.st_value,
size: s64.st_size,
}
}
fn parse_strtab_name(strtab: &Vec<u8>, idx: u32) -> String {
let bytes: Vec<u8> = strtab let bytes: Vec<u8> = strtab
.iter() .iter()
.skip(idx as usize) .skip(idx as usize)

@ -216,15 +216,15 @@ fn make_strtab() -> (Vec<u8>, Vec<usize>) {
} }
fn get_start_offset(loadable: &Loadable) -> Result<u64, Error> { fn get_start_offset(loadable: &Loadable) -> Result<u64, Error> {
use crate::error::Trace; use crate::error::LinkError;
loadable.start_offset.ok_or_else(|| { loadable.start_offset.ok_or_else(|| {
let trace = Trace { let link_error = LinkError {
message: "Program entrypoint not found", message: "Program entrypoint not found".into(),
..Default::default() ..Default::default()
}; };
Error::LinkingError(trace) Error::LinkingError(link_error)
}) })
} }

@ -32,8 +32,8 @@ where
let r = R::new(origin, DataIndex::for_object(self.relocatables.len()))?; let r = R::new(origin, DataIndex::for_object(self.relocatables.len()))?;
// TODO: parallelize? // TODO: parallelize?
for s in r.sections() { for section in r.sections() {
self.loadable.process_section(s?)?; self.loadable.process_section(section?)?;
} }
self.relocatables.push(r); self.relocatables.push(r);
@ -42,10 +42,22 @@ where
} }
pub fn link(mut self) -> Result<PathBuf, Error> { pub fn link(mut self) -> Result<PathBuf, Error> {
self.process_symbols()?;
self.loadable.start_offset = Some(4096); // TODO: get from .start symbol location self.loadable.start_offset = Some(4096); // TODO: get from .start symbol location
self.output.finalize(&self.relocatables, &self.loadable) self.output.finalize(&self.relocatables, &self.loadable)
} }
fn process_symbols(&mut self) -> Result<(), Error> {
for r in &self.relocatables {
for symbol in r.symbols() {
self.loadable.process_symbol(symbol, &self.relocatables)?;
}
}
Ok(())
}
// pub fn object_path(origin: &Path) -> Result<PathBuf, Error> { // pub fn object_path(origin: &Path) -> Result<PathBuf, Error> {
// let mut dest = std::fs::canonicalize(origin)?; // let mut dest = std::fs::canonicalize(origin)?;
// if !dest.pop() { // if !dest.pop() {

Loading…
Cancel
Save