rustc_codegen_llvm/
mono_item.rs1use std::ffi::CString;
2
3use rustc_abi::AddressSpace;
4use rustc_codegen_ssa::traits::*;
5use rustc_hir::attrs::Linkage;
6use rustc_hir::def::DefKind;
7use rustc_hir::def_id::{DefId, LOCAL_CRATE};
8use rustc_middle::bug;
9use rustc_middle::mir::mono::Visibility;
10use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
11use rustc_middle::ty::{self, Instance, TypeVisitableExt};
12use rustc_session::config::CrateType;
13use rustc_span::Symbol;
14use rustc_target::spec::{Arch, RelocModel};
15use tracing::debug;
16
17use crate::context::CodegenCx;
18use crate::errors::SymbolAlreadyDefined;
19use crate::type_of::LayoutLlvmExt;
20use crate::{base, llvm};
21
22impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
23 fn predefine_static(
24 &mut self,
25 def_id: DefId,
26 linkage: Linkage,
27 visibility: Visibility,
28 symbol_name: &str,
29 ) {
30 let instance = Instance::mono(self.tcx, def_id);
31 let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
32 let ty =
35 if nested { self.tcx.types.unit } else { instance.ty(self.tcx, self.typing_env()) };
36 let llty = self.layout_of(ty).llvm_type(self);
37
38 let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
39 self.sess()
40 .dcx()
41 .emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name })
42 });
43
44 llvm::set_linkage(g, base::linkage_to_llvm(linkage));
45 llvm::set_visibility(g, base::visibility_to_llvm(visibility));
46 self.assume_dso_local(g, false);
47
48 let attrs = self.tcx.codegen_instance_attrs(instance.def);
49 self.add_aliases(g, &attrs.foreign_item_symbol_aliases);
50
51 self.instances.borrow_mut().insert(instance, g);
52 }
53
54 fn predefine_fn(
55 &mut self,
56 instance: Instance<'tcx>,
57 linkage: Linkage,
58 visibility: Visibility,
59 symbol_name: &str,
60 ) {
61 assert!(!instance.args.has_infer());
62
63 let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
64 let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
65 llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage));
66 let attrs = self.tcx.codegen_instance_attrs(instance.def);
67 base::set_link_section(lldecl, &attrs);
68 if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
69 && self.tcx.sess.target.supports_comdat()
70 {
71 llvm::SetUniqueComdat(self.llmod, lldecl);
72 }
73
74 if linkage != Linkage::Internal && self.tcx.is_compiler_builtins(LOCAL_CRATE) {
79 llvm::set_visibility(lldecl, llvm::Visibility::Hidden);
80 } else {
81 llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility));
82 }
83
84 debug!("predefine_fn: instance = {:?}", instance);
85
86 self.assume_dso_local(lldecl, false);
87
88 self.add_aliases(lldecl, &attrs.foreign_item_symbol_aliases);
89
90 self.instances.borrow_mut().insert(instance, lldecl);
91 }
92}
93
94impl CodegenCx<'_, '_> {
95 fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(Symbol, Linkage, Visibility)]) {
96 let ty = self.get_type_of_global(aliasee);
97
98 for (alias, linkage, visibility) in aliases {
99 tracing::debug!("ALIAS: {alias:?} {linkage:?} {visibility:?}");
100 let lldecl = llvm::add_alias(
101 self.llmod,
102 ty,
103 AddressSpace::ZERO,
104 aliasee,
105 &CString::new(alias.as_str()).unwrap(),
106 );
107
108 llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility));
109 llvm::set_linkage(lldecl, base::linkage_to_llvm(*linkage));
110 }
111 }
112
113 pub(crate) fn assume_dso_local(&self, llval: &llvm::Value, is_declaration: bool) -> bool {
117 let assume = self.should_assume_dso_local(llval, is_declaration);
118 if assume {
119 llvm::set_dso_local(llval);
120 }
121 assume
122 }
123
124 fn should_assume_dso_local(&self, llval: &llvm::Value, is_declaration: bool) -> bool {
125 let linkage = llvm::get_linkage(llval);
126 let visibility = llvm::get_visibility(llval);
127
128 if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
129 return true;
130 }
131
132 if visibility != llvm::Visibility::Default && linkage != llvm::Linkage::ExternalWeakLinkage
133 {
134 return true;
135 }
136
137 let all_exe = self.tcx.crate_types().iter().all(|ty| *ty == CrateType::Executable);
139 let is_declaration_for_linker =
140 is_declaration || linkage == llvm::Linkage::AvailableExternallyLinkage;
141 if all_exe && !is_declaration_for_linker {
142 return true;
143 }
144
145 if matches!(self.tcx.sess.target.arch, Arch::PowerPC64 | Arch::PowerPC64LE) {
147 return false;
148 }
149
150 if self.tcx.sess.target.is_like_darwin {
152 return false;
153 }
154
155 if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration {
158 return true;
159 }
160
161 let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
163 .is_some_and(|v| llvm::LLVMIsThreadLocal(v).is_true());
164 if is_thread_local_var {
165 return false;
166 }
167
168 if let Some(direct) = self.tcx.sess.direct_access_external_data() {
170 return direct;
171 }
172
173 self.tcx.sess.relocation_model() == RelocModel::Static
175 }
176}