@@ -158,6 +158,81 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
158158 Ok ( ( ) )
159159 }
160160
161+ fn lookup_init_array ( & mut self ) -> InterpResult < ' tcx , Vec < ty:: Instance < ' tcx > > > {
162+ let this = self . eval_context_mut ( ) ;
163+ let tcx = this. tcx . tcx ;
164+
165+ let mut init_arrays = vec ! [ ] ;
166+
167+ let dependency_formats = tcx. dependency_formats ( ( ) ) ;
168+ let dependency_format = dependency_formats
169+ . iter ( )
170+ . find ( |( crate_type, _) | * crate_type == CrateType :: Executable )
171+ . expect ( "interpreting a non-executable crate" ) ;
172+ for cnum in iter:: once ( LOCAL_CRATE ) . chain (
173+ dependency_format. 1 . iter ( ) . enumerate ( ) . filter_map ( |( num, & linkage) | {
174+ // We add 1 to the number because that's what rustc also does everywhere it
175+ // calls `CrateNum::new`...
176+ #[ allow( clippy:: arithmetic_side_effects) ]
177+ ( linkage != Linkage :: NotLinked ) . then_some ( CrateNum :: new ( num + 1 ) )
178+ } ) ,
179+ ) {
180+ for & ( symbol, _export_info) in tcx. exported_symbols ( cnum) {
181+ if let ExportedSymbol :: NonGeneric ( def_id) = symbol {
182+ let attrs = tcx. codegen_fn_attrs ( def_id) ;
183+ let link_section = if let Some ( link_section) = attrs. link_section {
184+ if !link_section. as_str ( ) . starts_with ( ".init_array" ) {
185+ continue ;
186+ }
187+ link_section
188+ } else {
189+ continue ;
190+ } ;
191+
192+ init_arrays. push ( ( link_section, def_id) ) ;
193+ }
194+ }
195+ }
196+
197+ init_arrays. sort_by ( |( a, _) , ( b, _) | a. as_str ( ) . cmp ( b. as_str ( ) ) ) ;
198+
199+ let endianness = tcx. data_layout . endian ;
200+ let ptr_size = tcx. data_layout . pointer_size ;
201+
202+ let mut init_array = vec ! [ ] ;
203+
204+ for ( _, def_id) in init_arrays {
205+ let alloc = tcx. eval_static_initializer ( def_id) ?. inner ( ) ;
206+ let mut expected_offset = Size :: ZERO ;
207+ for & ( offset, prov) in alloc. provenance ( ) . ptrs ( ) . iter ( ) {
208+ if offset != expected_offset {
209+ throw_ub_format ! ( ".init_array.* may not contain any non-function pointer data" ) ;
210+ }
211+ expected_offset += ptr_size;
212+
213+ let alloc_id = prov. alloc_id ( ) ;
214+
215+ let reloc_target_alloc = tcx. global_alloc ( alloc_id) ;
216+ match reloc_target_alloc {
217+ GlobalAlloc :: Function ( instance) => {
218+ let addend = {
219+ let offset = offset. bytes ( ) as usize ;
220+ let bytes = & alloc. inspect_with_uninit_and_ptr_outside_interpreter (
221+ offset..offset + ptr_size. bytes ( ) as usize ,
222+ ) ;
223+ read_target_uint ( endianness, bytes) . unwrap ( )
224+ } ;
225+ assert_eq ! ( addend, 0 ) ;
226+ init_array. push ( instance) ;
227+ }
228+ _ => throw_ub_format ! ( ".init_array.* member is not a function pointer" ) ,
229+ }
230+ }
231+ }
232+
233+ Ok ( init_array)
234+ }
235+
161236 /// Lookup the body of a function that has `link_name` as the symbol name.
162237 fn lookup_exported_symbol (
163238 & mut self ,
0 commit comments