]>
Commit | Line | Data |
---|---|---|
416331ca | 1 | use std::collections::hash_map::Entry::*; |
ba9703b0 | 2 | |
74b04a01 | 3 | use rustc_ast::expand::allocator::ALLOCATOR_METHODS; |
dfeec247 | 4 | use rustc_data_structures::fx::FxHashMap; |
9ffffee4 | 5 | use rustc_hir::def::DefKind; |
04454e1e | 6 | use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; |
ba9703b0 XL |
7 | use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; |
8 | use rustc_middle::middle::exported_symbols::{ | |
04454e1e | 9 | metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, |
ba9703b0 | 10 | }; |
3c0e092e | 11 | use rustc_middle::ty::query::{ExternProviders, Providers}; |
ba9703b0 XL |
12 | use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; |
13 | use rustc_middle::ty::Instance; | |
9ffffee4 | 14 | use rustc_middle::ty::{self, DefIdTree, SymbolName, TyCtxt}; |
2b03887a | 15 | use rustc_session::config::{CrateType, OomStrategy}; |
cdc7bbd5 | 16 | use rustc_target::spec::SanitizerSet; |
ea8adc8c | 17 | |
dc9dc135 | 18 | pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { |
f9f354fc | 19 | crates_export_threshold(&tcx.sess.crate_types()) |
476ff2be SL |
20 | } |
21 | ||
f9f354fc | 22 | fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel { |
ea8adc8c | 23 | match crate_type { |
f9f354fc XL |
24 | CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => { |
25 | SymbolExportLevel::C | |
26 | } | |
27 | CrateType::Rlib | CrateType::Dylib => SymbolExportLevel::Rust, | |
476ff2be | 28 | } |
ea8adc8c | 29 | } |
476ff2be | 30 | |
f9f354fc | 31 | pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel { |
dfeec247 XL |
32 | if crate_types |
33 | .iter() | |
34 | .any(|&crate_type| crate_export_threshold(crate_type) == SymbolExportLevel::Rust) | |
a1dfa0c6 | 35 | { |
ea8adc8c XL |
36 | SymbolExportLevel::Rust |
37 | } else { | |
38 | SymbolExportLevel::C | |
39 | } | |
40 | } | |
41 | ||
04454e1e | 42 | fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<SymbolExportInfo> { |
0531ce1d XL |
43 | assert_eq!(cnum, LOCAL_CRATE); |
44 | ||
94b46f34 | 45 | if !tcx.sess.opts.output_types.should_codegen() { |
f9f354fc | 46 | return Default::default(); |
0531ce1d XL |
47 | } |
48 | ||
49 | // Check to see if this crate is a "special runtime crate". These | |
50 | // crates, implementation details of the standard library, typically | |
51 | // have a bunch of `pub extern` and `#[no_mangle]` functions as the | |
52 | // ABI between them. We don't want their symbols to have a `C` | |
53 | // export level, however, as they're just implementation details. | |
54 | // Down below we'll hardwire all of the symbols to the `Rust` export | |
55 | // level instead. | |
dfeec247 XL |
56 | let special_runtime_crate = |
57 | tcx.is_panic_runtime(LOCAL_CRATE) || tcx.is_compiler_builtins(LOCAL_CRATE); | |
0531ce1d | 58 | |
dfeec247 | 59 | let mut reachable_non_generics: DefIdMap<_> = tcx |
17df50a5 | 60 | .reachable_set(()) |
0531ce1d | 61 | .iter() |
3dfed10e | 62 | .filter_map(|&def_id| { |
0531ce1d XL |
63 | // We want to ignore some FFI functions that are not exposed from |
64 | // this crate. Reachable FFI functions can be lumped into two | |
65 | // categories: | |
66 | // | |
67 | // 1. Those that are included statically via a static library | |
0731742a | 68 | // 2. Those included otherwise (e.g., dynamically or via a framework) |
0531ce1d XL |
69 | // |
70 | // Although our LLVM module is not literally emitting code for the | |
71 | // statically included symbols, it's an export of our library which | |
72 | // needs to be passed on to the linker and encoded in the metadata. | |
73 | // | |
74 | // As a result, if this id is an FFI item (foreign item) then we only | |
75 | // let it through if it's included statically. | |
9ffffee4 FG |
76 | if let Some(parent_id) = tcx.opt_local_parent(def_id) |
77 | && let DefKind::ForeignMod = tcx.def_kind(parent_id) | |
78 | { | |
79 | let library = tcx.native_library(def_id)?; | |
80 | return library.kind.is_statically_included().then_some(def_id); | |
81 | } | |
476ff2be | 82 | |
9ffffee4 FG |
83 | // Only consider nodes that actually have exported symbols. |
84 | match tcx.def_kind(def_id) { | |
85 | DefKind::Fn | DefKind::Static(_) => {} | |
86 | DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {} | |
87 | _ => return None, | |
88 | }; | |
0531ce1d | 89 | |
9ffffee4 FG |
90 | let generics = tcx.generics_of(def_id); |
91 | if generics.requires_monomorphization(tcx) { | |
92 | return None; | |
93 | } | |
94 | ||
95 | // Functions marked with #[inline] are codegened with "internal" | |
96 | // linkage and are not exported unless marked with an extern | |
97 | // indicator | |
98 | if !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx) | |
99 | || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator() | |
100 | { | |
101 | Some(def_id) | |
102 | } else { | |
103 | None | |
3b2f2976 | 104 | } |
0531ce1d | 105 | }) |
83c7162d | 106 | .map(|def_id| { |
f2b60f7d FG |
107 | // We won't link right if this symbol is stripped during LTO. |
108 | let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name; | |
109 | let used = name == "rust_eh_personality"; | |
110 | ||
111 | let export_level = if special_runtime_crate { | |
112 | SymbolExportLevel::Rust | |
0531ce1d | 113 | } else { |
f2b60f7d | 114 | symbol_export_level(tcx, def_id.to_def_id()) |
0531ce1d | 115 | }; |
04454e1e | 116 | let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id()); |
dfeec247 XL |
117 | debug!( |
118 | "EXPORTED SYMBOL (local): {} ({:?})", | |
f9f354fc | 119 | tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())), |
dfeec247 XL |
120 | export_level |
121 | ); | |
9ffffee4 | 122 | let info = SymbolExportInfo { |
04454e1e FG |
123 | level: export_level, |
124 | kind: if tcx.is_static(def_id.to_def_id()) { | |
125 | if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { | |
126 | SymbolExportKind::Tls | |
127 | } else { | |
128 | SymbolExportKind::Data | |
129 | } | |
130 | } else { | |
131 | SymbolExportKind::Text | |
132 | }, | |
133 | used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) | |
9ffffee4 FG |
134 | || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) |
135 | || used, | |
136 | }; | |
137 | (def_id.to_def_id(), info) | |
0531ce1d XL |
138 | }) |
139 | .collect(); | |
140 | ||
17df50a5 | 141 | if let Some(id) = tcx.proc_macro_decls_static(()) { |
04454e1e FG |
142 | reachable_non_generics.insert( |
143 | id.to_def_id(), | |
144 | SymbolExportInfo { | |
145 | level: SymbolExportLevel::C, | |
146 | kind: SymbolExportKind::Data, | |
147 | used: false, | |
148 | }, | |
149 | ); | |
0531ce1d XL |
150 | } |
151 | ||
f9f354fc | 152 | reachable_non_generics |
83c7162d XL |
153 | } |
154 | ||
416331ca | 155 | fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: DefId) -> bool { |
83c7162d XL |
156 | let export_threshold = threshold(tcx); |
157 | ||
04454e1e FG |
158 | if let Some(&info) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { |
159 | info.level.is_below_threshold(export_threshold) | |
83c7162d XL |
160 | } else { |
161 | false | |
0531ce1d | 162 | } |
83c7162d XL |
163 | } |
164 | ||
416331ca | 165 | fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> bool { |
83c7162d XL |
166 | tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) |
167 | } | |
168 | ||
9c376795 FG |
169 | fn exported_symbols_provider_local( |
170 | tcx: TyCtxt<'_>, | |
dc9dc135 | 171 | cnum: CrateNum, |
9c376795 | 172 | ) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] { |
83c7162d XL |
173 | assert_eq!(cnum, LOCAL_CRATE); |
174 | ||
94b46f34 | 175 | if !tcx.sess.opts.output_types.should_codegen() { |
ba9703b0 | 176 | return &[]; |
83c7162d XL |
177 | } |
178 | ||
9c376795 FG |
179 | // FIXME: Sorting this is unnecessary since we are sorting later anyway. |
180 | // Can we skip the later sorting? | |
181 | let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| { | |
182 | tcx.reachable_non_generics(LOCAL_CRATE) | |
183 | .to_sorted(&hcx, true) | |
184 | .into_iter() | |
185 | .map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)) | |
186 | .collect() | |
187 | }); | |
3b2f2976 | 188 | |
17df50a5 | 189 | if tcx.entry_fn(()).is_some() { |
487cf647 FG |
190 | let exported_symbol = |
191 | ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref())); | |
0531ce1d | 192 | |
04454e1e FG |
193 | symbols.push(( |
194 | exported_symbol, | |
195 | SymbolExportInfo { | |
196 | level: SymbolExportLevel::C, | |
197 | kind: SymbolExportKind::Text, | |
198 | used: false, | |
199 | }, | |
200 | )); | |
0531ce1d XL |
201 | } |
202 | ||
136023e0 | 203 | if tcx.allocator_kind(()).is_some() { |
487cf647 FG |
204 | for symbol_name in ALLOCATOR_METHODS |
205 | .iter() | |
206 | .map(|method| format!("__rust_{}", method.name)) | |
207 | .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()]) | |
208 | { | |
3dfed10e | 209 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); |
0531ce1d | 210 | |
04454e1e FG |
211 | symbols.push(( |
212 | exported_symbol, | |
213 | SymbolExportInfo { | |
214 | level: SymbolExportLevel::Rust, | |
215 | kind: SymbolExportKind::Text, | |
216 | used: false, | |
217 | }, | |
218 | )); | |
476ff2be | 219 | } |
2b03887a FG |
220 | |
221 | symbols.push(( | |
222 | ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)), | |
223 | SymbolExportInfo { | |
224 | level: SymbolExportLevel::Rust, | |
225 | kind: SymbolExportKind::Text, | |
226 | used: false, | |
227 | }, | |
228 | )); | |
0531ce1d | 229 | } |
476ff2be | 230 | |
cdc7bbd5 | 231 | if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() { |
0531ce1d XL |
232 | // These are weak symbols that point to the profile version and the |
233 | // profile name, which need to be treated as exported so LTO doesn't nix | |
234 | // them. | |
dfeec247 XL |
235 | const PROFILER_WEAK_SYMBOLS: [&str; 2] = |
236 | ["__llvm_profile_raw_version", "__llvm_profile_filename"]; | |
a1dfa0c6 XL |
237 | |
238 | symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| { | |
3dfed10e | 239 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); |
04454e1e FG |
240 | ( |
241 | exported_symbol, | |
242 | SymbolExportInfo { | |
243 | level: SymbolExportLevel::C, | |
244 | kind: SymbolExportKind::Data, | |
245 | used: false, | |
246 | }, | |
247 | ) | |
a1dfa0c6 | 248 | })); |
0531ce1d | 249 | } |
abe05a73 | 250 | |
064997fb | 251 | if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) { |
04454e1e FG |
252 | let mut msan_weak_symbols = Vec::new(); |
253 | ||
dfeec247 | 254 | // Similar to profiling, preserve weak msan symbol during LTO. |
064997fb | 255 | if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) { |
04454e1e FG |
256 | msan_weak_symbols.push("__msan_keep_going"); |
257 | } | |
258 | ||
064997fb | 259 | if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 { |
04454e1e FG |
260 | msan_weak_symbols.push("__msan_track_origins"); |
261 | } | |
dfeec247 | 262 | |
04454e1e | 263 | symbols.extend(msan_weak_symbols.into_iter().map(|sym| { |
3dfed10e | 264 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); |
04454e1e FG |
265 | ( |
266 | exported_symbol, | |
267 | SymbolExportInfo { | |
268 | level: SymbolExportLevel::C, | |
269 | kind: SymbolExportKind::Data, | |
270 | used: false, | |
271 | }, | |
272 | ) | |
dfeec247 XL |
273 | })); |
274 | } | |
275 | ||
064997fb FG |
276 | if tcx.sess.crate_types().contains(&CrateType::Dylib) |
277 | || tcx.sess.crate_types().contains(&CrateType::ProcMacro) | |
278 | { | |
0531ce1d | 279 | let symbol_name = metadata_symbol_name(tcx); |
3dfed10e | 280 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); |
abe05a73 | 281 | |
04454e1e FG |
282 | symbols.push(( |
283 | exported_symbol, | |
284 | SymbolExportInfo { | |
064997fb | 285 | level: SymbolExportLevel::C, |
04454e1e | 286 | kind: SymbolExportKind::Data, |
064997fb | 287 | used: true, |
04454e1e FG |
288 | }, |
289 | )); | |
0531ce1d XL |
290 | } |
291 | ||
b7449926 | 292 | if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() { |
ba9703b0 XL |
293 | use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; |
294 | use rustc_middle::ty::InstanceDef; | |
83c7162d XL |
295 | |
296 | // Normally, we require that shared monomorphizations are not hidden, | |
297 | // because if we want to re-use a monomorphization from a Rust dylib, it | |
298 | // needs to be exported. | |
299 | // However, on platforms that don't allow for Rust dylibs, having | |
300 | // external linkage is enough for monomorphization to be linked to. | |
29967ef6 | 301 | let need_visibility = tcx.sess.target.dynamic_linking && !tcx.sess.target.only_cdylib; |
83c7162d | 302 | |
17df50a5 | 303 | let (_, cgus) = tcx.collect_and_partition_mono_items(()); |
83c7162d | 304 | |
dfeec247 | 305 | for (mono_item, &(linkage, visibility)) in cgus.iter().flat_map(|cgu| cgu.items().iter()) { |
83c7162d XL |
306 | if linkage != Linkage::External { |
307 | // We can only re-use things with external linkage, otherwise | |
308 | // we'll get a linker error | |
dfeec247 | 309 | continue; |
83c7162d XL |
310 | } |
311 | ||
312 | if need_visibility && visibility == Visibility::Hidden { | |
313 | // If we potentially share things from Rust dylibs, they must | |
314 | // not be hidden | |
dfeec247 | 315 | continue; |
83c7162d XL |
316 | } |
317 | ||
dfeec247 | 318 | match *mono_item { |
3dfed10e | 319 | MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => { |
dfeec247 | 320 | if substs.non_erasable_generics().next().is_some() { |
3dfed10e | 321 | let symbol = ExportedSymbol::Generic(def.did, substs); |
04454e1e FG |
322 | symbols.push(( |
323 | symbol, | |
324 | SymbolExportInfo { | |
325 | level: SymbolExportLevel::Rust, | |
326 | kind: SymbolExportKind::Text, | |
327 | used: false, | |
328 | }, | |
329 | )); | |
dfeec247 XL |
330 | } |
331 | } | |
332 | MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }) => { | |
333 | // A little sanity-check | |
334 | debug_assert_eq!( | |
335 | substs.non_erasable_generics().next(), | |
336 | Some(GenericArgKind::Type(ty)) | |
337 | ); | |
04454e1e FG |
338 | symbols.push(( |
339 | ExportedSymbol::DropGlue(ty), | |
340 | SymbolExportInfo { | |
341 | level: SymbolExportLevel::Rust, | |
342 | kind: SymbolExportKind::Text, | |
343 | used: false, | |
344 | }, | |
345 | )); | |
dfeec247 XL |
346 | } |
347 | _ => { | |
348 | // Any other symbols don't qualify for sharing | |
83c7162d XL |
349 | } |
350 | } | |
351 | } | |
352 | } | |
353 | ||
0531ce1d | 354 | // Sort so we get a stable incr. comp. hash. |
dfeec247 | 355 | symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); |
2c00a5a8 | 356 | |
ba9703b0 | 357 | tcx.arena.alloc_from_iter(symbols) |
ea8adc8c | 358 | } |
476ff2be | 359 | |
416331ca XL |
360 | fn upstream_monomorphizations_provider( |
361 | tcx: TyCtxt<'_>, | |
17df50a5 | 362 | (): (), |
f9f354fc | 363 | ) -> DefIdMap<FxHashMap<SubstsRef<'_>, CrateNum>> { |
136023e0 | 364 | let cnums = tcx.crates(()); |
83c7162d | 365 | |
a1dfa0c6 | 366 | let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default(); |
83c7162d | 367 | |
dfeec247 XL |
368 | let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn(); |
369 | ||
83c7162d | 370 | for &cnum in cnums.iter() { |
e74abb32 | 371 | for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { |
dfeec247 XL |
372 | let (def_id, substs) = match *exported_symbol { |
373 | ExportedSymbol::Generic(def_id, substs) => (def_id, substs), | |
374 | ExportedSymbol::DropGlue(ty) => { | |
375 | if let Some(drop_in_place_fn_def_id) = drop_in_place_fn_def_id { | |
9ffffee4 | 376 | (drop_in_place_fn_def_id, tcx.mk_substs(&[ty.into()])) |
dfeec247 XL |
377 | } else { |
378 | // `drop_in_place` in place does not exist, don't try | |
379 | // to use it. | |
380 | continue; | |
83c7162d | 381 | } |
dfeec247 XL |
382 | } |
383 | ExportedSymbol::NonGeneric(..) | ExportedSymbol::NoDefId(..) => { | |
384 | // These are no monomorphizations | |
385 | continue; | |
386 | } | |
387 | }; | |
388 | ||
389 | let substs_map = instances.entry(def_id).or_default(); | |
390 | ||
391 | match substs_map.entry(substs) { | |
392 | Occupied(mut e) => { | |
393 | // If there are multiple monomorphizations available, | |
394 | // we select one deterministically. | |
395 | let other_cnum = *e.get(); | |
04454e1e | 396 | if tcx.stable_crate_id(other_cnum) > tcx.stable_crate_id(cnum) { |
83c7162d XL |
397 | e.insert(cnum); |
398 | } | |
399 | } | |
dfeec247 XL |
400 | Vacant(e) => { |
401 | e.insert(cnum); | |
402 | } | |
83c7162d XL |
403 | } |
404 | } | |
405 | } | |
406 | ||
f9f354fc | 407 | instances |
83c7162d XL |
408 | } |
409 | ||
416331ca XL |
410 | fn upstream_monomorphizations_for_provider( |
411 | tcx: TyCtxt<'_>, | |
dc9dc135 | 412 | def_id: DefId, |
416331ca | 413 | ) -> Option<&FxHashMap<SubstsRef<'_>, CrateNum>> { |
83c7162d | 414 | debug_assert!(!def_id.is_local()); |
17df50a5 | 415 | tcx.upstream_monomorphizations(()).get(&def_id) |
83c7162d XL |
416 | } |
417 | ||
dfeec247 XL |
418 | fn upstream_drop_glue_for_provider<'tcx>( |
419 | tcx: TyCtxt<'tcx>, | |
420 | substs: SubstsRef<'tcx>, | |
421 | ) -> Option<CrateNum> { | |
422 | if let Some(def_id) = tcx.lang_items().drop_in_place_fn() { | |
423 | tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&substs).cloned()) | |
424 | } else { | |
425 | None | |
426 | } | |
427 | } | |
428 | ||
17df50a5 XL |
429 | fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { |
430 | !tcx.reachable_set(()).contains(&def_id) | |
83c7162d XL |
431 | } |
432 | ||
f035d41b | 433 | pub fn provide(providers: &mut Providers) { |
0531ce1d | 434 | providers.reachable_non_generics = reachable_non_generics_provider; |
83c7162d | 435 | providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; |
0531ce1d | 436 | providers.exported_symbols = exported_symbols_provider_local; |
83c7162d XL |
437 | providers.upstream_monomorphizations = upstream_monomorphizations_provider; |
438 | providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; | |
dfeec247 | 439 | providers.upstream_drop_glue_for = upstream_drop_glue_for_provider; |
17df50a5 | 440 | providers.wasm_import_module_map = wasm_import_module_map; |
0531ce1d | 441 | } |
476ff2be | 442 | |
3c0e092e | 443 | pub fn provide_extern(providers: &mut ExternProviders) { |
83c7162d XL |
444 | providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; |
445 | providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; | |
476ff2be SL |
446 | } |
447 | ||
dc9dc135 | 448 | fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel { |
abe05a73 XL |
449 | // We export anything that's not mangled at the "C" layer as it probably has |
450 | // to do with ABI concerns. We do not, however, apply such treatment to | |
451 | // special symbols in the standard library for various plumbing between | |
452 | // core/std/allocators/etc. For example symbols used to hook up allocation | |
453 | // are not considered for export | |
94b46f34 XL |
454 | let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id); |
455 | let is_extern = codegen_fn_attrs.contains_extern_indicator(); | |
456 | let std_internal = | |
457 | codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); | |
0531ce1d | 458 | |
abe05a73 | 459 | if is_extern && !std_internal { |
29967ef6 | 460 | let target = &tcx.sess.target.llvm_target; |
e74abb32 | 461 | // WebAssembly cannot export data symbols, so reduce their export level |
dfeec247 | 462 | if target.contains("emscripten") { |
9ffffee4 | 463 | if let DefKind::Static(_) = tcx.def_kind(sym_def_id) { |
a1dfa0c6 XL |
464 | return SymbolExportLevel::Rust; |
465 | } | |
466 | } | |
467 | ||
476ff2be | 468 | SymbolExportLevel::C |
476ff2be | 469 | } else { |
ea8adc8c | 470 | SymbolExportLevel::Rust |
476ff2be SL |
471 | } |
472 | } | |
dfeec247 XL |
473 | |
474 | /// This is the symbol name of the given instance instantiated in a specific crate. | |
475 | pub fn symbol_name_for_instance_in_crate<'tcx>( | |
476 | tcx: TyCtxt<'tcx>, | |
477 | symbol: ExportedSymbol<'tcx>, | |
478 | instantiating_crate: CrateNum, | |
479 | ) -> String { | |
480 | // If this is something instantiated in the local crate then we might | |
481 | // already have cached the name as a query result. | |
482 | if instantiating_crate == LOCAL_CRATE { | |
483 | return symbol.symbol_name_for_local_instance(tcx).to_string(); | |
484 | } | |
485 | ||
486 | // This is something instantiated in an upstream crate, so we have to use | |
487 | // the slower (because uncached) version of computing the symbol name. | |
488 | match symbol { | |
ba9703b0 XL |
489 | ExportedSymbol::NonGeneric(def_id) => { |
490 | rustc_symbol_mangling::symbol_name_for_instance_in_crate( | |
491 | tcx, | |
492 | Instance::mono(tcx, def_id), | |
493 | instantiating_crate, | |
494 | ) | |
495 | } | |
496 | ExportedSymbol::Generic(def_id, substs) => { | |
497 | rustc_symbol_mangling::symbol_name_for_instance_in_crate( | |
498 | tcx, | |
499 | Instance::new(def_id, substs), | |
500 | instantiating_crate, | |
501 | ) | |
502 | } | |
503 | ExportedSymbol::DropGlue(ty) => rustc_symbol_mangling::symbol_name_for_instance_in_crate( | |
dfeec247 XL |
504 | tcx, |
505 | Instance::resolve_drop_in_place(tcx, ty), | |
506 | instantiating_crate, | |
507 | ), | |
508 | ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(), | |
509 | } | |
510 | } | |
17df50a5 | 511 | |
04454e1e FG |
512 | /// This is the symbol name of the given instance as seen by the linker. |
513 | /// | |
514 | /// On 32-bit Windows symbols are decorated according to their calling conventions. | |
515 | pub fn linking_symbol_name_for_instance_in_crate<'tcx>( | |
516 | tcx: TyCtxt<'tcx>, | |
517 | symbol: ExportedSymbol<'tcx>, | |
518 | instantiating_crate: CrateNum, | |
519 | ) -> String { | |
520 | use rustc_target::abi::call::Conv; | |
521 | ||
522 | let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); | |
523 | ||
524 | let target = &tcx.sess.target; | |
525 | if !target.is_like_windows { | |
526 | // Mach-O has a global "_" suffix and `object` crate will handle it. | |
527 | // ELF does not have any symbol decorations. | |
528 | return undecorated; | |
529 | } | |
530 | ||
531 | let x86 = match &target.arch[..] { | |
532 | "x86" => true, | |
533 | "x86_64" => false, | |
534 | // Only x86/64 use symbol decorations. | |
535 | _ => return undecorated, | |
536 | }; | |
537 | ||
538 | let instance = match symbol { | |
539 | ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _) | |
540 | if tcx.is_static(def_id) => | |
541 | { | |
542 | None | |
543 | } | |
544 | ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)), | |
545 | ExportedSymbol::Generic(def_id, substs) => Some(Instance::new(def_id, substs)), | |
546 | // DropGlue always use the Rust calling convention and thus follow the target's default | |
547 | // symbol decoration scheme. | |
548 | ExportedSymbol::DropGlue(..) => None, | |
549 | // NoDefId always follow the target's default symbol decoration scheme. | |
550 | ExportedSymbol::NoDefId(..) => None, | |
551 | }; | |
552 | ||
553 | let (conv, args) = instance | |
554 | .map(|i| { | |
555 | tcx.fn_abi_of_instance(ty::ParamEnv::reveal_all().and((i, ty::List::empty()))) | |
556 | .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed")) | |
557 | }) | |
558 | .map(|fnabi| (fnabi.conv, &fnabi.args[..])) | |
559 | .unwrap_or((Conv::Rust, &[])); | |
560 | ||
f2b60f7d | 561 | // Decorate symbols with prefixes, suffixes and total number of bytes of arguments. |
04454e1e FG |
562 | // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170 |
563 | let (prefix, suffix) = match conv { | |
564 | Conv::X86Fastcall => ("@", "@"), | |
565 | Conv::X86Stdcall => ("_", "@"), | |
566 | Conv::X86VectorCall => ("", "@@"), | |
567 | _ => { | |
568 | if x86 { | |
569 | undecorated.insert(0, '_'); | |
570 | } | |
571 | return undecorated; | |
572 | } | |
573 | }; | |
574 | ||
575 | let args_in_bytes: u64 = args | |
576 | .iter() | |
577 | .map(|abi| abi.layout.size.bytes().next_multiple_of(target.pointer_width as u64 / 8)) | |
578 | .sum(); | |
579 | format!("{prefix}{undecorated}{suffix}{args_in_bytes}") | |
580 | } | |
581 | ||
17df50a5 XL |
582 | fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> { |
583 | // Build up a map from DefId to a `NativeLib` structure, where | |
584 | // `NativeLib` internally contains information about | |
585 | // `#[link(wasm_import_module = "...")]` for example. | |
586 | let native_libs = tcx.native_libraries(cnum); | |
587 | ||
588 | let def_id_to_native_lib = native_libs | |
589 | .iter() | |
590 | .filter_map(|lib| lib.foreign_module.map(|id| (id, lib))) | |
591 | .collect::<FxHashMap<_, _>>(); | |
592 | ||
593 | let mut ret = FxHashMap::default(); | |
594 | for (def_id, lib) in tcx.foreign_modules(cnum).iter() { | |
595 | let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module); | |
5e7ed085 | 596 | let Some(module) = module else { continue }; |
17df50a5 XL |
597 | ret.extend(lib.foreign_items.iter().map(|id| { |
598 | assert_eq!(id.krate, cnum); | |
599 | (*id, module.to_string()) | |
600 | })); | |
601 | } | |
602 | ||
603 | ret | |
604 | } |