From 365750acd38abe6bba115e3388c302c00cc65691 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 20 Feb 2019 16:45:25 -0800 Subject: [PATCH 01/17] decl: add scope and visibility enums --- src/artifact/decl.rs | 157 ++++++++++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 48 deletions(-) diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index 90a5a5d..d5484f8 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -29,6 +29,31 @@ impl ImportKind { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// Linker binding scope of a definition +pub enum Scope { + /// Available to all components + Global, + /// Available only inside the defining component + Local, + /// Available to all modules, but only selected if a Global + /// definition is not found + Weak, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// Linker visibility of a definition +pub enum Visibility { + /// Visibility determined by the symbol's `Scope`. + Default, + /// Visible in other components, but cannot be preempted. References to the symbol must be + /// resolved to this definition in that component, even if another definition would interpose + /// by the default rules. + Protected, + /// Not visible to other components, plus the constraints provided by `Protected`. + Hidden, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// A declaration that is defined inside this artifact pub enum DefinedDecl { @@ -261,33 +286,87 @@ impl Into for DataImportDecl { } } +macro_rules! scope_methods { + () => { + /// Set scope to global + pub fn global(self) -> Self { + self.with_scope(Scope::Global) + } + /// Set scope to local + pub fn local(self) -> Self { + self.with_scope(Scope::Local) + } + /// Set scope to weak + pub fn weak(self) -> Self { + self.with_scope(Scope::Weak) + } + /// Builder for scope + pub fn with_scope(mut self, scope: Scope) -> Self { + self.scope = scope; + self + } + /// Gst scope + pub fn get_scope(&self) -> Scope { + self.scope + } + /// Set scope + pub fn set_scope(&mut self, scope: Scope) { + self.scope = scope; + } + /// Check if scope is `Scope::Global` + pub fn is_global(&self) -> bool { + self.scope == Scope::Global + } +}} + +macro_rules! visibility_methods { + () => { + /// Set visibility to default + pub fn default_visibility(self) -> Self { + self.with_visibility(Visibility::Default) + } + /// Set visibility to protected + pub fn protected(self) -> Self { + self.with_visibility(Visibility::Protected) + } + /// Set visibility to hidden + pub fn hidden(self) -> Self { + self.with_visibility(Visibility::Hidden) + } + /// Builder for visibility + pub fn with_visibility(mut self, visibility: Visibility) -> Self { + self.visibility =visibility; + self + } + /// Get visibility + pub fn get_visibility(&self) -> Visibility { + self.visibility + } + /// Set visibility + pub fn set_visibility(&mut self, visibility: Visibility) { + self.visibility = visibility; + } +}} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Builder for function declarations pub struct FunctionDecl { - global: bool, + scope: Scope, + visibility: Visibility, } impl Default for FunctionDecl { fn default() -> Self { - FunctionDecl { global: false } + FunctionDecl { + scope: Scope::Local, + visibility: Visibility::Default, + } } } impl FunctionDecl { - /// Set binding to global - pub fn global(mut self) -> Self { - self.global = true; - self - } - /// Set binding to local - pub fn local(mut self) -> Self { - self.global = false; - self - } - /// Accessor for binding - pub fn is_global(&self) -> bool { - self.global - } + scope_methods!(); + visibility_methods!(); } impl Into for FunctionDecl { @@ -299,34 +378,24 @@ impl Into for FunctionDecl { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Builder for data declarations pub struct DataDecl { - global: bool, + scope: Scope, + visibility: Visibility, writable: bool, } impl Default for DataDecl { fn default() -> Self { DataDecl { - global: false, + scope: Scope::Local, + visibility: Visibility::Default, writable: false, } } } impl DataDecl { - /// Set binding to global - pub fn global(mut self) -> Self { - self.global = true; - self - } - /// Set binding to local - pub fn local(mut self) -> Self { - self.global = false; - self - } - /// Accessor for binding - pub fn is_global(&self) -> bool { - self.global - } + scope_methods!(); + visibility_methods!(); /// Set mutability to writable pub fn writable(mut self) -> Self { self.writable = true; @@ -352,30 +421,22 @@ impl Into for DataDecl { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Builder for a CString (0-terminated character sequence) declaration pub struct CStringDecl { - global: bool, + scope: Scope, + visibility: Visibility, } impl Default for CStringDecl { fn default() -> Self { - CStringDecl { global: false } + CStringDecl { + scope: Scope::Local, + visibility: Visibility::Default, + } } } impl CStringDecl { - /// Set binding to global - pub fn global(mut self) -> Self { - self.global = true; - self - } - /// Set binding to local - pub fn local(mut self) -> Self { - self.global = false; - self - } - /// Accessor for binding - pub fn is_global(&self) -> bool { - self.global - } + scope_methods!(); + visibility_methods!(); } impl Into for CStringDecl { From adefb3c115deb630cc4af59d8bfe901b879fa34b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 20 Feb 2019 17:42:55 -0800 Subject: [PATCH 02/17] use scope in elf --- src/artifact.rs | 2 +- src/elf.rs | 75 +++++++++++++++++++++++++------------------------ 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/artifact.rs b/src/artifact.rs index b3293cf..1f4ca24 100644 --- a/src/artifact.rs +++ b/src/artifact.rs @@ -12,7 +12,7 @@ use std::io::Write; use crate::{elf, mach}; pub(crate) mod decl; -pub use decl::{Decl, DefinedDecl, ImportKind}; +pub use decl::{Decl, DefinedDecl, ImportKind, Scope, Visibility}; /// A blob of binary bytes, representing a function body, or data object pub type Data = Vec; diff --git a/src/elf.rs b/src/elf.rs index 433ec7c..5e4111a 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -6,7 +6,9 @@ #![allow(dead_code)] use crate::{ - artifact::{self, Artifact, Decl, DefinedDecl, ImportKind, LinkAndDecl, Reloc}, + artifact::{ + self, Artifact, Decl, DefinedDecl, ImportKind, LinkAndDecl, Reloc, Scope, Visibility, + }, target::make_ctx, Ctx, }; @@ -61,12 +63,10 @@ impl From for MachineTag { } /// The kind of symbol this is; used in [SymbolBuilder](struct.SymbolBuilder.html) -enum SymbolType { - /// A function - Function, - /// A data object - Object, - /// An impor +enum SymbolType<'a> { + /// From a definition + Decl(&'a DefinedDecl), + /// An import Import, /// A section reference Section, @@ -77,33 +77,29 @@ enum SymbolType { } /// A builder for creating a 32/64 bit ELF symbol -struct SymbolBuilder { +struct SymbolBuilder<'a> { name_offset: usize, - global: bool, size: u64, - typ: SymbolType, + typ: SymbolType<'a>, } -impl SymbolBuilder { +impl<'a> SymbolBuilder<'a> { /// Create a new symbol with `typ` - pub fn new(typ: SymbolType) -> Self { + pub fn new(typ: SymbolType<'a>) -> Self { SymbolBuilder { - global: false, name_offset: 0, typ, size: 0, } } + pub fn from_decl(decl: &'a DefinedDecl) -> Self { + SymbolBuilder::new(SymbolType::Decl(decl)) + } /// Set the size of this symbol; for functions, it should be the routines size in bytes pub fn size(mut self, size: usize) -> Self { self.size = size as u64; self } - /// Is this symbol local in scope? - pub fn local(mut self, local: bool) -> Self { - self.global = !local; - self - } /// Set the symbol name as a byte offset into the corresponding strtab pub fn name_offset(mut self, name_offset: usize) -> Self { self.name_offset = name_offset; @@ -113,23 +109,40 @@ impl SymbolBuilder { pub fn create(self) -> Symbol { use goblin::elf::section_header::SHN_ABS; use goblin::elf::sym::{ - STB_GLOBAL, STB_LOCAL, STT_FILE, STT_FUNC, STT_NOTYPE, STT_OBJECT, STT_SECTION, + STB_GLOBAL, STB_LOCAL, STB_WEAK, STT_FILE, STT_FUNC, STT_NOTYPE, STT_OBJECT, + STT_SECTION, }; let mut st_shndx = 0; let mut st_info = 0; let st_value = 0; + + fn scope_stb_flags(s: Scope) -> u8 { + let flag = match s { + Scope::Local => STB_LOCAL, + Scope::Global => STB_GLOBAL, + Scope::Weak => STB_WEAK, + }; + flag << 4 + } + match self.typ { - SymbolType::Function => { + SymbolType::Decl(DefinedDecl::Function(d)) => { st_info |= STT_FUNC; + st_info |= scope_stb_flags(d.get_scope()); } - SymbolType::Object => { + SymbolType::Decl(DefinedDecl::Data(d)) => { st_info |= STT_OBJECT; + st_info |= scope_stb_flags(d.get_scope()); + } + SymbolType::Decl(DefinedDecl::CString(d)) => { + st_info |= STT_OBJECT; + st_info |= scope_stb_flags(d.get_scope()); } SymbolType::Import => { st_info = STT_NOTYPE; st_info |= STB_GLOBAL << 4; } - SymbolType::Section => { + SymbolType::Decl(DefinedDecl::DebugSection(_)) | SymbolType::Section => { st_info |= STT_SECTION; st_info |= STB_LOCAL << 4; } @@ -140,11 +153,6 @@ impl SymbolBuilder { } SymbolType::None => st_info = STT_NOTYPE, } - if self.global { - st_info |= STB_GLOBAL << 4; - } else { - st_info |= STB_LOCAL << 4; - } Symbol { st_name: self.name_offset, st_other: 0, @@ -483,15 +491,10 @@ impl<'a> Elf<'a> { idx, offset, self.sizeof_strtab ); // build symbol based on this _and_ the properties of the definition - let mut symbol = SymbolBuilder::new(if let DefinedDecl::Function { .. } = decl { - SymbolType::Function - } else { - SymbolType::Object - }) - .size(size) - .name_offset(offset) - .local(!decl.is_global()) - .create(); + let mut symbol = SymbolBuilder::from_decl(decl) + .size(size) + .name_offset(offset) + .create(); symbol.st_shndx = shndx; // insert it into our symbol table self.symbols.insert(idx, symbol); From b1e6fe9bc45aea86c5c4c9e10c31fb6b3011ffc2 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 20 Feb 2019 17:53:33 -0800 Subject: [PATCH 03/17] add visibility flags to st_other --- src/elf.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/elf.rs b/src/elf.rs index 5e4111a..25cf5bb 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -114,6 +114,7 @@ impl<'a> SymbolBuilder<'a> { }; let mut st_shndx = 0; let mut st_info = 0; + let mut st_other = 0; let st_value = 0; fn scope_stb_flags(s: Scope) -> u8 { @@ -125,18 +126,30 @@ impl<'a> SymbolBuilder<'a> { flag << 4 } + // TODO put these into goblin + fn vis_stother_flags(v: Visibility) -> u8 { + match v { + Visibility::Default => 0, + Visibility::Hidden => 2, + Visibility::Protected => 3, + } + } + match self.typ { SymbolType::Decl(DefinedDecl::Function(d)) => { st_info |= STT_FUNC; st_info |= scope_stb_flags(d.get_scope()); + st_other |= vis_stother_flags(d.get_visibility()); } SymbolType::Decl(DefinedDecl::Data(d)) => { st_info |= STT_OBJECT; st_info |= scope_stb_flags(d.get_scope()); + st_other |= vis_stother_flags(d.get_visibility()); } SymbolType::Decl(DefinedDecl::CString(d)) => { st_info |= STT_OBJECT; st_info |= scope_stb_flags(d.get_scope()); + st_other |= vis_stother_flags(d.get_visibility()); } SymbolType::Import => { st_info = STT_NOTYPE; @@ -155,7 +168,7 @@ impl<'a> SymbolBuilder<'a> { } Symbol { st_name: self.name_offset, - st_other: 0, + st_other, st_size: self.size, st_info, st_shndx, From 1e5d24f1dfe27897df706de276ca98e81821f632 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 21 Feb 2019 12:26:56 -0800 Subject: [PATCH 04/17] elf: refactor add_definition and add_section into one and, put section_index into SymbolBuilder because many users set it right after building the symbol anyway --- src/elf.rs | 121 +++++++++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 54 deletions(-) diff --git a/src/elf.rs b/src/elf.rs index 25cf5bb..b9d1482 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -81,6 +81,7 @@ struct SymbolBuilder<'a> { name_offset: usize, size: u64, typ: SymbolType<'a>, + shndx: usize, } impl<'a> SymbolBuilder<'a> { @@ -90,6 +91,7 @@ impl<'a> SymbolBuilder<'a> { name_offset: 0, typ, size: 0, + shndx: 0, } } pub fn from_decl(decl: &'a DefinedDecl) -> Self { @@ -105,6 +107,13 @@ impl<'a> SymbolBuilder<'a> { self.name_offset = name_offset; self } + /// Set the section index + pub fn section_index(mut self, shndx: usize) -> Self { + // Underlying representation is only 16 bits. Catch this early! + debug_assert!(shndx < u16::max_value() as usize); + self.shndx = shndx; + self + } /// Finalize and create the symbol pub fn create(self) -> Symbol { use goblin::elf::section_header::SHN_ABS; @@ -112,7 +121,7 @@ impl<'a> SymbolBuilder<'a> { STB_GLOBAL, STB_LOCAL, STB_WEAK, STT_FILE, STT_FUNC, STT_NOTYPE, STT_OBJECT, STT_SECTION, }; - let mut st_shndx = 0; + let mut st_shndx = self.shndx; let mut st_info = 0; let mut st_other = 0; let st_value = 0; @@ -465,61 +474,70 @@ impl<'a> Elf<'a> { } } pub fn add_definition(&mut self, name: &str, data: &'a [u8], decl: &artifact::DefinedDecl) { - // we need this because sh_info requires nsections + nlocals to add as delimiter; see the associated FunFact + // sh_info requires nsections + nlocals to add as delimiter; see the associated FunFact if !decl.is_global() { self.nlocals += 1; } - // FIXME: this is kind of hacky? - let segment_name = if let DefinedDecl::Function { .. } = decl { - "text" - } else { - // we'd add ro here once the prop supports that - "data" + let def_size = data.len(); + + let section_name = match decl { + DefinedDecl::Function(_) => format!(".text.{}", name), + DefinedDecl::Data(d) => format!( + ".{}.{}", + if d.is_writable() { "data" } else { "rodata" }, + name + ), + DefinedDecl::CString(_) => format!(".rodata.{}", name), + DefinedDecl::DebugSection(_) => name.to_owned(), }; - let section_name = format!(".{}.{}", segment_name, name); - // store the size of this code - let size = data.len(); - - // now we build the section a la LLVM "function sections" - // FIXME: probably add padding alignment - let section = { - let stype = match decl { - DefinedDecl::Function { .. } => SectionType::Bits, - DefinedDecl::CString { .. } => SectionType::String, - _ => SectionType::Data, - }; - SectionBuilder::new(size as u64) - .section_type(stype) + let section = match decl { + DefinedDecl::Function(_) => SectionBuilder::new(def_size as u64) + .section_type(SectionType::Bits) .alloc() - .writable(decl.is_writable()) - .exec(decl.is_function()) + .writable(false) + .exec(true), + DefinedDecl::Data(d) => SectionBuilder::new(def_size as u64) + .section_type(SectionType::Data) + .alloc() + .writable(d.is_writable()) + .exec(false), + DefinedDecl::CString(_) => SectionBuilder::new(def_size as u64) + .section_type(SectionType::String) + .alloc() + .writable(false) + .exec(false), + DefinedDecl::DebugSection(_) => SectionBuilder::new(def_size as u64).section_type( + if name == ".debug_str" || name == ".debug_line_str" { + SectionType::String + } else { + SectionType::Bits + }, + ), }; + let shndx = self.add_progbits(section_name, section, data); - // can do prefix optimization here actually, because .text.* - let (idx, offset) = self.new_string(name.to_string()); - debug!( - "idx: {:?} @ {:#x} - new strtab offset: {:#x}", - idx, offset, self.sizeof_strtab - ); - // build symbol based on this _and_ the properties of the definition - let mut symbol = SymbolBuilder::from_decl(decl) - .size(size) - .name_offset(offset) - .create(); - symbol.st_shndx = shndx; - // insert it into our symbol table - self.symbols.insert(idx, symbol); - } - pub fn add_section(&mut self, name: &str, data: &'a [u8], _decl: &artifact::DefinedDecl) { - let stype = if name == ".debug_str" || name == ".debug_line_str" { - SectionType::String - } else { - SectionType::Bits - }; - let section = SectionBuilder::new(data.len() as u64).section_type(stype); - self.add_progbits(name.to_string(), section, data); + match decl { + DefinedDecl::Function(_) | DefinedDecl::Data(_) | DefinedDecl::CString(_) => { + let (idx, offset) = self.new_string(name.to_string()); + debug!( + "idx: {:?} @ {:#x} - new strtab offset: {:#x}", + idx, offset, self.sizeof_strtab + ); + // build symbol based on this _and_ the properties of the definition + let symbol = SymbolBuilder::from_decl(decl) + .size(def_size) + .name_offset(offset) + .section_index(shndx) + .create(); + // insert it into our symbol table + self.symbols.insert(idx, symbol); + } + DefinedDecl::DebugSection(_) => { + // No symbols in debug sections, yet... + } + } } /// Create a progbits section (and its section symbol), and return the section index. fn add_progbits(&mut self, name: String, section: SectionBuilder, data: &'a [u8]) -> usize { @@ -532,8 +550,7 @@ impl<'a> Elf<'a> { let size = data.len(); // the symbols section reference/index will be the current number of sections let shndx = self.sections.len() + 3; // null + strtab + symtab - let mut section_symbol = SymbolBuilder::new(SymbolType::Section).create(); - section_symbol.st_shndx = shndx; + let section_symbol = SymbolBuilder::new(SymbolType::Section).section_index(shndx).create(); let mut section = section.name_offset(offset).create(&self.ctx); // the offset is the head of how many program bits we've added @@ -867,11 +884,7 @@ pub fn to_bytes(artifact: &Artifact) -> Result, Error> { let mut elf = Elf::new(&artifact); for def in artifact.definitions() { debug!("Def: {:?}", def); - if let DefinedDecl::DebugSection { .. } = def.decl { - elf.add_section(def.name, def.data, def.decl); - } else { - elf.add_definition(def.name, def.data, def.decl); - } + elf.add_definition(def.name, def.data, def.decl); } for (ref import, ref kind) in artifact.imports() { debug!("Import: {:?} -> {:?}", import, kind); From 38190a80572f0adbc267aa1693a2154c14253642 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 21 Feb 2019 12:42:11 -0800 Subject: [PATCH 05/17] cstrings are now just a subset of data --- src/artifact.rs | 2 +- src/artifact/decl.rs | 68 ++++++++++++++++++-------------------------- src/elf.rs | 29 ++++++++----------- src/lib.rs | 4 +-- src/mach.rs | 15 +++++----- 5 files changed, 50 insertions(+), 68 deletions(-) diff --git a/src/artifact.rs b/src/artifact.rs index 1f4ca24..0a9a5ea 100644 --- a/src/artifact.rs +++ b/src/artifact.rs @@ -12,7 +12,7 @@ use std::io::Write; use crate::{elf, mach}; pub(crate) mod decl; -pub use decl::{Decl, DefinedDecl, ImportKind, Scope, Visibility}; +pub use decl::{DataType, Decl, DefinedDecl, ImportKind, Scope, 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 d5484f8..e8897be 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -61,8 +61,6 @@ pub enum DefinedDecl { Function(FunctionDecl), /// A data object defined in this artifact Data(DataDecl), - /// A null-terminated string object defined in this artifact - CString(CStringDecl), /// A DWARF debug section defined in this artifact DebugSection(DebugSectionDecl), } @@ -84,14 +82,6 @@ impl DefinedDecl { } } - /// Accessor to determine whether variant is CString - pub fn is_cstring(&self) -> bool { - match self { - DefinedDecl::CString { .. } => true, - _ => false, - } - } - /// Accessor to determine whether variant is DebugSection pub fn is_debug_section(&self) -> bool { match self { @@ -105,7 +95,6 @@ impl DefinedDecl { match self { DefinedDecl::Function(a) => a.is_global(), DefinedDecl::Data(a) => a.is_global(), - DefinedDecl::CString(a) => a.is_global(), DefinedDecl::DebugSection(a) => a.is_global(), } } @@ -114,7 +103,7 @@ impl DefinedDecl { pub fn is_writable(&self) -> bool { match self { DefinedDecl::Data(a) => a.is_writable(), - DefinedDecl::Function(_) | DefinedDecl::CString(_) | DefinedDecl::DebugSection(_) => { + DefinedDecl::Function(_) | DefinedDecl::DebugSection(_) => { false } } @@ -139,8 +128,8 @@ impl Decl { DataDecl::default() } /// A null-terminated string object defined in this artifact - pub fn cstring() -> CStringDecl { - CStringDecl::default() + pub fn cstring() -> DataDecl { + DataDecl::default().with_datatype(DataType::String) } /// A DWARF debug section defined in this artifact pub fn debug_section() -> DebugSectionDecl { @@ -375,12 +364,22 @@ impl Into for FunctionDecl { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// Type of data declared +pub enum DataType { + /// Ordinary raw bytes + Bytes, + /// 0-terminated ascii string + String, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Builder for data declarations pub struct DataDecl { scope: Scope, visibility: Visibility, writable: bool, + datatype: DataType, } impl Default for DataDecl { @@ -389,6 +388,7 @@ impl Default for DataDecl { scope: Scope::Local, visibility: Visibility::Default, writable: false, + datatype: DataType::Bytes, } } } @@ -410,41 +410,29 @@ impl DataDecl { pub fn is_writable(&self) -> bool { self.writable } -} -impl Into for DataDecl { - fn into(self) -> Decl { - Decl::Defined(DefinedDecl::Data(self)) + /// Build datatype + pub fn with_datatype(mut self, datatype: DataType) -> Self { + self.datatype = datatype; + self } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -/// Builder for a CString (0-terminated character sequence) declaration -pub struct CStringDecl { - scope: Scope, - visibility: Visibility, -} - -impl Default for CStringDecl { - fn default() -> Self { - CStringDecl { - scope: Scope::Local, - visibility: Visibility::Default, - } + /// Set datatype + pub fn set_datatype(&mut self, datatype: DataType) { + self.datatype = datatype; + } + /// Get datatype + pub fn get_datatype(&self) -> DataType { + self.datatype } } -impl CStringDecl { - scope_methods!(); - visibility_methods!(); -} - -impl Into for CStringDecl { +impl Into for DataDecl { fn into(self) -> Decl { - Decl::Defined(DefinedDecl::CString(self)) + Decl::Defined(DefinedDecl::Data(self)) } } + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Builder for a debug section declaration pub struct DebugSectionDecl {} diff --git a/src/elf.rs b/src/elf.rs index b9d1482..0c0ff9f 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -7,7 +7,7 @@ use crate::{ artifact::{ - self, Artifact, Decl, DefinedDecl, ImportKind, LinkAndDecl, Reloc, Scope, Visibility, + self, Artifact, Decl, DefinedDecl, ImportKind, LinkAndDecl, Reloc, Scope, Visibility, DataType }, target::make_ctx, Ctx, @@ -155,11 +155,6 @@ impl<'a> SymbolBuilder<'a> { st_info |= scope_stb_flags(d.get_scope()); st_other |= vis_stother_flags(d.get_visibility()); } - SymbolType::Decl(DefinedDecl::CString(d)) => { - st_info |= STT_OBJECT; - st_info |= scope_stb_flags(d.get_scope()); - st_other |= vis_stother_flags(d.get_visibility()); - } SymbolType::Import => { st_info = STT_NOTYPE; st_info |= STB_GLOBAL << 4; @@ -197,6 +192,15 @@ enum SectionType { None, } +impl SectionType { + pub fn from_datatype(datatype: DataType) -> Self { + match datatype { + DataType::Bytes => SectionType::Bits, + DataType::String => SectionType::String, + } + } +} + /// A builder for creating a 32/64 bit section struct SectionBuilder { typ: SectionType, @@ -487,7 +491,6 @@ impl<'a> Elf<'a> { if d.is_writable() { "data" } else { "rodata" }, name ), - DefinedDecl::CString(_) => format!(".rodata.{}", name), DefinedDecl::DebugSection(_) => name.to_owned(), }; @@ -498,15 +501,10 @@ impl<'a> Elf<'a> { .writable(false) .exec(true), DefinedDecl::Data(d) => SectionBuilder::new(def_size as u64) - .section_type(SectionType::Data) + .section_type(SectionType::from_datatype(d.get_datatype())) .alloc() .writable(d.is_writable()) .exec(false), - DefinedDecl::CString(_) => SectionBuilder::new(def_size as u64) - .section_type(SectionType::String) - .alloc() - .writable(false) - .exec(false), DefinedDecl::DebugSection(_) => SectionBuilder::new(def_size as u64).section_type( if name == ".debug_str" || name == ".debug_line_str" { SectionType::String @@ -519,7 +517,7 @@ impl<'a> Elf<'a> { let shndx = self.add_progbits(section_name, section, data); match decl { - DefinedDecl::Function(_) | DefinedDecl::Data(_) | DefinedDecl::CString(_) => { + DefinedDecl::Function(_) | DefinedDecl::Data(_) => { let (idx, offset) = self.new_string(name.to_string()); debug!( "idx: {:?} @ {:#x} - new strtab offset: {:#x}", @@ -634,9 +632,6 @@ impl<'a> Elf<'a> { Decl::Defined(DefinedDecl::Function { .. }) | Decl::Import(ImportKind::Function) => (reloc::R_X86_64_PLT32, -4), Decl::Defined(DefinedDecl::Data { .. }) => (reloc::R_X86_64_PC32, -4), - Decl::Defined(DefinedDecl::CString { .. }) => { - (reloc::R_X86_64_PC32, -4) - } Decl::Import(ImportKind::Data) => (reloc::R_X86_64_GOTPCREL, -4), _ => panic!("unsupported relocation {:?}", l), } diff --git a/src/lib.rs b/src/lib.rs index 0fd08e7..c474408 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,8 +22,8 @@ mod target; pub mod artifact; pub use crate::artifact::{ decl::{ - CStringDecl, DataDecl, DataImportDecl, DebugSectionDecl, Decl, FunctionDecl, - FunctionImportDecl, + DataDecl, DataImportDecl, DataType, DebugSectionDecl, Decl, FunctionDecl, + FunctionImportDecl, Scope, Visibility, }, Artifact, ArtifactBuilder, ImportKind, Link, Reloc, }; diff --git a/src/mach.rs b/src/mach.rs index 7d2610f..fb25223 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::{Decl, DefinedDecl, Definition, ImportKind, Reloc}; +use crate::artifact::{DataType, Decl, DefinedDecl, Definition, ImportKind, Reloc}; use crate::target::make_ctx; use crate::{Artifact, Ctx}; @@ -574,11 +574,12 @@ impl<'a> Mach<'a> { DefinedDecl::Function { .. } => { code.push(def); } - DefinedDecl::Data { .. } => { - data.push(def); - } - DefinedDecl::CString { .. } => { - cstrings.push(def); + DefinedDecl::Data(d) => { + if d.get_datatype() == DataType::String { + cstrings.push(def); + } else { + data.push(def); + } } DefinedDecl::DebugSection { .. } => { debug.push(def); @@ -813,8 +814,6 @@ fn build_relocations(segment: &mut SegmentBuilder, artifact: &Artifact, symtab: Decl::Defined(DefinedDecl::Data { .. }), ) => (true, X86_64_RELOC_UNSIGNED), (_, Decl::Defined(DefinedDecl::Data { .. })) => (false, X86_64_RELOC_SIGNED), - // TODO: we will also need to specify relocations from Data to Cstrings, e.g., char * STR = "a global static string"; - (_, Decl::Defined(DefinedDecl::CString { .. })) => (false, X86_64_RELOC_SIGNED), (_, Decl::Import(ImportKind::Function)) => (false, X86_64_RELOC_BRANCH), (_, Decl::Import(ImportKind::Data)) => (false, X86_64_RELOC_GOT_LOAD), } From 89c83d3e9ef2803a9c9a8bd502a8804161568b4a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 21 Feb 2019 12:45:07 -0800 Subject: [PATCH 06/17] add datatype to debugsection decl, thread through to elf TODO: come up with a plan to deprecate automatically making .debug_str and .debug_line_str into string sections, because theres a proper api for that now --- src/artifact/decl.rs | 37 ++++++++++++++++++++++--------------- src/elf.rs | 29 +++++++++++++++-------------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index e8897be..9eabcbe 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -382,6 +382,24 @@ pub struct DataDecl { datatype: DataType, } +macro_rules! datatype_methods { + () => { + /// Build datatype + pub fn with_datatype(mut self, datatype: DataType) -> Self { + self.datatype = datatype; + self + } + /// Set datatype + pub fn set_datatype(&mut self, datatype: DataType) { + self.datatype = datatype; + } + /// Get datatype + pub fn get_datatype(&self) -> DataType { + self.datatype + } + } +} + impl Default for DataDecl { fn default() -> Self { DataDecl { @@ -396,6 +414,7 @@ impl Default for DataDecl { impl DataDecl { scope_methods!(); visibility_methods!(); + datatype_methods!(); /// Set mutability to writable pub fn writable(mut self) -> Self { self.writable = true; @@ -411,19 +430,6 @@ impl DataDecl { self.writable } - /// Build datatype - pub fn with_datatype(mut self, datatype: DataType) -> Self { - self.datatype = datatype; - self - } - /// Set datatype - pub fn set_datatype(&mut self, datatype: DataType) { - self.datatype = datatype; - } - /// Get datatype - pub fn get_datatype(&self) -> DataType { - self.datatype - } } impl Into for DataDecl { @@ -435,9 +441,10 @@ impl Into for DataDecl { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Builder for a debug section declaration -pub struct DebugSectionDecl {} +pub struct DebugSectionDecl { datatype: DataType } impl DebugSectionDecl { + datatype_methods!(); /// Debug sections are never global, but we have an accessor /// for symmetry with other section declarations pub fn is_global(&self) -> bool { @@ -447,7 +454,7 @@ impl DebugSectionDecl { impl Default for DebugSectionDecl { fn default() -> Self { - DebugSectionDecl {} + DebugSectionDecl { datatype: DataType::Bytes } } } diff --git a/src/elf.rs b/src/elf.rs index 0c0ff9f..c1ec2b4 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -7,7 +7,8 @@ use crate::{ artifact::{ - self, Artifact, Decl, DefinedDecl, ImportKind, LinkAndDecl, Reloc, Scope, Visibility, DataType + self, Artifact, DataType, Decl, DefinedDecl, ImportKind, LinkAndDecl, Reloc, Scope, + Visibility, }, target::make_ctx, Ctx, @@ -192,15 +193,6 @@ enum SectionType { None, } -impl SectionType { - pub fn from_datatype(datatype: DataType) -> Self { - match datatype { - DataType::Bytes => SectionType::Bits, - DataType::String => SectionType::String, - } - } -} - /// A builder for creating a 32/64 bit section struct SectionBuilder { typ: SectionType, @@ -501,15 +493,22 @@ impl<'a> Elf<'a> { .writable(false) .exec(true), DefinedDecl::Data(d) => SectionBuilder::new(def_size as u64) - .section_type(SectionType::from_datatype(d.get_datatype())) + .section_type(match d.get_datatype() { + DataType::Bytes => SectionType::Data, + DataType::String => SectionType::String, + }) .alloc() .writable(d.is_writable()) .exec(false), - DefinedDecl::DebugSection(_) => SectionBuilder::new(def_size as u64).section_type( + DefinedDecl::DebugSection(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" { SectionType::String } else { - SectionType::Bits + match d.get_datatype() { + DataType::Bytes => SectionType::Bits, + DataType::String => SectionType::String, + } }, ), }; @@ -548,7 +547,9 @@ impl<'a> Elf<'a> { let size = data.len(); // the symbols section reference/index will be the current number of sections let shndx = self.sections.len() + 3; // null + strtab + symtab - let section_symbol = SymbolBuilder::new(SymbolType::Section).section_index(shndx).create(); + let section_symbol = SymbolBuilder::new(SymbolType::Section) + .section_index(shndx) + .create(); let mut section = section.name_offset(offset).create(&self.ctx); // the offset is the head of how many program bits we've added From d59a3489f4ba41c67081e48a33da415fe97ca010 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 21 Feb 2019 13:00:57 -0800 Subject: [PATCH 07/17] add alignment from decl through to elf --- src/artifact/decl.rs | 219 ++++++++++++++++++++++++------------------- src/elf.rs | 44 ++++----- 2 files changed, 145 insertions(+), 118 deletions(-) diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index 9eabcbe..19b1499 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -41,6 +41,39 @@ pub enum Scope { Weak, } +macro_rules! scope_methods { + () => { + /// Set scope to global + pub fn global(self) -> Self { + self.with_scope(Scope::Global) + } + /// Set scope to local + pub fn local(self) -> Self { + self.with_scope(Scope::Local) + } + /// Set scope to weak + pub fn weak(self) -> Self { + self.with_scope(Scope::Weak) + } + /// Builder for scope + pub fn with_scope(mut self, scope: Scope) -> Self { + self.scope = scope; + self + } + /// Gst scope + pub fn get_scope(&self) -> Scope { + self.scope + } + /// Set scope + pub fn set_scope(&mut self, scope: Scope) { + self.scope = scope; + } + /// Check if scope is `Scope::Global` + pub fn is_global(&self) -> bool { + self.scope == Scope::Global + } +}} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Linker visibility of a definition pub enum Visibility { @@ -54,6 +87,80 @@ pub enum Visibility { Hidden, } +macro_rules! visibility_methods { + () => { + /// Set visibility to default + pub fn default_visibility(self) -> Self { + self.with_visibility(Visibility::Default) + } + /// Set visibility to protected + pub fn protected(self) -> Self { + self.with_visibility(Visibility::Protected) + } + /// Set visibility to hidden + pub fn hidden(self) -> Self { + self.with_visibility(Visibility::Hidden) + } + /// Builder for visibility + pub fn with_visibility(mut self, visibility: Visibility) -> Self { + self.visibility =visibility; + self + } + /// Get visibility + pub fn get_visibility(&self) -> Visibility { + self.visibility + } + /// Set visibility + pub fn set_visibility(&mut self, visibility: Visibility) { + self.visibility = visibility; + } +}} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +/// Type of data declared +pub enum DataType { + /// Ordinary raw bytes + Bytes, + /// 0-terminated ascii string + String, +} + +macro_rules! datatype_methods { + () => { + /// Build datatype + pub fn with_datatype(mut self, datatype: DataType) -> Self { + self.datatype = datatype; + self + } + /// Set datatype + pub fn set_datatype(&mut self, datatype: DataType) { + self.datatype = datatype; + } + /// Get datatype + pub fn get_datatype(&self) -> DataType { + self.datatype + } + } +} + +macro_rules! align_methods { + () => { + /// Build alignment + pub fn with_align(mut self, align: Option) -> Self { + self.align = align; + self + } + /// Set alignment + pub fn set_align(&mut self, align: Option) { + self.align = align; + } + /// Get alignment + pub fn get_align(&self) -> Option { + self.align + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// A declaration that is defined inside this artifact pub enum DefinedDecl { @@ -103,9 +210,7 @@ impl DefinedDecl { pub fn is_writable(&self) -> bool { match self { DefinedDecl::Data(a) => a.is_writable(), - DefinedDecl::Function(_) | DefinedDecl::DebugSection(_) => { - false - } + DefinedDecl::Function(_) | DefinedDecl::DebugSection(_) => false, } } } @@ -275,73 +380,12 @@ impl Into for DataImportDecl { } } -macro_rules! scope_methods { - () => { - /// Set scope to global - pub fn global(self) -> Self { - self.with_scope(Scope::Global) - } - /// Set scope to local - pub fn local(self) -> Self { - self.with_scope(Scope::Local) - } - /// Set scope to weak - pub fn weak(self) -> Self { - self.with_scope(Scope::Weak) - } - /// Builder for scope - pub fn with_scope(mut self, scope: Scope) -> Self { - self.scope = scope; - self - } - /// Gst scope - pub fn get_scope(&self) -> Scope { - self.scope - } - /// Set scope - pub fn set_scope(&mut self, scope: Scope) { - self.scope = scope; - } - /// Check if scope is `Scope::Global` - pub fn is_global(&self) -> bool { - self.scope == Scope::Global - } -}} - -macro_rules! visibility_methods { - () => { - /// Set visibility to default - pub fn default_visibility(self) -> Self { - self.with_visibility(Visibility::Default) - } - /// Set visibility to protected - pub fn protected(self) -> Self { - self.with_visibility(Visibility::Protected) - } - /// Set visibility to hidden - pub fn hidden(self) -> Self { - self.with_visibility(Visibility::Hidden) - } - /// Builder for visibility - pub fn with_visibility(mut self, visibility: Visibility) -> Self { - self.visibility =visibility; - self - } - /// Get visibility - pub fn get_visibility(&self) -> Visibility { - self.visibility - } - /// Set visibility - pub fn set_visibility(&mut self, visibility: Visibility) { - self.visibility = visibility; - } -}} - #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Builder for function declarations pub struct FunctionDecl { scope: Scope, visibility: Visibility, + align: Option, } impl Default for FunctionDecl { @@ -349,6 +393,7 @@ impl Default for FunctionDecl { FunctionDecl { scope: Scope::Local, visibility: Visibility::Default, + align: None, } } } @@ -356,6 +401,7 @@ impl Default for FunctionDecl { impl FunctionDecl { scope_methods!(); visibility_methods!(); + align_methods!(); } impl Into for FunctionDecl { @@ -364,15 +410,6 @@ impl Into for FunctionDecl { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -/// Type of data declared -pub enum DataType { - /// Ordinary raw bytes - Bytes, - /// 0-terminated ascii string - String, -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Builder for data declarations pub struct DataDecl { @@ -380,24 +417,7 @@ pub struct DataDecl { visibility: Visibility, writable: bool, datatype: DataType, -} - -macro_rules! datatype_methods { - () => { - /// Build datatype - pub fn with_datatype(mut self, datatype: DataType) -> Self { - self.datatype = datatype; - self - } - /// Set datatype - pub fn set_datatype(&mut self, datatype: DataType) { - self.datatype = datatype; - } - /// Get datatype - pub fn get_datatype(&self) -> DataType { - self.datatype - } - } + align: Option, } impl Default for DataDecl { @@ -407,6 +427,7 @@ impl Default for DataDecl { visibility: Visibility::Default, writable: false, datatype: DataType::Bytes, + align: None, } } } @@ -415,6 +436,7 @@ impl DataDecl { scope_methods!(); visibility_methods!(); datatype_methods!(); + align_methods!(); /// Set mutability to writable pub fn writable(mut self) -> Self { self.writable = true; @@ -429,7 +451,6 @@ impl DataDecl { pub fn is_writable(&self) -> bool { self.writable } - } impl Into for DataDecl { @@ -438,13 +459,16 @@ impl Into for DataDecl { } } - #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] /// Builder for a debug section declaration -pub struct DebugSectionDecl { datatype: DataType } +pub struct DebugSectionDecl { + datatype: DataType, + align: Option, +} impl DebugSectionDecl { datatype_methods!(); + align_methods!(); /// Debug sections are never global, but we have an accessor /// for symmetry with other section declarations pub fn is_global(&self) -> bool { @@ -454,7 +478,10 @@ impl DebugSectionDecl { impl Default for DebugSectionDecl { fn default() -> Self { - DebugSectionDecl { datatype: DataType::Bytes } + DebugSectionDecl { + datatype: DataType::Bytes, + align: None, + } } } diff --git a/src/elf.rs b/src/elf.rs index c1ec2b4..bf8823d 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -201,6 +201,7 @@ struct SectionBuilder { alloc: bool, size: u64, name_offset: usize, + align: Option, } impl SectionBuilder { @@ -213,6 +214,7 @@ impl SectionBuilder { alloc: false, name_offset: 0, size, + align: None, } } /// Make this section executable @@ -230,6 +232,11 @@ impl SectionBuilder { self.write = writable; self } + /// Specify section alignment + pub fn align(mut self, align: Option) -> Self { + self.align = align; + self + } /// Set the byte offset of this section's name in the corresponding strtab pub fn name_offset(mut self, name_offset: usize) -> Self { @@ -257,36 +264,29 @@ impl SectionBuilder { if self.alloc { shdr.sh_flags |= SHF_ALLOC as u64 } + + let align = if let Some(align) = self.align { + align as u64 + } else if self.exec { + 0x10 + } else if self.write { + 0x8 + } else { + 1 + }; + match self.typ { SectionType::Bits => { - shdr.sh_addralign = if self.exec { - 0x10 - } else if self.write { - 0x8 - } else { - 1 - }; - shdr.sh_type = SHT_PROGBITS + shdr.sh_addralign = align; + shdr.sh_type = SHT_PROGBITS; } SectionType::String => { - shdr.sh_addralign = if self.exec { - 0x10 - } else if self.write { - 0x8 - } else { - 1 - }; + shdr.sh_addralign = align; shdr.sh_type = SHT_PROGBITS; shdr.sh_flags |= (SHF_MERGE | SHF_STRINGS) as u64; } SectionType::Data => { - shdr.sh_addralign = if self.exec { - 0x10 - } else if self.write { - 0x8 - } else { - 1 - }; + shdr.sh_addralign = align; shdr.sh_type = SHT_PROGBITS; } SectionType::StrTab => { From 47e6069b81ec4d21e8fc10906c2af9acaddccd22 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 21 Feb 2019 14:54:36 -0800 Subject: [PATCH 08/17] readme: update decls, segment for string --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 09f862e..13820ea 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,11 @@ let mut obj = ArtifactBuilder::new(triple!("x86_64-unknown-unknown-unknown-elf") // it is a runtime error to define a symbol _without_ declaring it first obj.declarations( [ - ("deadbeef", Decl::Function { global: false }), - ("main", Decl::Function { global: true }), - ("str.1", Decl::CString { global: false }), - ("DEADBEEF", Decl::DataImport), - ("printf", Decl::FunctionImport), + ("deadbeef", Decl::function().into()), + ("main", Decl::function().global().into()), + ("str.1", Decl::cstring().into()), + ("DEADBEEF", Decl::data_import()), + ("printf", Decl::function_import()), ].into_iter().cloned() )?; @@ -89,7 +89,7 @@ e_phoff: 0x0 e_shoff: 0x2a20 SHT_NULL 0x0 0x0 0x0 0x0 0x0 1 .strtab SHT_STRTAB 0x8c 0x0 0xc6 0x0 0x1 2 .symtab SHT_SYMTAB 0x152 0x0 0xf0 .strtab(1) 0x18 0x8 - 3 .data.str.1 SHT_PROGBITS ALLOC MERGE STRINGS 0x40 0x0 0x10 0x1 0x1 + 3 .rodata.str.1 SHT_PROGBITS ALLOC MERGE STRINGS 0x40 0x0 0x10 0x1 0x1 4 .text.deadbeef SHT_PROGBITS ALLOC EXECINSTR 0x50 0x0 0x14 0x0 0x10 5 .text.main SHT_PROGBITS ALLOC EXECINSTR 0x64 0x0 0x28 0x0 0x10 6 .reloc.main SHT_RELA 0x242 0x0 0x48 .symtab(2) 0x18 0x8 @@ -100,10 +100,10 @@ e_phoff: 0x0 e_shoff: 0x2a2 Addr Bind Type Symbol Size Section Other 0 LOCAL NOTYPE 0x0 0x0 0 LOCAL FILE test.o 0x0 ABS 0x0 - 0 LOCAL SECTION 0x0 .data.str.1(3) 0x0 + 0 LOCAL SECTION 0x0 .rodata.str.1(3) 0x0 0 LOCAL SECTION 0x0 .text.deadbeef(4) 0x0 0 LOCAL SECTION 0x0 .text.main(5) 0x0 - 0 LOCAL OBJECT str.1 0x10 .data.str.1(3) 0x0 + 0 LOCAL OBJECT str.1 0x10 .rodata.str.1(3) 0x0 0 LOCAL FUNC deadbeef 0x14 .text.deadbeef(4) 0x0 0 GLOBAL FUNC main 0x28 .text.main(5) 0x0 0 GLOBAL NOTYPE DEADBEEF 0x0 0x0 @@ -111,7 +111,7 @@ e_phoff: 0x0 e_shoff: 0x2a2Shdr Relocations(4): .text.main(3) - 13 X86_64_PC32 .data.str.1 + 13 X86_64_PC32 .rodata.str.1 1d X86_64_PLT32 printf+-4 a X86_64_PLT32 .text.deadbeef+-4 From 7dff5b4b2a19080f4998afac0708269415c017a1 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 21 Feb 2019 15:12:50 -0800 Subject: [PATCH 09/17] artifact: fix use statement for 2018 --- src/artifact.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/artifact.rs b/src/artifact.rs index 0a9a5ea..48148f6 100644 --- a/src/artifact.rs +++ b/src/artifact.rs @@ -12,7 +12,7 @@ use std::io::Write; use crate::{elf, mach}; pub(crate) mod decl; -pub use decl::{DataType, Decl, DefinedDecl, ImportKind, Scope, Visibility}; +pub use crate::artifact::decl::{DataType, Decl, DefinedDecl, ImportKind, Scope, Visibility}; /// A blob of binary bytes, representing a function body, or data object pub type Data = Vec; From 0b0dcf248cf7b34b69bc998eb897a6d6bc1cf103 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 21 Feb 2019 15:44:50 -0800 Subject: [PATCH 10/17] writable attribute needed builder --- src/artifact/decl.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index 19b1499..2207639 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -437,15 +437,22 @@ impl DataDecl { visibility_methods!(); datatype_methods!(); align_methods!(); - /// Set mutability to writable - pub fn writable(mut self) -> Self { - self.writable = true; + /// Builder for writability + pub fn with_writable(mut self, writable: bool) -> Self { + self.writable = writable; self } + /// Set mutability to writable + pub fn writable(self) -> Self { + self.with_writable(true) + } /// Set mutability to read-only - pub fn read_only(mut self) -> Self { - self.writable = false; - self + pub fn read_only(self) -> Self { + self.with_writable(false) + } + /// Setter for mutability + pub fn set_writable(&mut self, writable: bool) { + self.writable = writable; } /// Accessor for mutability pub fn is_writable(&self) -> bool { From 31f98522da98511ebed8a04f2f5db0ad92b83913 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 22 Feb 2019 11:54:51 -0800 Subject: [PATCH 11/17] bump goblin to 0.21, use STV definitions --- Cargo.toml | 2 +- src/elf.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e07bc77..28a6a54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ name = "prototype" path = "src/bin/main.rs" [dependencies] -goblin = "0.0.19" +goblin = "0.0.21" scroll = "0.9" log = "0.4" env_logger = "0.5" diff --git a/src/elf.rs b/src/elf.rs index bf8823d..d7ea1c0 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -120,7 +120,7 @@ impl<'a> SymbolBuilder<'a> { use goblin::elf::section_header::SHN_ABS; use goblin::elf::sym::{ STB_GLOBAL, STB_LOCAL, STB_WEAK, STT_FILE, STT_FUNC, STT_NOTYPE, STT_OBJECT, - STT_SECTION, + STT_SECTION, STV_DEFAULT, STV_HIDDEN, STV_PROTECTED }; let mut st_shndx = self.shndx; let mut st_info = 0; @@ -136,12 +136,11 @@ impl<'a> SymbolBuilder<'a> { flag << 4 } - // TODO put these into goblin fn vis_stother_flags(v: Visibility) -> u8 { match v { - Visibility::Default => 0, - Visibility::Hidden => 2, - Visibility::Protected => 3, + Visibility::Default => STV_DEFAULT, + Visibility::Hidden => STV_HIDDEN, + Visibility::Protected => STV_PROTECTED, } } From 5909c3e2b793fe96a7c4836dbfbb38a941df4f99 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 22 Feb 2019 12:56:31 -0800 Subject: [PATCH 12/17] export ArtifactError from crate, and use it on declare --- src/artifact.rs | 2 +- src/artifact/decl.rs | 3 +-- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/artifact.rs b/src/artifact.rs index 48148f6..175309d 100644 --- a/src/artifact.rs +++ b/src/artifact.rs @@ -282,7 +282,7 @@ impl Artifact { } /// Declare a new symbolic reference, with the given `decl`. /// **Note**: All declarations _must_ precede their definitions. - pub fn declare, D: Into>(&mut self, name: T, decl: D) -> Result<(), Error> { + pub fn declare, D: Into>(&mut self, name: T, decl: D) -> Result<(), ArtifactError> { let decl = decl.into(); let decl_name = self.strings.get_or_intern(name.as_ref()); let previous_was_import; diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index 2207639..0645684 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -1,5 +1,4 @@ use crate::artifact::ArtifactError; -use failure::Error; /// The kind of declaration this is #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -254,7 +253,7 @@ impl Decl { /// 4. Anything else is a [IncompatibleDeclaration](enum.ArtifactError.html#variant.IncompatibleDeclaration) error! // ref https://github.com/m4b/faerie/issues/24 // ref https://github.com/m4b/faerie/issues/18 - pub fn absorb(&mut self, other: Self) -> Result<(), Error> { + pub fn absorb(&mut self, other: Self) -> Result<(), ArtifactError> { // FIXME: i can't think of a way offhand to not clone here, without unusual contortions match self.clone() { Decl::Import(ImportKind::Data) => { diff --git a/src/lib.rs b/src/lib.rs index c474408..a870fa4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,5 +25,5 @@ pub use crate::artifact::{ DataDecl, DataImportDecl, DataType, DebugSectionDecl, Decl, FunctionDecl, FunctionImportDecl, Scope, Visibility, }, - Artifact, ArtifactBuilder, ImportKind, Link, Reloc, + Artifact, ArtifactBuilder, ArtifactError, ImportKind, Link, Reloc, }; From 0ce05662eac73bb019dc4f848355f287bc46e47c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 22 Feb 2019 14:03:10 -0800 Subject: [PATCH 13/17] elf: actually thread alignment through good thing i wrote tests! --- src/elf.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/elf.rs b/src/elf.rs index d7ea1c0..7f038c1 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -486,11 +486,12 @@ impl<'a> Elf<'a> { }; let section = match decl { - DefinedDecl::Function(_) => SectionBuilder::new(def_size as u64) + DefinedDecl::Function(d) => SectionBuilder::new(def_size as u64) .section_type(SectionType::Bits) .alloc() .writable(false) - .exec(true), + .exec(true) + .align(d.get_align()), DefinedDecl::Data(d) => SectionBuilder::new(def_size as u64) .section_type(match d.get_datatype() { DataType::Bytes => SectionType::Data, @@ -498,7 +499,8 @@ impl<'a> Elf<'a> { }) .alloc() .writable(d.is_writable()) - .exec(false), + .exec(false) + .align(d.get_align()), DefinedDecl::DebugSection(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" { @@ -509,7 +511,8 @@ impl<'a> Elf<'a> { DataType::String => SectionType::String, } }, - ), + ) + .align(d.get_align()), }; let shndx = self.add_progbits(section_name, section, data); From 5a85a2709c4bfda3f021bb6cca5be42d8a7bfa4a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 22 Feb 2019 14:03:25 -0800 Subject: [PATCH 14/17] elf tests: add a test suite that maps decl to sym & sect flags --- tests/elf.rs | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 2 deletions(-) diff --git a/tests/elf.rs b/tests/elf.rs index c60be99..d07fce6 100644 --- a/tests/elf.rs +++ b/tests/elf.rs @@ -3,11 +3,13 @@ extern crate goblin; extern crate scroll; #[macro_use] extern crate target_lexicon; - -use std::str::FromStr; +#[macro_use] +extern crate failure; use faerie::{Artifact, Decl, Link}; +use failure::Error; use goblin::elf::*; +use std::str::FromStr; #[test] // This test is for a known bug (issue #31). @@ -72,3 +74,172 @@ fn link_symbol_pair_panic_issue_30() { // and return an error describing them: assert!(obj.emit().is_err()); } + + +#[test] +fn decl_attributes() { + decl_tests(vec![ + DeclTestCase::new("weak_func", Decl::function().weak(), |sym, sect| { + ensure!(sym.is_function(), "symbol is function"); + ensure!(sym.st_bind() == sym::STB_WEAK, "symbol is weak"); + ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); + ensure!(sect.is_executable(), "executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }), + DeclTestCase::new("weak_data", Decl::data().weak(), |sym, sect| { + ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); + ensure!(sym.st_bind() == sym::STB_WEAK, "symbol is weak"); + ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); + ensure!(!sect.is_executable(), "not executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }), + DeclTestCase::new("weak_data_writable", Decl::data().weak().writable(), |sym, sect| { + ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); + ensure!(sym.st_bind() == sym::STB_WEAK, "symbol is weak"); + ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); + ensure!(!sect.is_executable(), "not executable"); + ensure!(sect.is_writable(), "mutable"); + Ok(()) + }), + DeclTestCase::new("weak_cstring", Decl::cstring().weak(), |sym, sect| { + ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); + ensure!(sym.st_bind() == sym::STB_WEAK, "symbol is weak"); + ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); + ensure!(!sect.is_executable(), "not executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }), + DeclTestCase::new("hidden_func", Decl::function().hidden(), |sym, sect| { + ensure!(sym.is_function(), "symbol is func"); + ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is local"); + ensure!(sym.st_visibility() == sym::STV_HIDDEN, "symbol is hidden"); + ensure!(sect.is_executable(), "executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }), + DeclTestCase::new("hidden_data", Decl::data().hidden(), |sym, sect| { + ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); + ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is local"); + ensure!(sym.st_visibility() == sym::STV_HIDDEN, "symbol is hidden"); + ensure!(!sect.is_executable(), "not executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }), + DeclTestCase::new("hidden_cstring", Decl::cstring().hidden(), |sym, sect| { + ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); + ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is weak"); + ensure!(sym.st_visibility() == sym::STV_HIDDEN, "symbol is hidden"); + ensure!(!sect.is_executable(), "not executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }), + DeclTestCase::new("protected_func", Decl::function().protected(), |sym, sect| { + ensure!(sym.is_function(), "symbol is func"); + ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is local"); + ensure!(sym.st_visibility() == sym::STV_PROTECTED, "symbol is protected"); + ensure!(sect.is_executable(), "executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }), + DeclTestCase::new("protected_data", Decl::data().protected(), |sym, sect| { + ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); + ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is local"); + ensure!(sym.st_visibility() == sym::STV_PROTECTED, "symbol is protected"); + ensure!(!sect.is_executable(), "not executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }), + DeclTestCase::new("protected_cstring", Decl::cstring().protected(), |sym, sect| { + ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); + ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is weak"); + ensure!(sym.st_visibility() == sym::STV_PROTECTED, "symbol is protected"); + ensure!(!sect.is_executable(), "not executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }), + DeclTestCase::new("ordinary_func", Decl::function(), |sym, sect| { + ensure!(sym.is_function(), "symbol is function"); + ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is local"); + ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); + ensure!(sect.is_executable(), "executable"); + ensure!(!sect.is_writable(), "immutable"); + ensure!(sect.sh_addralign == 16, "aligned to 16"); + Ok(()) + }), + + DeclTestCase::new("custom_align_func", Decl::function().with_align(Some(64)), |_sym, sect| { + ensure!(sect.sh_addralign == 64, "expected aligned to 64, got {}", sect.sh_addralign); + Ok(()) + }), + + DeclTestCase::new("custom_align_data", Decl::data().with_align(Some(128)), |_sym, sect| { + ensure!(sect.sh_addralign == 128, "expected aligned to 128, got {}", sect.sh_addralign); + Ok(()) + }), + + ]); +} + +/* test scaffolding: */ + +fn decl_tests(tests: Vec) { + + let mut obj = Artifact::new(triple!("x86_64-unknown-unknown-unknown-elf"), "a".into()); + for t in tests.iter() { + t.define(&mut obj); + } + + println!("\n{:#?}", obj); + let bytes = obj.emit().expect("can emit elf file"); + let bytes = bytes.as_slice(); + println!("{:?}", bytes); + + let elf = goblin::Object::parse(&bytes).expect("can parse elf file"); + + match elf { + goblin::Object::Elf(elf) => { + for t in tests { + t.check(&elf) + } + } + _ => { + panic!("Elf file not parsed as elf file"); + } + } +} + +struct DeclTestCase { + name: String, + decl: Decl, + pred: Box Result<(), Error>>, +} +impl DeclTestCase { + fn new(name: &str, decl: D, pred: F) -> Self + where + D: Into, + F: Fn(&Sym, &SectionHeader) -> Result<(), Error> + 'static, + { + Self { + name: name.to_owned(), + decl: decl.into(), + pred: Box::new(pred), + } + } + fn define(&self, art: &mut Artifact) { + art.declare(&self.name, self.decl) + .expect(&format!("declare {}", self.name)); + art.define(&self.name, vec![1, 2, 3, 4]) + .expect(&format!("define {}", self.name)); + } + fn check(&self, elf: &goblin::elf::Elf) { + let sym = elf + .syms + .iter() + .find(|sym| &elf.strtab[sym.st_name] == self.name) + .expect("symbol should exist"); + let sectheader = elf.section_headers.get(sym.st_shndx).expect("section header should exist"); + (self.pred)(&sym, sectheader).expect(&format!("check {}", self.name)) + } +} From 090fd1a00fe52643381ef36c974dfe234d59f2e9 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Fri, 22 Feb 2019 14:04:46 -0800 Subject: [PATCH 15/17] fmt --- src/artifact.rs | 6 ++- src/elf.rs | 27 +++++----- tests/elf.rs | 136 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 112 insertions(+), 57 deletions(-) diff --git a/src/artifact.rs b/src/artifact.rs index 175309d..9e026af 100644 --- a/src/artifact.rs +++ b/src/artifact.rs @@ -282,7 +282,11 @@ impl Artifact { } /// Declare a new symbolic reference, with the given `decl`. /// **Note**: All declarations _must_ precede their definitions. - pub fn declare, D: Into>(&mut self, name: T, decl: D) -> Result<(), ArtifactError> { + pub fn declare, D: Into>( + &mut self, + name: T, + decl: D, + ) -> Result<(), ArtifactError> { let decl = decl.into(); let decl_name = self.strings.get_or_intern(name.as_ref()); let previous_was_import; diff --git a/src/elf.rs b/src/elf.rs index 7f038c1..f765bb3 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -120,7 +120,7 @@ impl<'a> SymbolBuilder<'a> { use goblin::elf::section_header::SHN_ABS; use goblin::elf::sym::{ STB_GLOBAL, STB_LOCAL, STB_WEAK, STT_FILE, STT_FUNC, STT_NOTYPE, STT_OBJECT, - STT_SECTION, STV_DEFAULT, STV_HIDDEN, STV_PROTECTED + STT_SECTION, STV_DEFAULT, STV_HIDDEN, STV_PROTECTED, }; let mut st_shndx = self.shndx; let mut st_info = 0; @@ -501,18 +501,19 @@ impl<'a> Elf<'a> { .writable(d.is_writable()) .exec(false) .align(d.get_align()), - DefinedDecl::DebugSection(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" { - SectionType::String - } else { - match d.get_datatype() { - DataType::Bytes => SectionType::Bits, - DataType::String => SectionType::String, - } - }, - ) - .align(d.get_align()), + DefinedDecl::DebugSection(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" { + SectionType::String + } else { + match d.get_datatype() { + DataType::Bytes => SectionType::Bits, + DataType::String => SectionType::String, + } + }, + ) + .align(d.get_align()), }; let shndx = self.add_progbits(section_name, section, data); diff --git a/tests/elf.rs b/tests/elf.rs index d07fce6..fa91495 100644 --- a/tests/elf.rs +++ b/tests/elf.rs @@ -75,14 +75,16 @@ fn link_symbol_pair_panic_issue_30() { assert!(obj.emit().is_err()); } - #[test] fn decl_attributes() { decl_tests(vec![ DeclTestCase::new("weak_func", Decl::function().weak(), |sym, sect| { ensure!(sym.is_function(), "symbol is function"); ensure!(sym.st_bind() == sym::STB_WEAK, "symbol is weak"); - ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); + ensure!( + sym.st_visibility() == sym::STV_DEFAULT, + "symbol is default vis" + ); ensure!(sect.is_executable(), "executable"); ensure!(!sect.is_writable(), "immutable"); Ok(()) @@ -90,23 +92,36 @@ fn decl_attributes() { DeclTestCase::new("weak_data", Decl::data().weak(), |sym, sect| { ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); ensure!(sym.st_bind() == sym::STB_WEAK, "symbol is weak"); - ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); + ensure!( + sym.st_visibility() == sym::STV_DEFAULT, + "symbol is default vis" + ); ensure!(!sect.is_executable(), "not executable"); ensure!(!sect.is_writable(), "immutable"); Ok(()) }), - DeclTestCase::new("weak_data_writable", Decl::data().weak().writable(), |sym, sect| { - ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); - ensure!(sym.st_bind() == sym::STB_WEAK, "symbol is weak"); - ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); - ensure!(!sect.is_executable(), "not executable"); - ensure!(sect.is_writable(), "mutable"); - Ok(()) - }), + DeclTestCase::new( + "weak_data_writable", + Decl::data().weak().writable(), + |sym, sect| { + ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); + ensure!(sym.st_bind() == sym::STB_WEAK, "symbol is weak"); + ensure!( + sym.st_visibility() == sym::STV_DEFAULT, + "symbol is default vis" + ); + ensure!(!sect.is_executable(), "not executable"); + ensure!(sect.is_writable(), "mutable"); + Ok(()) + }, + ), DeclTestCase::new("weak_cstring", Decl::cstring().weak(), |sym, sect| { ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); ensure!(sym.st_bind() == sym::STB_WEAK, "symbol is weak"); - ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); + ensure!( + sym.st_visibility() == sym::STV_DEFAULT, + "symbol is default vis" + ); ensure!(!sect.is_executable(), "not executable"); ensure!(!sect.is_writable(), "immutable"); Ok(()) @@ -135,57 +150,89 @@ fn decl_attributes() { ensure!(!sect.is_writable(), "immutable"); Ok(()) }), - DeclTestCase::new("protected_func", Decl::function().protected(), |sym, sect| { - ensure!(sym.is_function(), "symbol is func"); - ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is local"); - ensure!(sym.st_visibility() == sym::STV_PROTECTED, "symbol is protected"); - ensure!(sect.is_executable(), "executable"); - ensure!(!sect.is_writable(), "immutable"); - Ok(()) - }), + DeclTestCase::new( + "protected_func", + Decl::function().protected(), + |sym, sect| { + ensure!(sym.is_function(), "symbol is func"); + ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is local"); + ensure!( + sym.st_visibility() == sym::STV_PROTECTED, + "symbol is protected" + ); + ensure!(sect.is_executable(), "executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }, + ), DeclTestCase::new("protected_data", Decl::data().protected(), |sym, sect| { ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is local"); - ensure!(sym.st_visibility() == sym::STV_PROTECTED, "symbol is protected"); - ensure!(!sect.is_executable(), "not executable"); - ensure!(!sect.is_writable(), "immutable"); - Ok(()) - }), - DeclTestCase::new("protected_cstring", Decl::cstring().protected(), |sym, sect| { - ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); - ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is weak"); - ensure!(sym.st_visibility() == sym::STV_PROTECTED, "symbol is protected"); + ensure!( + sym.st_visibility() == sym::STV_PROTECTED, + "symbol is protected" + ); ensure!(!sect.is_executable(), "not executable"); ensure!(!sect.is_writable(), "immutable"); Ok(()) }), + DeclTestCase::new( + "protected_cstring", + Decl::cstring().protected(), + |sym, sect| { + ensure!(sym.st_type() == sym::STT_OBJECT, "symbol is object"); + ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is weak"); + ensure!( + sym.st_visibility() == sym::STV_PROTECTED, + "symbol is protected" + ); + ensure!(!sect.is_executable(), "not executable"); + ensure!(!sect.is_writable(), "immutable"); + Ok(()) + }, + ), DeclTestCase::new("ordinary_func", Decl::function(), |sym, sect| { ensure!(sym.is_function(), "symbol is function"); ensure!(sym.st_bind() == sym::STB_LOCAL, "symbol is local"); - ensure!(sym.st_visibility() == sym::STV_DEFAULT, "symbol is default vis"); + ensure!( + sym.st_visibility() == sym::STV_DEFAULT, + "symbol is default vis" + ); ensure!(sect.is_executable(), "executable"); ensure!(!sect.is_writable(), "immutable"); ensure!(sect.sh_addralign == 16, "aligned to 16"); Ok(()) }), - - DeclTestCase::new("custom_align_func", Decl::function().with_align(Some(64)), |_sym, sect| { - ensure!(sect.sh_addralign == 64, "expected aligned to 64, got {}", sect.sh_addralign); - Ok(()) - }), - - DeclTestCase::new("custom_align_data", Decl::data().with_align(Some(128)), |_sym, sect| { - ensure!(sect.sh_addralign == 128, "expected aligned to 128, got {}", sect.sh_addralign); - Ok(()) - }), - + DeclTestCase::new( + "custom_align_func", + Decl::function().with_align(Some(64)), + |_sym, sect| { + ensure!( + sect.sh_addralign == 64, + "expected aligned to 64, got {}", + sect.sh_addralign + ); + Ok(()) + }, + ), + DeclTestCase::new( + "custom_align_data", + Decl::data().with_align(Some(128)), + |_sym, sect| { + ensure!( + sect.sh_addralign == 128, + "expected aligned to 128, got {}", + sect.sh_addralign + ); + Ok(()) + }, + ), ]); } /* test scaffolding: */ fn decl_tests(tests: Vec) { - let mut obj = Artifact::new(triple!("x86_64-unknown-unknown-unknown-elf"), "a".into()); for t in tests.iter() { t.define(&mut obj); @@ -239,7 +286,10 @@ impl DeclTestCase { .iter() .find(|sym| &elf.strtab[sym.st_name] == self.name) .expect("symbol should exist"); - let sectheader = elf.section_headers.get(sym.st_shndx).expect("section header should exist"); + let sectheader = elf + .section_headers + .get(sym.st_shndx) + .expect("section header should exist"); (self.pred)(&sym, sectheader).expect(&format!("check {}", self.name)) } } From 8aa9550f31c1fd6f23b48b1b5d2cb0f40611988a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Sat, 23 Feb 2019 11:27:27 -0800 Subject: [PATCH 16/17] add docs per sunfishcode's code review --- src/artifact/decl.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/artifact/decl.rs b/src/artifact/decl.rs index 0645684..ea81028 100644 --- a/src/artifact/decl.rs +++ b/src/artifact/decl.rs @@ -36,7 +36,8 @@ pub enum Scope { /// Available only inside the defining component Local, /// Available to all modules, but only selected if a Global - /// definition is not found + /// definition is not found. No conflict if there are multiple + /// weak symbols. Weak, } @@ -67,7 +68,7 @@ macro_rules! scope_methods { pub fn set_scope(&mut self, scope: Scope) { self.scope = scope; } - /// Check if scope is `Scope::Global` + /// Check if scope is `Scope::Global`. False if set to Local or Weak. pub fn is_global(&self) -> bool { self.scope == Scope::Global } @@ -120,7 +121,7 @@ macro_rules! visibility_methods { pub enum DataType { /// Ordinary raw bytes Bytes, - /// 0-terminated ascii string + /// 0-terminated C-style string. String, } @@ -144,7 +145,8 @@ macro_rules! datatype_methods { macro_rules! align_methods { () => { - /// Build alignment + /// Build alignment. Size is in bytes. If None, a default is chosen + /// in the backend. pub fn with_align(mut self, align: Option) -> Self { self.align = align; self From 4bf9650dc3e32c425b08bd72aa8dcbaf0acb68ac Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Sat, 23 Feb 2019 11:28:22 -0800 Subject: [PATCH 17/17] bump version to 0.8.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 28a6a54..5c38b51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "faerie" -version = "0.7.1" +version = "0.8.0" authors = ["m4b ", "Dan Gohman ", "Pat Hickey ", "Philip Craig "] readme = "README.md" keywords = ["elf", "mach-o", "binary", "object", "compiler"]