@@ -158,6 +158,81 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
158
158
Ok ( ( ) )
159
159
}
160
160
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
+
161
236
/// Lookup the body of a function that has `link_name` as the symbol name.
162
237
fn lookup_exported_symbol (
163
238
& mut self ,
0 commit comments