miri/shims/
extern_static.rs

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