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 , PassMode } ;
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 ;
@@ -46,7 +51,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
4651 self . assume_dso_local ( g, false ) ;
4752
4853 let attrs = self . tcx . codegen_instance_attrs ( instance. def ) ;
49- self . add_aliases ( g, & attrs. foreign_item_symbol_aliases ) ;
54+ self . add_static_aliases ( g, & attrs. foreign_item_symbol_aliases ) ;
5055
5156 self . instances . borrow_mut ( ) . insert ( instance, g) ;
5257 }
@@ -60,11 +65,29 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
6065 ) {
6166 assert ! ( !instance. args. has_infer( ) ) ;
6267
63- let fn_abi = self . fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
68+ let attrs = self . tcx . codegen_instance_attrs ( instance. def ) ;
69+
70+ let lldecl =
71+ self . predefine_without_aliases ( instance, & attrs, linkage, visibility, symbol_name) ;
72+ self . add_function_aliases ( instance, lldecl, & attrs, & attrs. foreign_item_symbol_aliases ) ;
73+
74+ self . instances . borrow_mut ( ) . insert ( instance, lldecl) ;
75+ }
76+ }
77+
78+ impl < ' ll , ' tcx > CodegenCx < ' ll , ' tcx > {
79+ fn predefine_without_aliases (
80+ & self ,
81+ instance : Instance < ' tcx > ,
82+ attrs : & Cow < ' _ , CodegenFnAttrs > ,
83+ linkage : Linkage ,
84+ visibility : Visibility ,
85+ symbol_name : & str ,
86+ ) -> & ' ll llvm:: Value {
87+ let fn_abi: & FnAbi < ' tcx , Ty < ' tcx > > = self . fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
6488 let lldecl = self . declare_fn ( symbol_name, fn_abi, Some ( instance) ) ;
6589 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) ;
90+ base:: set_link_section ( lldecl, attrs) ;
6891 if ( linkage == Linkage :: LinkOnceODR || linkage == Linkage :: WeakODR )
6992 && self . tcx . sess . target . supports_comdat ( )
7093 {
@@ -76,20 +99,45 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
7699
77100 self . assume_dso_local ( lldecl, false ) ;
78101
79- self . add_aliases ( lldecl, & attrs. foreign_item_symbol_aliases ) ;
80-
81- self . instances . borrow_mut ( ) . insert ( instance, lldecl) ;
102+ lldecl
82103 }
83- }
84104
85- impl CodegenCx < ' _ , ' _ > {
86- fn add_aliases ( & self , aliasee : & llvm:: Value , aliases : & [ ( DefId , Linkage , Visibility ) ] ) {
105+ /// LLVM has the concept of an `alias`.
106+ /// We need this for the "externally implementable items" feature,
107+ /// though it's generally useful.
108+ ///
109+ /// On macos, though this might be a more general problem, function symbols
110+ /// have a fixed target architecture. This is necessary, since macos binaries
111+ /// may contain code for both ARM and x86 macs.
112+ ///
113+ /// LLVM *can* add attributes for target architecture to function symbols,
114+ /// cannot do so for statics, but importantly, also cannot for aliases
115+ /// *even* when aliases may refer to a function symbol.
116+ ///
117+ /// This is not a problem: instead of using LLVM aliases, we can just generate
118+ /// a new function symbol (with target architecture!) which effectively comes down to:
119+ ///
120+ /// ```ignore (illustrative example)
121+ /// fn alias_name(...args) {
122+ /// original_name(...args)
123+ /// }
124+ /// ```
125+ ///
126+ /// That's also an alias.
127+ ///
128+ /// This does mean that the alias symbol has a different address than the original symbol
129+ /// (assuming no optimizations by LLVM occur). This is unacceptable for statics.
130+ /// So for statics we do want to use LLVM aliases, which is fine,
131+ /// since for those we don't care about target architecture anyway.
132+ ///
133+ /// So, this function is for static aliases. See [`add_function_aliases`](Self::add_function_aliases) for the alternative.
134+ fn add_static_aliases ( & self , aliasee : & llvm:: Value , aliases : & [ ( DefId , Linkage , Visibility ) ] ) {
87135 let ty = self . get_type_of_global ( aliasee) ;
88136
89137 for ( alias, linkage, visibility) in aliases {
90138 let symbol_name = self . tcx . symbol_name ( Instance :: mono ( self . tcx , * alias) ) ;
139+ tracing:: debug!( "STATIC ALIAS: {alias:?} {linkage:?} {visibility:?}" ) ;
91140
92- tracing:: debug!( "ALIAS: {alias:?} {linkage:?} {visibility:?}" ) ;
93141 let lldecl = llvm:: add_alias (
94142 self . llmod ,
95143 ty,
@@ -103,6 +151,61 @@ impl CodegenCx<'_, '_> {
103151 }
104152 }
105153
154+ /// See [`add_static_aliases`](Self::add_static_aliases) for docs.
155+ fn add_function_aliases (
156+ & self ,
157+ aliasee_instance : Instance < ' tcx > ,
158+ aliasee : & ' ll llvm:: Value ,
159+ attrs : & Cow < ' _ , CodegenFnAttrs > ,
160+ aliases : & [ ( DefId , Linkage , Visibility ) ] ,
161+ ) {
162+ for ( alias, linkage, visibility) in aliases {
163+ let symbol_name = self . tcx . symbol_name ( Instance :: mono ( self . tcx , * alias) ) ;
164+ tracing:: debug!( "FUNCTION ALIAS: {alias:?} {linkage:?} {visibility:?}" ) ;
165+
166+ // predefine another copy of the original instance
167+ // with a new symbol name
168+ let alias_lldecl = self . predefine_without_aliases (
169+ aliasee_instance,
170+ attrs,
171+ * linkage,
172+ * visibility,
173+ symbol_name. name ,
174+ ) ;
175+
176+ let fn_abi: & FnAbi < ' tcx , Ty < ' tcx > > =
177+ self . fn_abi_of_instance ( aliasee_instance, ty:: List :: empty ( ) ) ;
178+
179+ // both the alias and the aliasee have the same ty
180+ let fn_ty = fn_abi. llvm_type ( self ) ;
181+ let start_llbb = Builder :: append_block ( self , alias_lldecl, "start" ) ;
182+ let mut start_bx = Builder :: build ( self , start_llbb) ;
183+
184+ let num_params = llvm:: count_params ( alias_lldecl) ;
185+ let mut args = Vec :: with_capacity ( num_params as usize ) ;
186+ for index in 0 ..num_params {
187+ args. push ( llvm:: get_param ( alias_lldecl, index) ) ;
188+ }
189+
190+ let call = start_bx. call (
191+ fn_ty,
192+ Some ( attrs) ,
193+ Some ( fn_abi) ,
194+ aliasee,
195+ & args,
196+ None ,
197+ Some ( aliasee_instance) ,
198+ ) ;
199+
200+ match & fn_abi. ret . mode {
201+ PassMode :: Ignore | PassMode :: Indirect { .. } => start_bx. ret_void ( ) ,
202+ PassMode :: Direct ( _) | PassMode :: Pair { .. } | PassMode :: Cast { .. } => {
203+ start_bx. ret ( call)
204+ }
205+ }
206+ }
207+ }
208+
106209 /// A definition or declaration can be assumed to be local to a group of
107210 /// libraries that form a single DSO or executable.
108211 /// Marks the local as DSO if so.
0 commit comments