use failure::Error;
use indexmap::IndexMap;
use string_interner::DefaultStringInterner;
use target_lexicon::{BinaryFormat, Triple};
use std::collections::BTreeSet;
use std::fs::File;
use std::io::Write;
use crate::{elf, mach};
pub(crate) mod decl;
pub use crate::artifact::decl::{DataType, Decl, DefinedDecl, ImportKind, Scope, Visibility};
pub type Data = Vec<u8>;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub enum Reloc {
Auto,
Raw {
reloc: u32,
addend: i32,
},
Debug {
size: u8,
addend: i32,
},
}
type StringID = usize;
type Relocation = (StringID, StringID, u64, Reloc);
#[derive(Fail, Debug)]
pub enum ArtifactError {
#[fail(display = "Undeclared symbolic reference to: {}", _0)]
Undeclared(String),
#[fail(display = "Attempt to define an undefined import: {}", _0)]
ImportDefined(String),
#[fail(display = "Attempt to add a relocation to an import: {}", _0)]
RelocateImport(String),
#[fail(
display = "Incompatible declarations, old declaration {:?} is incompatible with new {:?}",
old, new
)]
IncompatibleDeclaration {
old: Decl,
new: Decl,
},
#[fail(display = "duplicate definition of symbol: {}", _0)]
DuplicateDefinition(String),
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
struct InternalDefinition {
decl: DefinedDecl,
name: StringID,
data: Data,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct InternalDecl {
decl: Decl,
defined: bool,
}
impl InternalDecl {
pub fn new(decl: Decl) -> Self {
Self {
decl: decl,
defined: false,
}
}
pub fn define(&mut self) {
self.defined = true;
}
}
#[derive(Debug)]
pub struct Binding<'a> {
pub name: &'a str,
pub decl: &'a Decl,
}
#[derive(Debug)]
pub struct LinkAndDecl<'a> {
pub from: Binding<'a>,
pub to: Binding<'a>,
pub at: u64,
pub reloc: Reloc,
}
#[derive(Debug)]
pub(crate) struct Definition<'a> {
pub name: &'a str,
pub data: &'a [u8],
pub decl: &'a DefinedDecl,
}
impl<'a> From<(&'a InternalDefinition, &'a DefaultStringInterner)> for Definition<'a> {
fn from((def, strings): (&'a InternalDefinition, &'a DefaultStringInterner)) -> Self {
Definition {
name: strings
.resolve(def.name)
.expect("internal definition to have name"),
data: &def.data,
decl: &def.decl,
}
}
}
pub struct Link<'a> {
pub from: &'a str,
pub to: &'a str,
pub at: u64,
}
pub struct ArtifactBuilder {
target: Triple,
name: Option<String>,
library: bool,
}
impl ArtifactBuilder {
pub fn new(target: Triple) -> Self {
ArtifactBuilder {
target,
name: None,
library: false,
}
}
pub fn name(mut self, name: String) -> Self {
self.name = Some(name);
self
}
pub fn library(mut self, is_library: bool) -> Self {
self.library = is_library;
self
}
pub fn finish(self) -> Artifact {
let name = self.name.unwrap_or_else(|| "faerie.o".to_owned());
let mut artifact = Artifact::new(self.target, name);
artifact.is_library = self.library;
artifact
}
}
#[derive(Debug, Clone)]
pub struct Artifact {
pub name: String,
pub target: Triple,
pub is_library: bool,
imports: Vec<(StringID, ImportKind)>,
links: Vec<Relocation>,
declarations: IndexMap<StringID, InternalDecl>,
local_definitions: BTreeSet<InternalDefinition>,
nonlocal_definitions: BTreeSet<InternalDefinition>,
strings: DefaultStringInterner,
}
impl Artifact {
pub fn new(target: Triple, name: String) -> Self {
Artifact {
imports: Vec::new(),
links: Vec::new(),
name,
target,
is_library: false,
declarations: IndexMap::new(),
local_definitions: BTreeSet::new(),
nonlocal_definitions: BTreeSet::new(),
strings: DefaultStringInterner::default(),
}
}
pub fn imports<'a>(&'a self) -> Box<Iterator<Item = (&'a str, &'a ImportKind)> + 'a> {
Box::new(
self.imports
.iter()
.map(move |&(id, ref kind)| (self.strings.resolve(id).unwrap(), kind)),
)
}
pub(crate) fn definitions<'a>(&'a self) -> Box<Iterator<Item = Definition<'a>> + 'a> {
Box::new(
self.local_definitions
.iter()
.chain(self.nonlocal_definitions.iter())
.map(move |int_def| Definition::from((int_def, &self.strings))),
)
}
pub(crate) fn links<'a>(&'a self) -> Box<Iterator<Item = LinkAndDecl<'a>> + 'a> {
Box::new(
self.links
.iter()
.map(move |&(ref from, ref to, ref at, ref reloc)| {
let (ref from_decl, ref to_decl) = (
self.declarations.get(from).expect("declaration present"),
self.declarations.get(to).unwrap(),
);
let from = Binding {
name: self.strings.resolve(*from).expect("from link"),
decl: &from_decl.decl,
};
let to = Binding {
name: self.strings.resolve(*to).expect("to link"),
decl: &to_decl.decl,
};
LinkAndDecl {
from,
to,
at: *at,
reloc: *reloc,
}
}),
)
}
pub fn declare_with<T: AsRef<str>, D: Into<Decl>>(
&mut self,
name: T,
decl: D,
definition: Vec<u8>,
) -> Result<(), Error> {
self.declare(name.as_ref(), decl)?;
self.define(name, definition)?;
Ok(())
}
pub fn declare<T: AsRef<str>, D: Into<Decl>>(
&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;
let new_idecl = {
let previous = self
.declarations
.entry(decl_name)
.or_insert(InternalDecl::new(decl.clone()));
previous_was_import = previous.decl.is_import();
previous.decl.absorb(decl)?;
previous
};
match new_idecl.decl {
Decl::Import(_) => {
let mut present = false;
for &(ref name, _) in self.imports.iter() {
if *name == decl_name {
present = true;
}
}
if !present {
let kind = ImportKind::from_decl(&new_idecl.decl)
.expect("can convert from explicitly matched decls to importkind");
self.imports.push((decl_name, kind));
}
Ok(())
}
_ if previous_was_import => {
let mut index = None;
for (i, &(ref name, _)) in self.imports.iter().enumerate() {
if *name == decl_name {
index = Some(i);
}
}
let _ = self
.imports
.swap_remove(index.expect("previous import was not in the imports array"));
Ok(())
}
_ => Ok(()),
}
}
pub fn declarations<T: AsRef<str>, D: Iterator<Item = (T, Decl)>>(
&mut self,
declarations: D,
) -> Result<(), Error> {
for (name, decl) in declarations {
self.declare(name, decl)?;
}
Ok(())
}
pub fn define<T: AsRef<str>>(&mut self, name: T, data: Vec<u8>) -> Result<(), ArtifactError> {
let decl_name = self.strings.get_or_intern(name.as_ref());
match self.declarations.get_mut(&decl_name) {
Some(ref mut stype) => {
if stype.defined {
Err(ArtifactError::DuplicateDefinition(
name.as_ref().to_string(),
))?;
}
let decl = match stype.decl {
Decl::Defined(decl) => decl,
Decl::Import(_) => {
Err(ArtifactError::ImportDefined(name.as_ref().to_string()).into())?
}
};
if decl.is_global() {
self.nonlocal_definitions.insert(InternalDefinition {
name: decl_name,
data,
decl,
});
} else {
self.local_definitions.insert(InternalDefinition {
name: decl_name,
data,
decl,
});
}
stype.define();
}
None => Err(ArtifactError::Undeclared(name.as_ref().to_string()))?,
}
Ok(())
}
pub fn import<T: AsRef<str>>(&mut self, import: T, kind: ImportKind) -> Result<(), Error> {
self.declare(import.as_ref(), Decl::Import(kind))?;
Ok(())
}
pub fn link<'a>(&mut self, link: Link<'a>) -> Result<(), Error> {
self.link_with(link, Reloc::Auto)
}
pub fn link_with<'a>(&mut self, link: Link<'a>, reloc: Reloc) -> Result<(), Error> {
let (link_from, link_to) = (
self.strings.get_or_intern(link.from),
self.strings.get_or_intern(link.to),
);
match (
self.declarations.get(&link_from),
self.declarations.get(&link_to),
) {
(Some(ref from_type), Some(_)) => {
if from_type.decl.is_import() {
return Err(ArtifactError::RelocateImport(link.from.to_string()).into());
}
let link = (link_from, link_to, link.at, reloc);
self.links.push(link);
}
(None, _) => {
return Err(ArtifactError::Undeclared(link.from.to_string()).into());
}
(_, None) => {
return Err(ArtifactError::Undeclared(link.to.to_string()).into());
}
}
Ok(())
}
pub fn undefined_symbols(&self) -> Vec<String> {
let mut syms = Vec::new();
for (&name, _) in self
.declarations
.iter()
.filter(|&(_, &int)| !int.defined && !int.decl.is_import())
{
syms.push(String::from(
self.strings.resolve(name).expect("declaration has a name"),
));
}
syms
}
pub fn emit(&self) -> Result<Vec<u8>, Error> {
self.emit_as(self.target.binary_format)
}
pub fn emit_as(&self, format: BinaryFormat) -> Result<Vec<u8>, Error> {
let undef = self.undefined_symbols();
if undef.is_empty() {
match format {
BinaryFormat::Elf => elf::to_bytes(self),
BinaryFormat::Macho => mach::to_bytes(self),
_ => Err(format_err!(
"binary format {} is not supported",
self.target.binary_format
)),
}
} else {
Err(format_err!(
"the following symbols are declared but not defined: {:?}",
undef
))
}
}
pub fn write(&self, sink: File) -> Result<(), Error> {
self.write_as(sink, self.target.binary_format)
}
pub fn write_as(&self, mut sink: File, format: BinaryFormat) -> Result<(), Error> {
let bytes = self.emit_as(format)?;
sink.write_all(&bytes)?;
Ok(())
}
}