-use std::collections::HashMap;
-use std::convert::TryFrom;
+//! Abstraction around the object writing crate
-use rustc::session::Session;
+use std::convert::{TryFrom, TryInto};
-use cranelift_module::{FuncId, Module};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_session::Session;
-use faerie::*;
-#[cfg(feature = "backend_object")]
-use object::{SectionKind, SymbolFlags, RelocationKind, RelocationEncoding};
-#[cfg(feature = "backend_object")]
-use object::write::*;
-use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieProduct, FaerieTrapCollection};
+use cranelift_codegen::isa::TargetIsa;
+use cranelift_module::FuncId;
+use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
-#[cfg(feature = "backend_object")]
-use cranelift_object::*;
+use object::write::*;
+use object::{RelocationEncoding, SectionKind, SymbolFlags};
use gimli::SectionId;
use crate::debuginfo::{DebugReloc, DebugRelocName};
-pub trait WriteMetadata {
- fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
-}
-
-impl WriteMetadata for faerie::Artifact {
- 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();
- }
+pub(crate) trait WriteMetadata {
+ fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>);
}
-#[cfg(feature = "backend_object")]
impl WriteMetadata for object::write::Object {
- fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
+ fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>) {
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);
}
}
-pub trait WriteDebugInfo {
- type SectionId;
+pub(crate) trait WriteDebugInfo {
+ type SectionId: Copy;
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>,
- symbol_map: &indexmap::IndexMap<FuncId, String>,
+ section_map: &FxHashMap<SectionId, Self::SectionId>,
from: &Self::SectionId,
reloc: &DebugReloc,
);
}
-impl WriteDebugInfo for FaerieProduct {
- type SectionId = SectionId;
-
- fn add_debug_section(&mut self, id: SectionId, data: Vec<u8>) -> SectionId {
- self.artifact.declare_with(id.name(), Decl::section(faerie::SectionKind::Debug), data).unwrap();
- id
- }
-
- fn add_debug_reloc(
- &mut self,
- _section_map: &HashMap<SectionId, Self::SectionId>,
- symbol_map: &indexmap::IndexMap<FuncId, String>,
- from: &Self::SectionId,
- reloc: &DebugReloc,
- ) {
- self
- .artifact
- .link_with(
- faerie::Link {
- from: from.name(),
- to: match reloc.name {
- DebugRelocName::Section(id) => id.name(),
- DebugRelocName::Symbol(index) => &symbol_map.get_index(index).unwrap().1,
- },
- at: u64::from(reloc.offset),
- },
- faerie::Reloc::Debug {
- size: reloc.size,
- addend: reloc.addend as i32,
- },
- )
- .expect("faerie relocation error");
- }
-}
-
-#[cfg(feature = "backend_object")]
impl WriteDebugInfo for ObjectProduct {
type SectionId = (object::write::SectionId, object::write::SymbolId);
id: SectionId,
data: Vec<u8>,
) -> (object::write::SectionId, object::write::SymbolId) {
- let name = if self.object.format() == target_lexicon::BinaryFormat::Macho {
+ let name = if self.object.format() == object::BinaryFormat::MachO {
id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
} else {
id.name().to_string()
- }.into_bytes();
+ }
+ .into_bytes();
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);
+ // FIXME use SHT_X86_64_UNWIND for .eh_frame
+ let section_id = self.object.add_section(
+ segment,
+ name,
+ if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug },
+ );
+ self.object
+ .section_mut(section_id)
+ .set_data(data, if id == SectionId::EhFrame { 8 } else { 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>,
- symbol_map: &indexmap::IndexMap<FuncId, String>,
+ section_map: &FxHashMap<SectionId, Self::SectionId>,
from: &Self::SectionId,
reloc: &DebugReloc,
) {
let (symbol, symbol_offset) = match reloc.name {
- DebugRelocName::Section(id) => {
- (section_map.get(&id).unwrap().1, 0)
- }
+ DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
DebugRelocName::Symbol(id) => {
- let symbol_id = self.function_symbol(*symbol_map.get_index(id).unwrap().0);
- self.object.symbol_section_and_offset(symbol_id).expect("Debug reloc for undef sym???")
+ let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
+ self.object
+ .symbol_section_and_offset(symbol_id)
+ .expect("Debug reloc for undef sym???")
}
};
- self.object.add_relocation(from.0, Relocation {
- offset: u64::from(reloc.offset),
- symbol,
- kind: RelocationKind::Absolute,
- encoding: RelocationEncoding::Generic,
- size: reloc.size * 8,
- addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
- }).unwrap();
- }
-}
-
-pub trait Emit {
- fn emit(self) -> Vec<u8>;
-}
-
-impl Emit for FaerieProduct {
- fn emit(self) -> Vec<u8> {
- self.artifact.emit().unwrap()
- }
-}
-
-#[cfg(feature = "backend_object")]
-impl Emit for ObjectProduct {
- fn emit(self) -> Vec<u8> {
- self.object.write().unwrap()
+ self.object
+ .add_relocation(
+ from.0,
+ Relocation {
+ offset: u64::from(reloc.offset),
+ symbol,
+ kind: reloc.kind,
+ encoding: RelocationEncoding::Generic,
+ size: reloc.size * 8,
+ addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
+ },
+ )
+ .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);
+pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
+ let triple = crate::target_triple(sess);
+
+ let binary_format = match triple.binary_format {
+ target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
+ target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
+ target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
+ binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)),
+ };
+ let architecture = match triple.architecture {
+ target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
+ target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
+ target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
+ target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
+ architecture => {
+ sess.fatal(&format!("target architecture {:?} is unsupported", architecture,))
+ }
+ };
+ let endian = match triple.endianness().unwrap() {
+ target_lexicon::Endianness::Little => object::Endianness::Little,
+ target_lexicon::Endianness::Big => object::Endianness::Big,
+ };
+
+ let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
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
+pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
+ let mut builder =
+ ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
+ // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
+ // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
+ // can easily double the amount of time necessary to perform linking.
+ builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
+ ObjectModule::new(builder)
}