@@ -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