@@ -49,7 +49,7 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
4949 //
5050 // Statics have a guaranteed meaningful address so it's less clear that we want to do
5151 // something like this; it's also harder.
52- if ! is_static {
52+ if matches ! ( is_static, IsStatic :: No ) {
5353 assert ! ( alloc. len( ) != 0 ) ;
5454 }
5555 let mut llvals = Vec :: with_capacity ( alloc. provenance ( ) . ptrs ( ) . len ( ) + 1 ) ;
@@ -120,14 +120,28 @@ pub(crate) fn const_alloc_to_llvm<'ll>(
120120 as u64 ;
121121
122122 let address_space = cx. tcx . global_alloc ( prov. alloc_id ( ) ) . address_space ( cx) ;
123-
124- llvals. push ( cx. scalar_to_backend (
123+ // Pauthtest function pointers stored in init/fini arrays need special handling.
124+ let pac_metadata = Some (
125+ if cx. sess ( ) . target . env == Env :: Pauthtest && matches ! ( is_init_fini, IsInitOrFini :: Yes ) {
126+ PacMetadata {
127+ // Must correspond to ptrauth_key_init_fini_pointer from `ptrauth.h`.
128+ key : 0 ,
129+ // ptrauth_string_discriminator("init_fini")
130+ disc : 0xd9d4 ,
131+ addr_diversity : AddressDiversity :: Synthetic ( 1 ) ,
132+ }
133+ } else {
134+ PacMetadata :: default ( )
135+ } ,
136+ ) ;
137+ llvals. push ( cx. scalar_to_backend_with_pac (
125138 InterpScalar :: from_pointer ( Pointer :: new ( prov, Size :: from_bytes ( ptr_offset) ) , & cx. tcx ) ,
126139 Scalar :: Initialized {
127140 value : Primitive :: Pointer ( address_space) ,
128141 valid_range : WrappingRange :: full ( pointer_size) ,
129142 } ,
130143 cx. type_ptr_ext ( address_space) ,
144+ pac_metadata,
131145 ) ) ;
132146 next_offset = offset + pointer_size_bytes;
133147 }
@@ -152,7 +166,19 @@ fn codegen_static_initializer<'ll, 'tcx>(
152166 def_id : DefId ,
153167) -> Result < ( & ' ll Value , ConstAllocation < ' tcx > ) , ErrorHandled > {
154168 let alloc = cx. tcx . eval_static_initializer ( def_id) ?;
155- Ok ( ( const_alloc_to_llvm ( cx, alloc. inner ( ) , /*static*/ true ) , alloc) )
169+ let attrs = cx. tcx . codegen_fn_attrs ( def_id) ;
170+ let is_in_init_fini: IsInitOrFini = attrs
171+ . link_section
172+ . map ( |link_section| {
173+ let s = link_section. as_str ( ) ;
174+ if s. starts_with ( ".init_array" ) || s. starts_with ( ".fini_array" ) {
175+ IsInitOrFini :: Yes
176+ } else {
177+ IsInitOrFini :: No
178+ }
179+ } )
180+ . unwrap_or ( IsInitOrFini :: No ) ;
181+ Ok ( ( const_alloc_to_llvm ( cx, alloc. inner ( ) , IsStatic :: Yes , is_in_init_fini) , alloc) )
156182}
157183
158184fn set_global_alignment < ' ll > ( cx : & CodegenCx < ' ll , ' _ > , gv : & ' ll Value , mut align : Align ) {
@@ -175,6 +201,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
175201 if let Some ( linkage) = attrs. import_linkage {
176202 debug ! ( "get_static: sym={} linkage={:?}" , sym, linkage) ;
177203
204+ let mut should_sign = false ;
178205 // Declare a symbol `foo`. If `foo` is an extern_weak symbol, we declare
179206 // an extern_weak function, otherwise a global with the desired linkage.
180207 let g1 = if matches ! ( attrs. import_linkage, Some ( Linkage :: ExternalWeak ) ) {
@@ -187,8 +214,13 @@ fn check_and_apply_linkage<'ll, 'tcx>(
187214 && let ty:: FnPtr ( sig, header) = args. type_at ( 0 ) . kind ( )
188215 {
189216 let fn_sig = sig. with ( * header) ;
190-
191217 let fn_abi = cx. fn_abi_of_fn_ptr ( fn_sig, ty:: List :: empty ( ) ) ;
218+ // Decide if the initializer needs to be signed
219+ if cx. sess ( ) . target . env == Env :: Pauthtest
220+ && matches ! ( fn_sig. abi( ) , ExternAbi :: C { .. } )
221+ {
222+ should_sign = true ;
223+ }
192224 cx. declare_fn ( sym, & fn_abi, None )
193225 } else {
194226 cx. declare_global ( sym, cx. type_i8 ( ) )
@@ -217,7 +249,24 @@ fn check_and_apply_linkage<'ll, 'tcx>(
217249 } )
218250 } ) ;
219251 llvm:: set_linkage ( g2, llvm:: Linkage :: InternalLinkage ) ;
220- llvm:: set_initializer ( g2, g1) ;
252+
253+ // Sign the function pointer that is used to initialize the global
254+ let initializer = if should_sign {
255+ let key: u32 = 0 ;
256+ let discriminator: u64 = 0 ;
257+
258+ const_ptr_auth (
259+ cx. const_bitcast ( g1, llty) ,
260+ key,
261+ discriminator,
262+ None , /* address_diversity */
263+ )
264+ } else {
265+ g1
266+ } ;
267+
268+ llvm:: set_initializer ( g2, initializer) ;
269+
221270 g2
222271 } else if cx. tcx . sess . target . arch == Arch :: X86
223272 && common:: is_mingw_gnu_toolchain ( & cx. tcx . sess . target )
0 commit comments