]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/backend.rs
Auto merge of #80400 - adlerd:hashclone, r=Mark-Simulacrum
[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_module::FuncId;
9
10 use object::write::*;
11 use object::{RelocationEncoding, RelocationKind, SectionKind, SymbolFlags};
12
13 use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
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>, is_like_osx: bool);
21 }
22
23 impl WriteMetadata for object::write::Object {
24     fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
25         let segment = self
26             .segment_name(object::write::StandardSegment::Data)
27             .to_vec();
28         let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
29         let offset = self.append_section_data(section_id, &data, 1);
30         // For MachO and probably PE this is necessary to prevent the linker from throwing away the
31         // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
32         self.add_symbol(object::write::Symbol {
33             name: symbol_name.into_bytes(),
34             value: offset,
35             size: data.len() as u64,
36             kind: object::SymbolKind::Data,
37             scope: object::SymbolScope::Dynamic,
38             weak: false,
39             section: SymbolSection::Section(section_id),
40             flags: SymbolFlags::None,
41         });
42     }
43 }
44
45 pub(crate) trait WriteDebugInfo {
46     type SectionId: Copy;
47
48     fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
49     fn add_debug_reloc(
50         &mut self,
51         section_map: &FxHashMap<SectionId, Self::SectionId>,
52         from: &Self::SectionId,
53         reloc: &DebugReloc,
54     );
55 }
56
57 impl WriteDebugInfo for ObjectProduct {
58     type SectionId = (object::write::SectionId, object::write::SymbolId);
59
60     fn add_debug_section(
61         &mut self,
62         id: SectionId,
63         data: Vec<u8>,
64     ) -> (object::write::SectionId, object::write::SymbolId) {
65         let name = if self.object.format() == object::BinaryFormat::MachO {
66             id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
67         } else {
68             id.name().to_string()
69         }
70         .into_bytes();
71
72         let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
73         // FIXME use SHT_X86_64_UNWIND for .eh_frame
74         let section_id = self.object.add_section(
75             segment,
76             name,
77             if id == SectionId::EhFrame {
78                 SectionKind::ReadOnlyData
79             } else {
80                 SectionKind::Debug
81             },
82         );
83         self.object
84             .section_mut(section_id)
85             .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 });
86         let symbol_id = self.object.section_symbol(section_id);
87         (section_id, symbol_id)
88     }
89
90     fn add_debug_reloc(
91         &mut self,
92         section_map: &FxHashMap<SectionId, Self::SectionId>,
93         from: &Self::SectionId,
94         reloc: &DebugReloc,
95     ) {
96         let (symbol, symbol_offset) = match reloc.name {
97             DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
98             DebugRelocName::Symbol(id) => {
99                 let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
100                 self.object
101                     .symbol_section_and_offset(symbol_id)
102                     .expect("Debug reloc for undef sym???")
103             }
104         };
105         self.object
106             .add_relocation(
107                 from.0,
108                 Relocation {
109                     offset: u64::from(reloc.offset),
110                     symbol,
111                     kind: reloc.kind,
112                     encoding: RelocationEncoding::Generic,
113                     size: reloc.size * 8,
114                     addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
115                 },
116             )
117             .unwrap();
118     }
119 }
120
121 // FIXME remove once atomic instructions are implemented in Cranelift.
122 pub(crate) trait AddConstructor {
123     fn add_constructor(&mut self, func_id: FuncId);
124 }
125
126 impl AddConstructor for ObjectProduct {
127     fn add_constructor(&mut self, func_id: FuncId) {
128         let symbol = self.function_symbol(func_id);
129         let segment = self
130             .object
131             .segment_name(object::write::StandardSegment::Data);
132         let init_array_section =
133             self.object
134                 .add_section(segment.to_vec(), b".init_array".to_vec(), SectionKind::Data);
135         let address_size = self
136             .object
137             .architecture()
138             .address_size()
139             .expect("address_size must be known")
140             .bytes();
141         self.object.append_section_data(
142             init_array_section,
143             &std::iter::repeat(0)
144                 .take(address_size.into())
145                 .collect::<Vec<u8>>(),
146             8,
147         );
148         self.object
149             .add_relocation(
150                 init_array_section,
151                 object::write::Relocation {
152                     offset: 0,
153                     size: address_size * 8,
154                     kind: RelocationKind::Absolute,
155                     encoding: RelocationEncoding::Generic,
156                     symbol,
157                     addend: 0,
158                 },
159             )
160             .unwrap();
161     }
162 }
163
164 pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
165     let triple = crate::build_isa(sess, true).triple().clone();
166
167     let binary_format = match triple.binary_format {
168         target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
169         target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
170         target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
171         binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)),
172     };
173     let architecture = match triple.architecture {
174         target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
175         target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
176         target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
177         target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
178         architecture => sess.fatal(&format!(
179             "target architecture {:?} is unsupported",
180             architecture,
181         )),
182     };
183     let endian = match triple.endianness().unwrap() {
184         target_lexicon::Endianness::Little => object::Endianness::Little,
185         target_lexicon::Endianness::Big => object::Endianness::Big,
186     };
187
188     let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
189     metadata_object.add_file_symbol(name.as_bytes().to_vec());
190     f(&mut metadata_object);
191     metadata_object.write().unwrap()
192 }
193
194 pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
195     let mut builder = ObjectBuilder::new(
196         crate::build_isa(sess, true),
197         name + ".o",
198         cranelift_module::default_libcall_names(),
199     )
200     .unwrap();
201     // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
202     // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
203     // can easily double the amount of time necessary to perform linking.
204     builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
205     ObjectModule::new(builder)
206 }