Skip to main content

miri/shims/
extern_static.rs

1//! Provides the `extern static` that this platform expects.
2
3use rustc_span::Symbol;
4use rustc_target::spec::Os;
5
6use crate::*;
7
8impl<'tcx> MiriMachine<'tcx> {
9    fn add_extern_static(ecx: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) {
10        // This got just allocated, so there definitely is a pointer here.
11        let ptr = ptr.into_pointer_or_addr().unwrap();
12        ecx.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
13    }
14
15    fn alloc_extern_static(
16        ecx: &mut MiriInterpCx<'tcx>,
17        name: &str,
18        val: ImmTy<'tcx>,
19    ) -> InterpResult<'tcx> {
20        let place = ecx.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
21        ecx.write_immediate(*val, &place)?;
22        Self::add_extern_static(ecx, name, place.ptr());
23        interp_ok(())
24    }
25
26    /// Make `ptr` available as a weak symbol with the given name.
27    fn add_weak_symbol(
28        ecx: &mut MiriInterpCx<'tcx>,
29        name: &str,
30        ptr: Pointer,
31    ) -> InterpResult<'tcx> {
32        // Allocate the extra indirection place and add it to the map.
33        let layout = ecx.machine.layouts.mut_raw_ptr;
34        let place = ecx.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
35        ecx.write_scalar(Scalar::from_maybe_pointer(ptr, ecx), &place)?;
36        let weak_ptr = place.ptr().into_pointer_or_addr().unwrap();
37        ecx.machine.extern_statics_imports.try_insert(Symbol::intern(name), weak_ptr).unwrap();
38        interp_ok(())
39    }
40
41    /// Extern statics that are initialized with function pointers to the symbols of the same name.
42    fn weak_fn_symbols(ecx: &mut MiriInterpCx<'tcx>, names: &[&str]) -> InterpResult<'tcx> {
43        for name in names {
44            assert!(ecx.is_dyn_sym(name), "{name} is not a dynamic symbol");
45            let ptr = ecx.fn_ptr(FnVal::Other(DynSym::from_str(name)));
46            Self::add_weak_symbol(ecx, name, ptr.into())?;
47        }
48        interp_ok(())
49    }
50
51    /// Sets up the "extern statics" for this machine.
52    pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> {
53        if ecx.target_os_is_unix() {
54            // "environ" is mandated by POSIX.
55            let environ = ecx.machine.env_vars.unix().environ();
56            Self::add_extern_static(ecx, "environ", environ);
57            // We also provide it as a weak symbol, which is needed on FreeBSD.
58            Self::add_weak_symbol(ecx, "environ", environ)?;
59        }
60
61        match &ecx.tcx.sess.target.os {
62            Os::Linux => {
63                Self::weak_fn_symbols(ecx, &["getrandom", "gettid", "statx", "strlen"])?;
64            }
65            Os::Android => {
66                Self::weak_fn_symbols(
67                    ecx,
68                    &["signal", "getrandom", "gettid", "futimens", "preadv", "pwritev"],
69                )?;
70            }
71            Os::Windows => {
72                // "_tls_used"
73                // This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
74                let val = ImmTy::from_int(0, ecx.machine.layouts.u8);
75                Self::alloc_extern_static(ecx, "_tls_used", val)?;
76            }
77            Os::Illumos | Os::Solaris => {
78                Self::weak_fn_symbols(ecx, &["pthread_setname_np"])?;
79            }
80            _ => {} // No "extern statics" supported on this target.
81        }
82
83        // Also initialize `missing_weak_symbol`.
84        let place = ecx.allocate(ecx.machine.layouts.usize, MiriMemoryKind::ExternStatic.into())?;
85        ecx.write_null(&place)?;
86        ecx.machine.extern_static_weak_import_default =
87            Some(place.ptr().into_pointer_or_addr().unwrap());
88
89        interp_ok(())
90    }
91}