miri/shims/
extern_static.rs

1//! Provides the `extern static` that this platform expects.
2
3use rustc_symbol_mangling::mangle_internal_symbol;
4
5use crate::*;
6
7impl<'tcx> MiriMachine<'tcx> {
8    fn alloc_extern_static(
9        ecx: &mut MiriInterpCx<'tcx>,
10        name: &str,
11        val: ImmTy<'tcx>,
12    ) -> InterpResult<'tcx> {
13        let place = ecx.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
14        ecx.write_immediate(*val, &place)?;
15        Self::add_extern_static(ecx, name, place.ptr());
16        interp_ok(())
17    }
18
19    /// Zero-initialized pointer-sized extern statics are pretty common.
20    /// Most of them are for weak symbols, which we all set to null (indicating that the
21    /// symbol is not supported, and triggering fallback code which ends up calling
22    /// some other shim that we do support).
23    fn null_ptr_extern_statics(ecx: &mut MiriInterpCx<'tcx>, names: &[&str]) -> InterpResult<'tcx> {
24        for name in names {
25            let val = ImmTy::from_int(0, ecx.machine.layouts.usize);
26            Self::alloc_extern_static(ecx, name, val)?;
27        }
28        interp_ok(())
29    }
30
31    /// Extern statics that are initialized with function pointers to the symbols of the same name.
32    fn weak_symbol_extern_statics(
33        ecx: &mut MiriInterpCx<'tcx>,
34        names: &[&str],
35    ) -> InterpResult<'tcx> {
36        for name in names {
37            assert!(ecx.is_dyn_sym(name), "{name} is not a dynamic symbol");
38            let layout = ecx.machine.layouts.const_raw_ptr;
39            let ptr = ecx.fn_ptr(FnVal::Other(DynSym::from_str(name)));
40            let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, ecx), layout);
41            Self::alloc_extern_static(ecx, name, val)?;
42        }
43        interp_ok(())
44    }
45
46    /// Sets up the "extern statics" for this machine.
47    pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> {
48        // "__rust_no_alloc_shim_is_unstable"
49        let val = ImmTy::from_int(0, ecx.machine.layouts.u8); // always 0, value does not matter
50        Self::alloc_extern_static(ecx, "__rust_no_alloc_shim_is_unstable", val)?;
51
52        // "__rust_alloc_error_handler_should_panic"
53        let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic();
54        let val = ImmTy::from_int(val, ecx.machine.layouts.u8);
55        Self::alloc_extern_static(
56            ecx,
57            &mangle_internal_symbol(*ecx.tcx, "__rust_alloc_error_handler_should_panic"),
58            val,
59        )?;
60
61        if ecx.target_os_is_unix() {
62            // "environ" is mandated by POSIX.
63            let environ = ecx.machine.env_vars.unix().environ();
64            Self::add_extern_static(ecx, "environ", environ);
65        }
66
67        match ecx.tcx.sess.target.os.as_ref() {
68            "linux" => {
69                Self::null_ptr_extern_statics(
70                    ecx,
71                    &["__cxa_thread_atexit_impl", "__clock_gettime64"],
72                )?;
73                Self::weak_symbol_extern_statics(ecx, &["getrandom", "statx"])?;
74            }
75            "freebsd" => {
76                Self::null_ptr_extern_statics(ecx, &["__cxa_thread_atexit_impl"])?;
77            }
78            "android" => {
79                Self::null_ptr_extern_statics(ecx, &["bsd_signal"])?;
80                Self::weak_symbol_extern_statics(ecx, &["signal", "getrandom"])?;
81            }
82            "windows" => {
83                // "_tls_used"
84                // This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
85                let val = ImmTy::from_int(0, ecx.machine.layouts.u8);
86                Self::alloc_extern_static(ecx, "_tls_used", val)?;
87            }
88            "illumos" | "solaris" => {
89                Self::weak_symbol_extern_statics(ecx, &["pthread_setname_np"])?;
90            }
91            _ => {} // No "extern statics" supported on this target
92        }
93        interp_ok(())
94    }
95}