]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/backend.rs
Sync rustc_codegen_cranelift 'ddd4ce25535cf71203ba3700896131ce55fde795'
[rust.git] / compiler / rustc_codegen_cranelift / src / backend.rs
1 //! Abstraction around the object writing crate
2
3 use std::convert::{TryFrom, TryInto};
4
5 use rustc_data_structures::fx::FxHashMap;
6 use rustc_session::Session;
7
8 use cranelift_codegen::isa::TargetIsa;
9 use cranelift_module::FuncId;
10 use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
11
12 use object::write::*;
13 use object::{RelocationEncoding, SectionKind, SymbolFlags};
14
15 use gimli::SectionId;
16
17 use crate::debuginfo::{DebugReloc, DebugRelocName};
18
19 pub(crate) trait WriteMetadata {
20     fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>);
21 }
22
23 impl WriteMetadata for object::write::Object {
24     fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>) {
25         let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
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(),
32             value: offset,
33             size: data.len() as u64,
34             kind: object::SymbolKind::Data,
35             scope: object::SymbolScope::Dynamic,
36             weak: false,
37             section: SymbolSection::Section(section_id),
38             flags: SymbolFlags::None,
39         });
40     }
41 }
42
43 pub(crate) trait WriteDebugInfo {
44     type SectionId: Copy;
45
46     fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
47     fn add_debug_reloc(
48         &mut self,
49         section_map: &FxHashMap<SectionId, Self::SectionId>,
50         from: &Self::SectionId,
51         reloc: &DebugReloc,
52     );
53 }
54
55 impl WriteDebugInfo for ObjectProduct {
56     type SectionId = (object::write::SectionId, object::write::SymbolId);
57
58     fn add_debug_section(
59         &mut self,
60         id: SectionId,
61         data: Vec<u8>,
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
65         } else {
66             id.name().to_string()
67         }
68         .into_bytes();
69
70         let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
71         // FIXME use SHT_X86_64_UNWIND for .eh_frame
72         let section_id = self.object.add_section(
73             segment,
74             name,
75             if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug },
76         );
77         self.object
78             .section_mut(section_id)
79             .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 });
80         let symbol_id = self.object.section_symbol(section_id);
81         (section_id, symbol_id)
82     }
83
84     fn add_debug_reloc(
85         &mut self,
86         section_map: &FxHashMap<SectionId, Self::SectionId>,
87         from: &Self::SectionId,
88         reloc: &DebugReloc,
89     ) {
90         let (symbol, symbol_offset) = match reloc.name {
91             DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
92             DebugRelocName::Symbol(id) => {
93                 let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
94                 self.object
95                     .symbol_section_and_offset(symbol_id)
96                     .expect("Debug reloc for undef sym???")
97             }
98         };
99         self.object
100             .add_relocation(
101                 from.0,
102                 Relocation {
103                     offset: u64::from(reloc.offset),
104                     symbol,
105                     kind: reloc.kind,
106                     encoding: RelocationEncoding::Generic,
107                     size: reloc.size * 8,
108                     addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
109                 },
110             )
111             .unwrap();
112     }
113 }
114
115 pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
116     let triple = crate::target_triple(sess);
117
118     let binary_format = match triple.binary_format {
119         target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
120         target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
121         target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
122         binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)),
123     };
124     let architecture = match triple.architecture {
125         target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
126         target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
127         target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
128         target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
129         architecture => {
130             sess.fatal(&format!("target architecture {:?} is unsupported", architecture,))
131         }
132     };
133     let endian = match triple.endianness().unwrap() {
134         target_lexicon::Endianness::Little => object::Endianness::Little,
135         target_lexicon::Endianness::Big => object::Endianness::Big,
136     };
137
138     let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
139     metadata_object.add_file_symbol(name.as_bytes().to_vec());
140     f(&mut metadata_object);
141     metadata_object.write().unwrap()
142 }
143
144 pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
145     let mut builder =
146         ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
147     // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
148     // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
149     // can easily double the amount of time necessary to perform linking.
150     builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
151     ObjectModule::new(builder)
152 }