]> git.lizzy.rs Git - rust.git/blob - src/backend.rs
Fix metadata symbol scope
[rust.git] / src / backend.rs
1 use std::collections::HashMap;
2
3 use rustc::session::Session;
4
5 use cranelift_module::{FuncId, Module};
6
7 use faerie::*;
8 #[cfg(feature = "backend_object")]
9 use object::{SectionKind, RelocationKind, RelocationEncoding};
10 #[cfg(feature = "backend_object")]
11 use object::write::*;
12 use cranelift_faerie::{FaerieBackend, FaerieBuilder, FaerieProduct, FaerieTrapCollection};
13
14 #[cfg(feature = "backend_object")]
15 use cranelift_object::*;
16
17 use gimli::SectionId;
18
19 use crate::debuginfo::{DebugReloc, DebugRelocName};
20
21 pub trait WriteMetadata {
22     fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
23 }
24
25 impl WriteMetadata for faerie::Artifact {
26     fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool) {
27         self
28             .declare(".rustc", faerie::Decl::section(faerie::SectionKind::Data))
29             .unwrap();
30         self
31             .define_with_symbols(".rustc", data, {
32                 let mut map = std::collections::BTreeMap::new();
33                 // FIXME implement faerie elf backend section custom symbols
34                 // For MachO this is necessary to prevent the linker from throwing away the .rustc section,
35                 // but for ELF it isn't.
36                 if is_like_osx {
37                     map.insert(
38                         symbol_name,
39                         0,
40                     );
41                 }
42                 map
43             })
44             .unwrap();
45     }
46 }
47
48 #[cfg(feature = "backend_object")]
49 impl WriteMetadata for object::write::Object {
50     fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
51         let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
52         let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
53         let offset = self.append_section_data(section_id, &data, 1);
54         // For MachO and probably PE this is necessary to prevent the linker from throwing away the
55         // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
56         self.add_symbol(object::write::Symbol {
57             name: symbol_name.into_bytes(),
58             value: offset,
59             size: data.len() as u64,
60             kind: object::SymbolKind::Data,
61             scope: object::SymbolScope::Dynamic,
62             weak: false,
63             section: Some(section_id),
64         });
65     }
66 }
67
68 pub trait WriteDebugInfo {
69     type SectionId;
70
71     fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
72     fn add_debug_reloc(
73         &mut self,
74         section_map: &HashMap<SectionId, Self::SectionId>,
75         symbol_map: &indexmap::IndexMap<FuncId, String>,
76         from: &Self::SectionId,
77         reloc: &DebugReloc,
78     );
79 }
80
81 impl WriteDebugInfo for FaerieProduct {
82     type SectionId = SectionId;
83
84     fn add_debug_section(&mut self, id: SectionId, data: Vec<u8>) -> SectionId {
85         self.artifact.declare_with(id.name(), Decl::section(faerie::SectionKind::Debug), data).unwrap();
86         id
87     }
88
89     fn add_debug_reloc(
90         &mut self,
91         _section_map: &HashMap<SectionId, Self::SectionId>,
92         symbol_map: &indexmap::IndexMap<FuncId, String>,
93         from: &Self::SectionId,
94         reloc: &DebugReloc,
95     ) {
96         self
97             .artifact
98             .link_with(
99                 faerie::Link {
100                     from: from.name(),
101                     to: match reloc.name {
102                         DebugRelocName::Section(id) => id.name(),
103                         DebugRelocName::Symbol(index) => &symbol_map.get_index(index).unwrap().1,
104                     },
105                     at: u64::from(reloc.offset),
106                 },
107                 faerie::Reloc::Debug {
108                     size: reloc.size,
109                     addend: reloc.addend as i32,
110                 },
111             )
112             .expect("faerie relocation error");
113     }
114 }
115
116 #[cfg(feature = "backend_object")]
117 impl WriteDebugInfo for ObjectProduct {
118     type SectionId = (object::write::SectionId, object::write::SymbolId);
119
120     fn add_debug_section(
121         &mut self,
122         id: SectionId,
123         data: Vec<u8>,
124     ) -> (object::write::SectionId, object::write::SymbolId) {
125         let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
126         let name = id.name().as_bytes().to_vec();
127         let section_id = self.object.add_section(segment, name, SectionKind::Debug);
128         self.object.section_mut(section_id).set_data(data, 1);
129         let symbol_id = self.object.section_symbol(section_id);
130         (section_id, symbol_id)
131     }
132
133     fn add_debug_reloc(
134         &mut self,
135         section_map: &HashMap<SectionId, Self::SectionId>,
136         symbol_map: &indexmap::IndexMap<FuncId, String>,
137         from: &Self::SectionId,
138         reloc: &DebugReloc,
139     ) {
140         let symbol = match reloc.name {
141             DebugRelocName::Section(id) => section_map.get(&id).unwrap().1,
142             DebugRelocName::Symbol(id) => {
143                 self.function_symbol(*symbol_map.get_index(id).unwrap().0)
144             }
145         };
146         self.object.add_relocation(from.0, Relocation {
147             offset: u64::from(reloc.offset),
148             symbol,
149             kind: RelocationKind::Absolute,
150             encoding: RelocationEncoding::Generic,
151             size: reloc.size * 8,
152             addend: reloc.addend,
153         }).unwrap();
154     }
155 }
156
157 pub trait Emit {
158     fn emit(self) -> Vec<u8>;
159 }
160
161 impl Emit for FaerieProduct {
162     fn emit(self) -> Vec<u8> {
163         self.artifact.emit().unwrap()
164     }
165 }
166
167 #[cfg(feature = "backend_object")]
168 impl Emit for ObjectProduct {
169     fn emit(self) -> Vec<u8> {
170         self.object.write().unwrap()
171     }
172 }
173
174 #[cfg(not(feature = "backend_object"))]
175 pub fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Artifact)) -> Vec<u8> {
176     let mut metadata_artifact = faerie::Artifact::new(
177         crate::build_isa(sess, true).triple().clone(),
178         name.to_string(),
179     );
180     f(&mut metadata_artifact);
181     metadata_artifact.emit().unwrap()
182 }
183
184 #[cfg(feature = "backend_object")]
185 pub fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
186     let triple = crate::build_isa(sess, true).triple().clone();
187     let mut metadata_object =
188         object::write::Object::new(triple.binary_format, triple.architecture);
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 type Backend = impl cranelift_module::Backend<Product: Emit + WriteDebugInfo>;
195
196 #[cfg(not(feature = "backend_object"))]
197 pub fn make_module(sess: &Session, name: String) -> Module<Backend> {
198     let module: Module<FaerieBackend> = Module::new(
199         FaerieBuilder::new(
200             crate::build_isa(sess, true),
201             name + ".o",
202             FaerieTrapCollection::Disabled,
203             cranelift_module::default_libcall_names(),
204         )
205         .unwrap(),
206     );
207     module
208 }
209
210 #[cfg(feature = "backend_object")]
211 pub fn make_module(sess: &Session, name: String) -> Module<Backend> {
212     let module: Module<ObjectBackend> = Module::new(
213         ObjectBuilder::new(
214             crate::build_isa(sess, true),
215             name + ".o",
216             ObjectTrapCollection::Disabled,
217             cranelift_module::default_libcall_names(),
218         )
219         .unwrap(),
220     );
221     module
222 }