1 use std::convert::{TryFrom, TryInto};
3 use rustc_data_structures::fx::FxHashMap;
4 use rustc_session::Session;
6 use cranelift_module::{FuncId, Module};
9 use object::{RelocationEncoding, RelocationKind, SectionKind, SymbolFlags};
11 use cranelift_object::{ObjectBackend, ObjectBuilder, ObjectProduct};
15 use crate::debuginfo::{DebugReloc, DebugRelocName};
17 pub(crate) trait WriteMetadata {
18 fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
21 impl WriteMetadata for object::write::Object {
22 fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
24 .segment_name(object::write::StandardSegment::Data)
26 let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
27 let offset = self.append_section_data(section_id, &data, 1);
28 // For MachO and probably PE this is necessary to prevent the linker from throwing away the
29 // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
30 self.add_symbol(object::write::Symbol {
31 name: symbol_name.into_bytes(),
33 size: data.len() as u64,
34 kind: object::SymbolKind::Data,
35 scope: object::SymbolScope::Dynamic,
37 section: SymbolSection::Section(section_id),
38 flags: SymbolFlags::None,
43 pub(crate) trait WriteDebugInfo {
46 fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
49 section_map: &FxHashMap<SectionId, Self::SectionId>,
50 from: &Self::SectionId,
55 impl WriteDebugInfo for ObjectProduct {
56 type SectionId = (object::write::SectionId, object::write::SymbolId);
62 ) -> (object::write::SectionId, object::write::SymbolId) {
63 let name = if self.object.format() == object::BinaryFormat::MachO {
64 id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
70 let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
71 let section_id = self.object.add_section(segment, name, SectionKind::Debug);
72 self.object.section_mut(section_id).set_data(data, 1);
73 let symbol_id = self.object.section_symbol(section_id);
74 (section_id, symbol_id)
79 section_map: &FxHashMap<SectionId, Self::SectionId>,
80 from: &Self::SectionId,
83 let (symbol, symbol_offset) = match reloc.name {
84 DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
85 DebugRelocName::Symbol(id) => {
86 let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
88 .symbol_section_and_offset(symbol_id)
89 .expect("Debug reloc for undef sym???")
96 offset: u64::from(reloc.offset),
98 kind: RelocationKind::Absolute,
99 encoding: RelocationEncoding::Generic,
100 size: reloc.size * 8,
101 addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
108 // FIXME remove once atomic instructions are implemented in Cranelift.
109 pub(crate) trait AddConstructor {
110 fn add_constructor(&mut self, func_id: FuncId);
113 impl AddConstructor for ObjectProduct {
114 fn add_constructor(&mut self, func_id: FuncId) {
115 let symbol = self.function_symbol(func_id);
118 .segment_name(object::write::StandardSegment::Data);
119 let init_array_section =
121 .add_section(segment.to_vec(), b".init_array".to_vec(), SectionKind::Data);
122 self.object.append_section_data(
124 &std::iter::repeat(0)
125 .take(8 /*FIXME pointer size*/)
126 .collect::<Vec<u8>>(),
132 object::write::Relocation {
134 size: 64, // FIXME pointer size
135 kind: RelocationKind::Absolute,
136 encoding: RelocationEncoding::Generic,
145 pub(crate) trait Emit {
146 fn emit(self) -> Vec<u8>;
149 impl Emit for ObjectProduct {
150 fn emit(self) -> Vec<u8> {
151 self.object.write().unwrap()
155 pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
156 let triple = crate::build_isa(sess, true).triple().clone();
158 let binary_format = match triple.binary_format {
159 target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
160 target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
161 target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
162 binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)),
164 let architecture = match triple.architecture {
165 target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
166 target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
167 target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
168 target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
169 architecture => sess.fatal(&format!(
170 "target architecture {:?} is unsupported",
174 let endian = match triple.endianness().unwrap() {
175 target_lexicon::Endianness::Little => object::Endianness::Little,
176 target_lexicon::Endianness::Big => object::Endianness::Big,
179 let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
180 metadata_object.add_file_symbol(name.as_bytes().to_vec());
181 f(&mut metadata_object);
182 metadata_object.write().unwrap()
185 pub(crate) type Backend =
186 impl cranelift_module::Backend<Product: AddConstructor + Emit + WriteDebugInfo>;
188 pub(crate) fn make_module(sess: &Session, name: String) -> Module<Backend> {
189 let module: Module<ObjectBackend> = Module::new(
191 crate::build_isa(sess, true),
193 cranelift_module::default_libcall_names(),