diff --git a/src/artifact.rs b/src/artifact.rs index 9e026af..4d2702e 100644 --- a/src/artifact.rs +++ b/src/artifact.rs @@ -12,7 +12,9 @@ use std::io::Write; use crate::{elf, mach}; pub(crate) mod decl; -pub use crate::artifact::decl::{DataType, Decl, DefinedDecl, ImportKind, Scope, Visibility}; +pub use crate::artifact::decl::{ + DataType, Decl, DefinedDecl, ImportKind, Scope, SectionKind, Visibility, +}; /// A blob of binary bytes, representing a function body, or data object pub type Data = Vec; diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index f2e2945..a5489d2 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -169,8 +169,8 @@ pub enum DefinedDecl { Function(FunctionDecl), /// A data object defined in this artifact Data(DataDecl), - /// A DWARF debug section defined in this artifact - DebugSection(DebugSectionDecl), + /// A section defined in this artifact + Section(SectionDecl), } impl DefinedDecl { @@ -190,10 +190,10 @@ impl DefinedDecl { } } - /// Accessor to determine whether variant is DebugSection - pub fn is_debug_section(&self) -> bool { + /// Accessor to determine whether variant is Section + pub fn is_section(&self) -> bool { match self { - DefinedDecl::DebugSection { .. } => true, + DefinedDecl::Section(_) => true, _ => false, } } @@ -203,7 +203,7 @@ impl DefinedDecl { match self { DefinedDecl::Function(a) => a.is_global(), DefinedDecl::Data(a) => a.is_global(), - DefinedDecl::DebugSection(a) => a.is_global(), + DefinedDecl::Section(a) => a.is_global(), } } @@ -211,7 +211,8 @@ impl DefinedDecl { pub fn is_writable(&self) -> bool { match self { DefinedDecl::Data(a) => a.is_writable(), - DefinedDecl::Function(_) | DefinedDecl::DebugSection(_) => false, + DefinedDecl::Function(_) => false, + DefinedDecl::Section(a) => a.is_writable(), } } } @@ -237,9 +238,9 @@ impl Decl { pub fn cstring() -> DataDecl { DataDecl::default().with_datatype(DataType::String) } - /// A DWARF debug section defined in this artifact - pub fn debug_section() -> DebugSectionDecl { - DebugSectionDecl::default() + /// A section defined in this artifact + pub fn section(kind: SectionKind) -> SectionDecl { + SectionDecl::new(kind) } /// If it is compatible, absorb the new declaration (`other`) into the old (`self`); otherwise returns an error. @@ -343,7 +344,7 @@ impl Decl { /// Is this a section? pub fn is_section(&self) -> bool { match *self { - Decl::Defined(DefinedDecl::DebugSection { .. }) => true, + Decl::Defined(DefinedDecl::Section { .. }) => true, _ => false, } } @@ -438,6 +439,7 @@ impl DataDecl { visibility_methods!(); datatype_methods!(); align_methods!(); + /// Builder for writability pub fn with_writable(mut self, writable: bool) -> Self { self.writable = writable; @@ -468,33 +470,61 @@ impl Into for DataDecl { } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -/// Builder for a debug section declaration -pub struct DebugSectionDecl { +/// The kind of this section +pub enum SectionKind { + /// Mutable data + Data, + + /// DWARF debug info + Debug, + + /// Code or read-only data + Text, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// Builder for a section declaration +pub struct SectionDecl { + kind: SectionKind, datatype: DataType, align: Option, } -impl DebugSectionDecl { +impl SectionDecl { datatype_methods!(); align_methods!(); - /// Debug sections are never global, but we have an accessor + + /// Create a `SectionDecl` of the given kind + pub fn new(kind: SectionKind) -> Self { + SectionDecl { + kind, + datatype: DataType::Bytes, + align: None, + } + } + + /// Sections are never global, but we have an accessor /// for symmetry with other section declarations pub fn is_global(&self) -> bool { false } -} -impl Default for DebugSectionDecl { - fn default() -> Self { - DebugSectionDecl { - datatype: DataType::Bytes, - align: None, + /// Accessor to determine whether contents are writable + pub fn is_writable(&self) -> bool { + match self.kind { + SectionKind::Data => true, + SectionKind::Debug | SectionKind::Text => false, } } + + /// Get the kind for this `SectionDecl` + pub fn kind(&self) -> SectionKind { + self.kind + } } -impl Into for DebugSectionDecl { +impl Into for SectionDecl { fn into(self) -> Decl { - Decl::Defined(DefinedDecl::DebugSection(self)) + Decl::Defined(DefinedDecl::Section(self)) } } diff --git a/src/bin/main.rs b/src/bin/main.rs index 4979c7c..b361583 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -10,7 +10,7 @@ use failure::Error; use structopt::StructOpt; use target_lexicon::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor}; -use faerie::{ArtifactBuilder, Decl, Link, Reloc}; +use faerie::{ArtifactBuilder, Decl, Link, Reloc, SectionKind}; use std::env; use std::fs::File; use std::path::Path; @@ -159,6 +159,10 @@ fn run (args: Args) -> Result<(), Error> { // .data static references need to be zero'd out explicitly for now. obj.define("STATIC_REF", vec![0; 8])?; + // define a custom section + obj.declare(".faerie", Decl::section(SectionKind::Data))?; + obj.define(".faerie", b"some data".to_vec())?; + // Next, we declare our relocations, // which are _always_ relative to the `from` symbol // -- main relocations -- @@ -209,9 +213,9 @@ fn deadbeef (args: Args) -> Result<(), Error> { if args.dwarf { // DWARF sections - obj.declare(".debug_abbrev", Decl::debug_section())?; - obj.declare(".debug_info", Decl::debug_section())?; - obj.declare(".debug_str", Decl::debug_section())?; + obj.declare(".debug_abbrev", Decl::section(SectionKind::Debug))?; + obj.declare(".debug_info", Decl::section(SectionKind::Debug))?; + obj.declare(".debug_str", Decl::section(SectionKind::Debug))?; obj.define(".debug_str", concat![ diff --git a/src/elf.rs b/src/elf.rs index 7f5c1db..19ac0dd 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -160,7 +160,7 @@ impl<'a> SymbolBuilder<'a> { st_info = STT_NOTYPE; st_info |= STB_GLOBAL << 4; } - SymbolType::Decl(DefinedDecl::DebugSection(_)) | SymbolType::Section => { + SymbolType::Decl(DefinedDecl::Section(_)) | SymbolType::Section => { st_info |= STT_SECTION; st_info |= STB_LOCAL << 4; } @@ -479,7 +479,7 @@ impl<'a> Elf<'a> { if d.is_writable() { "data" } else { "rodata" }, name ), - DefinedDecl::DebugSection(_) => name.to_owned(), + DefinedDecl::Section(_) => name.to_owned(), }; let section = match decl { @@ -498,7 +498,7 @@ impl<'a> Elf<'a> { .writable(d.is_writable()) .exec(false) .align(d.get_align()), - DefinedDecl::DebugSection(d) => SectionBuilder::new(def_size as u64) + DefinedDecl::Section(d) => SectionBuilder::new(def_size as u64) .section_type( // TODO: this behavior should be deprecated, but we need to warn users! if name == ".debug_str" || name == ".debug_line_str" { @@ -537,8 +537,8 @@ impl<'a> Elf<'a> { self.nlocals += 1; } } - DefinedDecl::DebugSection(_) => { - // No symbols in debug sections, yet... + DefinedDecl::Section(_) => { + // No symbols in custom sections, yet... } } } diff --git a/src/lib.rs b/src/lib.rs index a870fa4..0730f47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,8 +22,8 @@ mod target; pub mod artifact; pub use crate::artifact::{ decl::{ - DataDecl, DataImportDecl, DataType, DebugSectionDecl, Decl, FunctionDecl, - FunctionImportDecl, Scope, Visibility, + DataDecl, DataImportDecl, DataType, Decl, FunctionDecl, FunctionImportDecl, Scope, + SectionDecl, SectionKind, Visibility, }, Artifact, ArtifactBuilder, ArtifactError, ImportKind, Link, Reloc, }; diff --git a/src/mach.rs b/src/mach.rs index fb25223..e39551b 100644 --- a/src/mach.rs +++ b/src/mach.rs @@ -1,6 +1,6 @@ //! The Mach 32/64 bit backend for transforming an artifact to a valid, mach-o object file. -use crate::artifact::{DataType, Decl, DefinedDecl, Definition, ImportKind, Reloc}; +use crate::artifact::{DataType, Decl, DefinedDecl, Definition, ImportKind, Reloc, SectionKind}; use crate::target::make_ctx; use crate::{Artifact, Ctx}; @@ -427,8 +427,8 @@ impl SegmentBuilder { let mut local_size = 0; let mut segment_relative_offset = 0; for def in definitions { - if let DefinedDecl::DebugSection { .. } = def.decl { - unimplemented!("debug sections for mach backend") + if let DefinedDecl::Section { .. } = def.decl { + unreachable!(); } local_size += def.data.len() as u64; symtab.insert( @@ -454,19 +454,29 @@ impl SegmentBuilder { *addr += local_size; sections.insert(sectname.to_string(), section); } - fn build_debug_section( + fn build_custom_section( sections: &mut IndexMap, offset: &mut u64, addr: &mut u64, def: &Definition, ) { + let segment_name = match def.decl { + DefinedDecl::Section(s) => match s.kind() { + SectionKind::Data => "__DATA", + SectionKind::Debug => "__DWARF", + SectionKind::Text => "__TEXT", + }, + _ => unreachable!("in build_custom_section: def.decl != Section"), + }; + let sectname = if def.name.starts_with('.') { format!("__{}", &def.name[1..]) } else { def.name.to_string() }; + let local_size = def.data.len() as u64; - let section = SectionBuilder::new(sectname, "__DWARF", local_size) + let section = SectionBuilder::new(sectname, segment_name, local_size) .offset(*offset) .addr(*addr) .align(1) @@ -482,7 +492,7 @@ impl SegmentBuilder { code: &[Definition], data: &[Definition], cstrings: &[Definition], - debug_sections: &[Definition], + custom_sections: &[Definition], symtab: &mut SymbolTable, ctx: &Ctx, ) -> Self { @@ -529,8 +539,8 @@ impl SegmentBuilder { 0, Some(S_CSTRING_LITERALS), ); - for def in debug_sections { - Self::build_debug_section(&mut sections, &mut offset, &mut size, def); + for def in custom_sections { + Self::build_custom_section(&mut sections, &mut offset, &mut size, def); } for (ref import, _) in artifact.imports() { symtab.insert(import, SymbolType::Undefined); @@ -559,7 +569,7 @@ struct Mach<'a> { code: ArtifactCode<'a>, data: ArtifactData<'a>, cstrings: Vec>, - debug: Vec>, + sections: Vec>, _p: ::std::marker::PhantomData<&'a ()>, } @@ -567,7 +577,7 @@ impl<'a> Mach<'a> { pub fn new(artifact: &'a Artifact) -> Self { let ctx = make_ctx(&artifact.target); // FIXME: I believe we can avoid this partition by refactoring SegmentBuilder::new - let (mut code, mut data, mut cstrings, mut debug) = + let (mut code, mut data, mut cstrings, mut sections) = (Vec::new(), Vec::new(), Vec::new(), Vec::new()); for def in artifact.definitions() { match def.decl { @@ -581,8 +591,8 @@ impl<'a> Mach<'a> { data.push(def); } } - DefinedDecl::DebugSection { .. } => { - debug.push(def); + DefinedDecl::Section(_) => { + sections.push(def); } } } @@ -593,7 +603,7 @@ impl<'a> Mach<'a> { &code, &data, &cstrings, - &debug, + §ions, &mut symtab, &ctx, ); @@ -608,7 +618,7 @@ impl<'a> Mach<'a> { code, data, cstrings, - debug, + sections, } } fn header(&self, sizeofcmds: u64) -> Header { @@ -719,12 +729,12 @@ impl<'a> Mach<'a> { debug!("SEEK: after cstrings: {}", file.seek(Current(0))?); ////////////////////////////// - // write debug sections + // write custom sections ////////////////////////////// - for debug in self.debug { - file.write_all(debug.data)?; + for section in self.sections { + file.write_all(section.data)?; } - debug!("SEEK: after debug: {}", file.seek(Current(0))?); + debug!("SEEK: after custom sections: {}", file.seek(Current(0))?); ////////////////////////////// // write symtable @@ -787,13 +797,22 @@ fn build_relocations(segment: &mut SegmentBuilder, artifact: &Artifact, symtab: // NB: we currently deduce the meaning of our relocation from from decls -> to decl relocations // e.g., global static data references, are constructed from Data -> Data links match (link.from.decl, link.to.decl) { - (Decl::Defined(DefinedDecl::DebugSection { .. }), _) => { + (Decl::Defined(DefinedDecl::Section(s)), _) + if s.kind() == SectionKind::Debug => + { panic!("must use Reloc::Debug for debug section links") } // only debug sections should link to debug sections - (_, Decl::Defined(DefinedDecl::DebugSection { .. })) => { + (_, Decl::Defined(DefinedDecl::Section(s))) + if s.kind() == SectionKind::Debug => + { panic!("invalid DebugSection link") } + + (Decl::Defined(DefinedDecl::Section(_)), _) + | (_, Decl::Defined(DefinedDecl::Section(_))) => { + panic!("relocations are not yet supported for custom sections") + } // various static function pointers in the .data section ( Decl::Defined(DefinedDecl::Data { .. }),