diff --git a/src/artifact.rs b/src/artifact.rs index 4d2702e..fb3f585 100644 --- a/src/artifact.rs +++ b/src/artifact.rs @@ -5,7 +5,7 @@ use indexmap::IndexMap; use string_interner::DefaultStringInterner; use target_lexicon::{BinaryFormat, Triple}; -use std::collections::BTreeSet; +use std::collections::{BTreeMap, BTreeSet}; use std::fs::File; use std::io::Write; @@ -68,15 +68,23 @@ pub enum ArtifactError { /// Declaration that caused this error new: Decl, }, - #[fail(display = "duplicate definition of symbol: {}", _0)] + #[fail(display = "Duplicate definition of symbol: {}", _0)] /// A duplicate definition DuplicateDefinition(String), + + /// A non section declaration got custom symbols during definition. + #[fail( + display = "Attempt to add custom symbols {:?} to non section declaration {:?}", + _1, _0 + )] + NonSectionCustomSymbols(DefinedDecl, BTreeMap), } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] struct InternalDefinition { decl: DefinedDecl, name: StringID, + symbols: BTreeMap, data: Data, } @@ -130,6 +138,8 @@ pub(crate) struct Definition<'a> { pub name: &'a str, /// Contents of definition pub data: &'a [u8], + /// Custom symbols referencing this section, or none for other definition types. + pub symbols: &'a BTreeMap, /// Declaration of symbol pub decl: &'a DefinedDecl, } @@ -141,6 +151,7 @@ impl<'a> From<(&'a InternalDefinition, &'a DefaultStringInterner)> for Definitio .resolve(def.name) .expect("internal definition to have name"), data: &def.data, + symbols: &def.symbols, decl: &def.decl, } } @@ -349,6 +360,40 @@ impl Artifact { /// **NB**: If you attempt to define an import, this will return an error. /// If you attempt to define something which has not been declared, this will return an error. pub fn define>(&mut self, name: T, data: Vec) -> Result<(), ArtifactError> { + self.define_with_symbols(name, data, BTreeMap::new()) + } + + /// Same as `define` but also allows to add custom symbols referencing a section decl. + /// + /// # Examples + /// + /// Create a MachO file with a section called `.my_section`. This section has the content + /// `de ad be ef`, with the symbol `a_symbol` referencing to `be`. + /// + /// ```rust + /// # extern crate target_lexicon; + /// # + /// # use std::collections::BTreeMap; + /// # use std::str::FromStr; + /// # + /// # use faerie::{Artifact, ArtifactBuilder, Decl, Link, SectionKind}; + /// # + /// let mut artifact = Artifact::new(target_lexicon::triple!("x86_64-apple-darwin"), "example".to_string()); + /// + /// artifact.declare(".my_section", Decl::section(SectionKind::Data)).unwrap(); + /// + /// let mut section_symbols = BTreeMap::new(); + /// section_symbols.insert("a_symbol".to_string(), 2); + /// artifact.define_with_symbols(".my_section", vec![0xde, 0xad, 0xbe, 0xef], section_symbols).unwrap(); + /// + /// let _blob = artifact.emit().unwrap(); + /// ``` + pub fn define_with_symbols>( + &mut self, + name: T, + data: Vec, + symbols: BTreeMap, + ) -> Result<(), ArtifactError> { let decl_name = self.strings.get_or_intern(name.as_ref()); match self.declarations.get_mut(&decl_name) { Some(ref mut stype) => { @@ -363,16 +408,28 @@ impl Artifact { Err(ArtifactError::ImportDefined(name.as_ref().to_string()).into())? } }; + + match decl { + DefinedDecl::Section(_) => {} + _ => { + if !symbols.is_empty() { + return Err(ArtifactError::NonSectionCustomSymbols(decl, symbols)); + } + } + } + if decl.is_global() { self.nonlocal_definitions.insert(InternalDefinition { name: decl_name, data, + symbols, decl, }); } else { self.local_definitions.insert(InternalDefinition { name: decl_name, data, + symbols, decl, }); } diff --git a/src/elf.rs b/src/elf.rs index 059763b..5825a5e 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -475,8 +475,10 @@ impl<'a> Elf<'a> { } } } - pub fn add_definition(&mut self, name: &str, data: &'a [u8], decl: &artifact::DefinedDecl) { - let def_size = data.len(); + pub fn add_definition(&mut self, def: artifact::Definition<'a>) { + let name = def.name; + let decl = def.decl; + let def_size = def.data.len(); let section_name = match decl { DefinedDecl::Function(_) => format!(".text.{}", name), @@ -519,7 +521,7 @@ impl<'a> Elf<'a> { .align(d.get_align()), }; - let shndx = self.add_progbits(section_name, section, data); + let shndx = self.add_progbits(section_name, section, def.data); match decl { DefinedDecl::Function(_) | DefinedDecl::Data(_) => { @@ -544,7 +546,10 @@ impl<'a> Elf<'a> { } } DefinedDecl::Section(_) => { - // No symbols in custom sections, yet... + for (_symbol, _symbol_dst_offset) in def.symbols { + // FIXME: implement it + unimplemented!("elf: custom symbols referencing sections"); + } } } } @@ -997,7 +1002,7 @@ pub fn to_bytes(artifact: &Artifact) -> Result, Error> { let mut elf = Elf::new(&artifact); for def in artifact.definitions() { debug!("Def: {:?}", def); - elf.add_definition(def.name, def.data, def.decl); + elf.add_definition(def); } for (ref import, ref kind) in artifact.imports() { debug!("Import: {:?} -> {:?}", import, kind); diff --git a/src/mach.rs b/src/mach.rs index f5bbdbf..b1f625b 100644 --- a/src/mach.rs +++ b/src/mach.rs @@ -51,6 +51,7 @@ type StrtableOffset = u64; const CODE_SECTION_INDEX: SectionIndex = 0; const DATA_SECTION_INDEX: SectionIndex = 1; const CSTRING_SECTION_INDEX: SectionIndex = 2; +const NUM_DEFAULT_SECTIONS: SectionIndex = 3; /// A builder for creating a 32/64 bit Mach-o Nlist symbol #[derive(Debug)] @@ -455,9 +456,12 @@ impl SegmentBuilder { sections.insert(sectname.to_string(), section); } fn build_custom_section( + symtab: &mut SymbolTable, sections: &mut IndexMap, offset: &mut u64, addr: &mut u64, + symbol_offset: &mut u64, + section_idx: SectionIndex, def: &Definition, ) { let s = match def.decl { @@ -483,7 +487,20 @@ impl SegmentBuilder { flags |= S_ATTR_DEBUG; } + for (symbol, symbol_dst_offset) in def.symbols { + symtab.insert( + symbol, + SymbolType::Defined { + section: section_idx, + segment_relative_offset: *symbol_dst_offset, + absolute_offset: *symbol_offset + *symbol_dst_offset, + global: true, + }, + ); + } + let local_size = def.data.len() as u64; + *symbol_offset += local_size; let section = SectionBuilder::new(sectname, segment_name, local_size) .offset(*offset) .addr(*addr) @@ -547,8 +564,16 @@ impl SegmentBuilder { 0, Some(S_CSTRING_LITERALS), ); - for def in custom_sections { - Self::build_custom_section(&mut sections, &mut offset, &mut size, def); + for (idx, def) in custom_sections.iter().enumerate() { + Self::build_custom_section( + symtab, + &mut sections, + &mut offset, + &mut size, + &mut symbol_offset, + idx + NUM_DEFAULT_SECTIONS, + def, + ); } for (ref import, _) in artifact.imports() { symtab.insert(import, SymbolType::Undefined);