rustc_codegen_ssa/back/
symbol_export.rs

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