2019-10-16 19:21:20 +00:00
|
|
|
use std::collections::HashMap;
|
2019-10-19 13:37:07 +00:00
|
|
|
use std::convert::TryFrom;
|
2019-10-16 19:21:20 +00:00
|
|
|
|
2019-10-18 15:19:13 +00:00
|
|
|
use rustc::session::Session;
|
|
|
|
|
|
|
|
use cranelift_module::{FuncId, Module};
|
2019-10-16 19:21:20 +00:00
|
|
|
|
|
|
|
use faerie::*;
|
2019-10-19 08:56:35 +00:00
|
|
|
#[cfg(feature = "backend_object")]
|
2019-10-16 19:21:20 +00:00
|
|
|
use object::{SectionKind, RelocationKind, RelocationEncoding};
|
2019-10-19 08:56:35 +00:00
|
|
|
#[cfg(feature = "backend_object")]
|
2019-10-16 19:21:20 +00:00
|
|
|
use object::write::*;
|
2019-10-18 15:19:13 +00:00
|
|
|
use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieProduct, FaerieTrapCollection};
|
2019-10-19 08:56:35 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "backend_object")]
|
2019-10-16 19:21:20 +00:00
|
|
|
use cranelift_object::*;
|
|
|
|
|
|
|
|
use gimli::SectionId;
|
|
|
|
|
|
|
|
use crate::debuginfo::{DebugReloc, DebugRelocName};
|
|
|
|
|
|
|
|
pub trait WriteMetadata {
|
2019-10-16 18:48:09 +00:00
|
|
|
fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
|
|
|
|
}
|
|
|
|
|
2019-10-16 19:21:20 +00:00
|
|
|
impl WriteMetadata for faerie::Artifact {
|
2019-10-16 18:48:09 +00:00
|
|
|
fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool) {
|
|
|
|
self
|
|
|
|
.declare(".rustc", faerie::Decl::section(faerie::SectionKind::Data))
|
|
|
|
.unwrap();
|
|
|
|
self
|
|
|
|
.define_with_symbols(".rustc", data, {
|
|
|
|
let mut map = std::collections::BTreeMap::new();
|
|
|
|
// FIXME implement faerie elf backend section custom symbols
|
|
|
|
// For MachO this is necessary to prevent the linker from throwing away the .rustc section,
|
|
|
|
// but for ELF it isn't.
|
|
|
|
if is_like_osx {
|
|
|
|
map.insert(
|
|
|
|
symbol_name,
|
|
|
|
0,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
map
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-19 08:56:35 +00:00
|
|
|
#[cfg(feature = "backend_object")]
|
2019-10-16 19:21:20 +00:00
|
|
|
impl WriteMetadata for object::write::Object {
|
2019-10-19 08:52:56 +00:00
|
|
|
fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
|
2019-10-16 18:48:09 +00:00
|
|
|
let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
|
|
|
|
let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
|
|
|
|
let offset = self.append_section_data(section_id, &data, 1);
|
2019-10-19 08:52:56 +00:00
|
|
|
// For MachO and probably PE this is necessary to prevent the linker from throwing away the
|
|
|
|
// .rustc section. For ELF this isn't necessary, but it also doesn't harm.
|
|
|
|
self.add_symbol(object::write::Symbol {
|
|
|
|
name: symbol_name.into_bytes(),
|
|
|
|
value: offset,
|
|
|
|
size: data.len() as u64,
|
|
|
|
kind: object::SymbolKind::Data,
|
2019-10-19 09:08:16 +00:00
|
|
|
scope: object::SymbolScope::Dynamic,
|
2019-10-19 08:52:56 +00:00
|
|
|
weak: false,
|
|
|
|
section: Some(section_id),
|
|
|
|
});
|
2019-10-16 18:48:09 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-16 19:21:20 +00:00
|
|
|
|
|
|
|
pub trait WriteDebugInfo {
|
|
|
|
type SectionId;
|
|
|
|
|
|
|
|
fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
|
|
|
|
fn add_debug_reloc(
|
|
|
|
&mut self,
|
|
|
|
section_map: &HashMap<SectionId, Self::SectionId>,
|
2019-10-19 08:52:56 +00:00
|
|
|
symbol_map: &indexmap::IndexMap<FuncId, String>,
|
2019-10-16 19:21:20 +00:00
|
|
|
from: &Self::SectionId,
|
|
|
|
reloc: &DebugReloc,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-10-18 15:19:13 +00:00
|
|
|
impl WriteDebugInfo for FaerieProduct {
|
2019-10-16 19:21:20 +00:00
|
|
|
type SectionId = SectionId;
|
|
|
|
|
|
|
|
fn add_debug_section(&mut self, id: SectionId, data: Vec<u8>) -> SectionId {
|
2019-10-18 15:19:13 +00:00
|
|
|
self.artifact.declare_with(id.name(), Decl::section(faerie::SectionKind::Debug), data).unwrap();
|
2019-10-16 19:21:20 +00:00
|
|
|
id
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_debug_reloc(
|
|
|
|
&mut self,
|
|
|
|
_section_map: &HashMap<SectionId, Self::SectionId>,
|
2019-10-19 08:52:56 +00:00
|
|
|
symbol_map: &indexmap::IndexMap<FuncId, String>,
|
2019-10-16 19:21:20 +00:00
|
|
|
from: &Self::SectionId,
|
|
|
|
reloc: &DebugReloc,
|
|
|
|
) {
|
|
|
|
self
|
2019-10-18 15:19:13 +00:00
|
|
|
.artifact
|
2019-10-16 19:21:20 +00:00
|
|
|
.link_with(
|
|
|
|
faerie::Link {
|
|
|
|
from: from.name(),
|
|
|
|
to: match reloc.name {
|
|
|
|
DebugRelocName::Section(id) => id.name(),
|
2019-10-19 08:52:56 +00:00
|
|
|
DebugRelocName::Symbol(index) => &symbol_map.get_index(index).unwrap().1,
|
2019-10-16 19:21:20 +00:00
|
|
|
},
|
|
|
|
at: u64::from(reloc.offset),
|
|
|
|
},
|
|
|
|
faerie::Reloc::Debug {
|
|
|
|
size: reloc.size,
|
|
|
|
addend: reloc.addend as i32,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.expect("faerie relocation error");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-19 08:56:35 +00:00
|
|
|
#[cfg(feature = "backend_object")]
|
2019-10-16 19:21:20 +00:00
|
|
|
impl WriteDebugInfo for ObjectProduct {
|
|
|
|
type SectionId = (object::write::SectionId, object::write::SymbolId);
|
|
|
|
|
|
|
|
fn add_debug_section(
|
|
|
|
&mut self,
|
|
|
|
id: SectionId,
|
|
|
|
data: Vec<u8>,
|
|
|
|
) -> (object::write::SectionId, object::write::SymbolId) {
|
2019-10-19 13:37:07 +00:00
|
|
|
let name = if self.object.format() == target_lexicon::BinaryFormat::Macho {
|
|
|
|
id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
|
|
|
|
} else {
|
|
|
|
id.name().to_string()
|
|
|
|
}.into_bytes();
|
|
|
|
|
2019-10-16 19:21:20 +00:00
|
|
|
let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
|
|
|
|
let section_id = self.object.add_section(segment, name, SectionKind::Debug);
|
|
|
|
self.object.section_mut(section_id).set_data(data, 1);
|
|
|
|
let symbol_id = self.object.section_symbol(section_id);
|
|
|
|
(section_id, symbol_id)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_debug_reloc(
|
|
|
|
&mut self,
|
|
|
|
section_map: &HashMap<SectionId, Self::SectionId>,
|
2019-10-19 08:52:56 +00:00
|
|
|
symbol_map: &indexmap::IndexMap<FuncId, String>,
|
2019-10-16 19:21:20 +00:00
|
|
|
from: &Self::SectionId,
|
|
|
|
reloc: &DebugReloc,
|
|
|
|
) {
|
2019-10-19 13:37:07 +00:00
|
|
|
let (symbol, symbol_offset) = match reloc.name {
|
|
|
|
DebugRelocName::Section(id) => {
|
|
|
|
(section_map.get(&id).unwrap().1, 0)
|
|
|
|
}
|
2019-10-16 19:21:20 +00:00
|
|
|
DebugRelocName::Symbol(id) => {
|
2019-10-19 13:37:07 +00:00
|
|
|
let symbol_id = self.function_symbol(*symbol_map.get_index(id).unwrap().0);
|
|
|
|
let symbol = self.object.symbol(symbol_id);
|
|
|
|
|
|
|
|
// A symbol gets a section assigned when `add_symbol_data` is called.
|
|
|
|
let section = symbol.section.expect("Symbol not defined");
|
|
|
|
let symbol_offset = symbol.value;
|
|
|
|
|
|
|
|
(self.object.section_symbol(section), symbol_offset)
|
2019-10-16 19:21:20 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
self.object.add_relocation(from.0, Relocation {
|
|
|
|
offset: u64::from(reloc.offset),
|
|
|
|
symbol,
|
|
|
|
kind: RelocationKind::Absolute,
|
|
|
|
encoding: RelocationEncoding::Generic,
|
|
|
|
size: reloc.size * 8,
|
2019-10-19 13:37:07 +00:00
|
|
|
addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
|
2019-10-16 19:21:20 +00:00
|
|
|
}).unwrap();
|
|
|
|
}
|
|
|
|
}
|
2019-10-18 15:19:13 +00:00
|
|
|
|
|
|
|
pub trait Emit {
|
|
|
|
fn emit(self) -> Vec<u8>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Emit for FaerieProduct {
|
|
|
|
fn emit(self) -> Vec<u8> {
|
|
|
|
self.artifact.emit().unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-19 08:56:35 +00:00
|
|
|
#[cfg(feature = "backend_object")]
|
2019-10-18 15:19:13 +00:00
|
|
|
impl Emit for ObjectProduct {
|
|
|
|
fn emit(self) -> Vec<u8> {
|
|
|
|
self.object.write().unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "backend_object"))]
|
|
|
|
pub fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Artifact)) -> Vec<u8> {
|
|
|
|
let mut metadata_artifact = faerie::Artifact::new(
|
|
|
|
crate::build_isa(sess, true).triple().clone(),
|
|
|
|
name.to_string(),
|
|
|
|
);
|
|
|
|
f(&mut metadata_artifact);
|
|
|
|
metadata_artifact.emit().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "backend_object")]
|
|
|
|
pub fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
|
|
|
|
let triple = crate::build_isa(sess, true).triple().clone();
|
|
|
|
let mut metadata_object =
|
|
|
|
object::write::Object::new(triple.binary_format, triple.architecture);
|
|
|
|
metadata_object.add_file_symbol(name.as_bytes().to_vec());
|
|
|
|
f(&mut metadata_object);
|
|
|
|
metadata_object.write().unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type Backend = impl cranelift_module::Backend<Product: Emit + WriteDebugInfo>;
|
|
|
|
|
|
|
|
#[cfg(not(feature = "backend_object"))]
|
|
|
|
pub fn make_module(sess: &Session, name: String) -> Module<Backend> {
|
|
|
|
let module: Module<FaerieBackend> = Module::new(
|
|
|
|
FaerieBuilder::new(
|
|
|
|
crate::build_isa(sess, true),
|
|
|
|
name + ".o",
|
|
|
|
FaerieTrapCollection::Disabled,
|
|
|
|
cranelift_module::default_libcall_names(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
module
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "backend_object")]
|
|
|
|
pub fn make_module(sess: &Session, name: String) -> Module<Backend> {
|
|
|
|
let module: Module<ObjectBackend> = Module::new(
|
|
|
|
ObjectBuilder::new(
|
|
|
|
crate::build_isa(sess, true),
|
|
|
|
name + ".o",
|
|
|
|
ObjectTrapCollection::Disabled,
|
|
|
|
cranelift_module::default_libcall_names(),
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
module
|
|
|
|
}
|