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::{
common::{Relocatable, Section, SectionInfo, Symbol},
error::{LinkError, Trace, LE_GLOBAL_SYMBOL_DUPLICATE},
};
use super::Binding;
pub enum SegmentType {
Text,
@ -40,6 +44,8 @@ pub struct Loadable {
rodata: SegmentSections,
data: SegmentSections,
bss: SegmentSections,
symbol_map: HashMap<Rc<str>, Symbol>,
}
impl Loadable {
@ -54,6 +60,38 @@ impl Loadable {
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] {
&[".text", ".rodata", ".data", ".bss"]
}

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

@ -3,6 +3,8 @@ use std::{
path::PathBuf,
};
pub const LE_GLOBAL_SYMBOL_DUPLICATE: u32 = 701;
#[derive(Debug)]
pub enum Error {
IOError(Box<dyn std::error::Error>),
@ -11,19 +13,24 @@ pub enum Error {
InvalidSectionData,
ParseError(Box<dyn std::error::Error>),
TryFromIntError,
LinkingError(Trace),
LinkingError(LinkError),
}
// "backtrace" for error origin
#[derive(Debug, Default)]
pub struct Trace {
pub code: u32, // specific trace code, should be >= 700
pub message: &'static str,
pub origin: PathBuf,
pub offset: u64, // 0 indicates unknown/invalid
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 {
// used for programmatic input/output handling, IDE's etc.
pub fn code(&self) -> u32 {
@ -34,7 +41,7 @@ impl Error {
Error::InvalidSectionData => 400,
Error::ParseError(_) => 500,
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 {
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";
write!(f, "\n\t{}", origin)?;
}
if self.offset > 0 {
if trace.offset > 0 {
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";
write!(f, "\n{}", si)?;
}
}
write!(f, "{}{}", new_line, self.message)
}

@ -39,6 +39,23 @@ impl ElfObject {
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 {
@ -124,7 +141,7 @@ impl Relocatable for ElfObject {
Contents64::Symbols(symbols) => {
Some(symbols.iter().filter_map(move |sym| match sym.get_bind() {
Bind::Global | Bind::Local | Bind::Weak => {
Some(make_symbol(sym, strtab))
Some(self.make_symbol(sym, strtab))
}
_ => None,
}))
@ -158,23 +175,7 @@ impl Display for ElfObject {
}
}
fn make_symbol(s64: &Symbol64, strtab: &Vec<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 {
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 {
fn parse_strtab_name(strtab: &[u8], idx: u32) -> String {
let bytes: Vec<u8> = strtab
.iter()
.skip(idx as usize)

@ -216,15 +216,15 @@ fn make_strtab() -> (Vec<u8>, Vec<usize>) {
}
fn get_start_offset(loadable: &Loadable) -> Result<u64, Error> {
use crate::error::Trace;
use crate::error::LinkError;
loadable.start_offset.ok_or_else(|| {
let trace = Trace {
message: "Program entrypoint not found",
let link_error = LinkError {
message: "Program entrypoint not found".into(),
..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()))?;
// TODO: parallelize?
for s in r.sections() {
self.loadable.process_section(s?)?;
for section in r.sections() {
self.loadable.process_section(section?)?;
}
self.relocatables.push(r);
@ -42,10 +42,22 @@ where
}
pub fn link(mut self) -> Result<PathBuf, Error> {
self.process_symbols()?;
self.loadable.start_offset = Some(4096); // TODO: get from .start symbol location
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> {
// let mut dest = std::fs::canonicalize(origin)?;
// if !dest.pop() {

Loading…
Cancel
Save