]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_ssa/src/back/symbol_export.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_codegen_ssa / src / back / symbol_export.rs
CommitLineData
416331ca 1use std::collections::hash_map::Entry::*;
ba9703b0 2
74b04a01 3use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
dfeec247 4use rustc_data_structures::fx::FxHashMap;
9ffffee4 5use rustc_hir::def::DefKind;
04454e1e 6use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
ba9703b0
XL
7use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
8use rustc_middle::middle::exported_symbols::{
04454e1e 9 metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
ba9703b0 10};
3c0e092e 11use rustc_middle::ty::query::{ExternProviders, Providers};
ba9703b0
XL
12use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
13use rustc_middle::ty::Instance;
9ffffee4 14use rustc_middle::ty::{self, DefIdTree, SymbolName, TyCtxt};
2b03887a 15use rustc_session::config::{CrateType, OomStrategy};
cdc7bbd5 16use rustc_target::spec::SanitizerSet;
ea8adc8c 17
dc9dc135 18pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
f9f354fc 19 crates_export_threshold(&tcx.sess.crate_types())
476ff2be
SL
20}
21
f9f354fc 22fn 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 31pub 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 42fn 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 155fn 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 165fn 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
169fn 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
360fn 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
410fn 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
418fn 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
429fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
430 !tcx.reachable_set(()).contains(&def_id)
83c7162d
XL
431}
432
f035d41b 433pub 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 443pub 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 448fn 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.
475pub 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.
515pub 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
582fn 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}