1+ use std:: borrow:: Cow ;
12use std:: ffi:: CString ;
23
34use rustc_abi:: AddressSpace ;
@@ -6,13 +7,17 @@ use rustc_hir::attrs::Linkage;
67use rustc_hir:: def:: DefKind ;
78use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
89use rustc_middle:: bug;
10+ use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrs ;
911use rustc_middle:: mir:: mono:: Visibility ;
1012use rustc_middle:: ty:: layout:: { FnAbiOf , HasTypingEnv , LayoutOf } ;
11- use rustc_middle:: ty:: { self , Instance , TypeVisitableExt } ;
13+ use rustc_middle:: ty:: { self , Instance , Ty , TypeVisitableExt } ;
1214use rustc_session:: config:: CrateType ;
15+ use rustc_target:: callconv:: FnAbi ;
1316use rustc_target:: spec:: { Arch , RelocModel } ;
1417use tracing:: debug;
1518
19+ use crate :: abi:: FnAbiLlvmExt ;
20+ use crate :: builder:: Builder ;
1621use crate :: context:: CodegenCx ;
1722use crate :: errors:: SymbolAlreadyDefined ;
1823use crate :: type_of:: LayoutLlvmExt ;
@@ -45,7 +50,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
4550 self . assume_dso_local ( g, false ) ;
4651
4752 let attrs = self . tcx . codegen_instance_attrs ( instance. def ) ;
48- self . add_aliases ( g, & attrs. foreign_item_symbol_aliases ) ;
53+ self . add_static_aliases ( g, & attrs. foreign_item_symbol_aliases ) ;
4954
5055 self . instances . borrow_mut ( ) . insert ( instance, g) ;
5156 }
@@ -59,11 +64,29 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
5964 ) {
6065 assert ! ( !instance. args. has_infer( ) ) ;
6166
62- let fn_abi = self . fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
67+ let attrs = self . tcx . codegen_instance_attrs ( instance. def ) ;
68+
69+ let lldecl =
70+ self . predefine_without_aliases ( instance, & attrs, linkage, visibility, symbol_name) ;
71+ self . add_function_aliases ( instance, lldecl, & attrs, & attrs. foreign_item_symbol_aliases ) ;
72+
73+ self . instances . borrow_mut ( ) . insert ( instance, lldecl) ;
74+ }
75+ }
76+
77+ impl < ' ll , ' tcx > CodegenCx < ' ll , ' tcx > {
78+ fn predefine_without_aliases (
79+ & self ,
80+ instance : Instance < ' tcx > ,
81+ attrs : & Cow < ' _ , CodegenFnAttrs > ,
82+ linkage : Linkage ,
83+ visibility : Visibility ,
84+ symbol_name : & str ,
85+ ) -> & ' ll llvm:: Value {
86+ let fn_abi: & FnAbi < ' tcx , Ty < ' tcx > > = self . fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
6387 let lldecl = self . declare_fn ( symbol_name, fn_abi, Some ( instance) ) ;
6488 llvm:: set_linkage ( lldecl, base:: linkage_to_llvm ( linkage) ) ;
65- let attrs = self . tcx . codegen_instance_attrs ( instance. def ) ;
66- base:: set_link_section ( lldecl, & attrs) ;
89+ base:: set_link_section ( lldecl, attrs) ;
6790 if ( linkage == Linkage :: LinkOnceODR || linkage == Linkage :: WeakODR )
6891 && self . tcx . sess . target . supports_comdat ( )
6992 {
@@ -84,20 +107,45 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
84107
85108 self . assume_dso_local ( lldecl, false ) ;
86109
87- self . add_aliases ( lldecl, & attrs. foreign_item_symbol_aliases ) ;
88-
89- self . instances . borrow_mut ( ) . insert ( instance, lldecl) ;
110+ lldecl
90111 }
91- }
92112
93- impl CodegenCx < ' _ , ' _ > {
94- fn add_aliases ( & self , aliasee : & llvm:: Value , aliases : & [ ( DefId , Linkage , Visibility ) ] ) {
113+ /// LLVM has the concept of an `alias`.
114+ /// We need this for the "externally implementable items" feature,
115+ /// though it's generally useful.
116+ ///
117+ /// On macos, though this might be a more general problem, function symbols
118+ /// have a fixed target architecture. This is necessary, since macos binaries
119+ /// may contain code for both ARM and x86 macs.
120+ ///
121+ /// LLVM *can* add attributes for target architecture to function symbols,
122+ /// cannot do so for statics, but importantly, also cannot for aliases
123+ /// *even* when aliases may refer to a function symbol.
124+ ///
125+ /// This is not a problem: instead of using LLVM aliases, we can just generate
126+ /// a new function symbol (with target architecture!) which effectively comes down to:
127+ ///
128+ /// ```ignore (illustrative example)
129+ /// fn alias_name(...args) {
130+ /// original_name(...args)
131+ /// }
132+ /// ```
133+ ///
134+ /// That's also an alias.
135+ ///
136+ /// This does mean that the alias symbol has a different address than the original symbol
137+ /// (assuming no optimizations by LLVM occur). This is unacceptable for statics.
138+ /// So for statics we do want to use LLVM aliases, which is fine,
139+ /// since for those we don't care about target architecture anyway.
140+ ///
141+ /// So, this function is for static aliases. See [`add_function_aliases`](Self::add_function_aliases) for the alternative.
142+ fn add_static_aliases ( & self , aliasee : & llvm:: Value , aliases : & [ ( DefId , Linkage , Visibility ) ] ) {
95143 let ty = self . get_type_of_global ( aliasee) ;
96144
97145 for ( alias, linkage, visibility) in aliases {
98146 let symbol_name = self . tcx . symbol_name ( Instance :: mono ( self . tcx , * alias) ) ;
147+ tracing:: debug!( "STATIC ALIAS: {alias:?} {linkage:?} {visibility:?}" ) ;
99148
100- tracing:: debug!( "ALIAS: {alias:?} {linkage:?} {visibility:?}" ) ;
101149 let lldecl = llvm:: add_alias (
102150 self . llmod ,
103151 ty,
@@ -111,6 +159,54 @@ impl CodegenCx<'_, '_> {
111159 }
112160 }
113161
162+ /// See [`add_static_aliases`](Self::add_static_aliases) for docs.
163+ fn add_function_aliases (
164+ & self ,
165+ aliasee_instance : Instance < ' tcx > ,
166+ aliasee : & ' ll llvm:: Value ,
167+ attrs : & Cow < ' _ , CodegenFnAttrs > ,
168+ aliases : & [ ( DefId , Linkage , Visibility ) ] ,
169+ ) {
170+ for ( alias, linkage, visibility) in aliases {
171+ let symbol_name = self . tcx . symbol_name ( Instance :: mono ( self . tcx , * alias) ) ;
172+ tracing:: debug!( "FUNCTION ALIAS: {alias:?} {linkage:?} {visibility:?}" ) ;
173+
174+ // predefine another copy of the original instance
175+ // with a new symbol name
176+ let alias_lldecl = self . predefine_without_aliases (
177+ aliasee_instance,
178+ attrs,
179+ * linkage,
180+ * visibility,
181+ symbol_name. name ,
182+ ) ;
183+
184+ let fn_abi: & FnAbi < ' tcx , Ty < ' tcx > > =
185+ self . fn_abi_of_instance ( aliasee_instance, ty:: List :: empty ( ) ) ;
186+
187+ // both the alias and the aliasee have the same ty
188+ let fn_ty = fn_abi. llvm_type ( self ) ;
189+ let start_llbb = Builder :: append_block ( self , alias_lldecl, "start" ) ;
190+ let mut start_bx = Builder :: build ( self , start_llbb) ;
191+
192+ let num_params = llvm:: count_params ( alias_lldecl) ;
193+ let mut args = Vec :: with_capacity ( num_params as usize ) ;
194+ for index in 0 ..num_params {
195+ args. push ( llvm:: get_param ( alias_lldecl, index) ) ;
196+ }
197+
198+ start_bx. tail_call (
199+ fn_ty,
200+ Some ( attrs) ,
201+ fn_abi,
202+ aliasee,
203+ & args,
204+ None ,
205+ Some ( aliasee_instance) ,
206+ ) ;
207+ }
208+ }
209+
114210 /// A definition or declaration can be assumed to be local to a group of
115211 /// libraries that form a single DSO or executable.
116212 /// Marks the local as DSO if so.
0 commit comments