use super::super::super::windows::*; use super::mystd::os::windows::prelude::*; use super::{coff, mmap, Library, LibrarySegment, OsString}; use alloc::vec; use alloc::vec::Vec; use core::mem; use core::mem::MaybeUninit; // For loading native libraries on Windows, see some discussion on // rust-lang/rust#71060 for the various strategies here. pub(super) fn native_libraries() -> Vec { let mut ret = Vec::new(); unsafe { add_loaded_images(&mut ret); } return ret; } unsafe fn add_loaded_images(ret: &mut Vec) { let snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); if snap == INVALID_HANDLE_VALUE { return; } let mut me = MaybeUninit::::zeroed().assume_init(); me.dwSize = mem::size_of_val(&me) as DWORD; if Module32FirstW(snap, &mut me) == TRUE { loop { if let Some(lib) = load_library(&me) { ret.push(lib); } if Module32NextW(snap, &mut me) != TRUE { break; } } } CloseHandle(snap); } unsafe fn load_library(me: &MODULEENTRY32W) -> Option { let pos = me .szExePath .iter() .position(|i| *i == 0) .unwrap_or(me.szExePath.len()); let name = OsString::from_wide(&me.szExePath[..pos]); // MinGW libraries currently don't support ASLR // (rust-lang/rust#16514), but DLLs can still be relocated around in // the address space. It appears that addresses in debug info are // all as-if this library was loaded at its "image base", which is a // field in its COFF file headers. Since this is what debuginfo // seems to list we parse the symbol table and store addresses as if // the library was loaded at "image base" as well. // // The library may not be loaded at "image base", however. // (presumably something else may be loaded there?) This is where // the `bias` field comes into play, and we need to figure out the // value of `bias` here. Unfortunately though it's not clear how to // acquire this from a loaded module. What we do have, however, is // the actual load address (`modBaseAddr`). // // As a bit of a cop-out for now we mmap the file, read the file // header information, then drop the mmap. This is wasteful because // we'll probably reopen the mmap later, but this should work well // enough for now. // // Once we have the `image_base` (desired load location) and the // `base_addr` (actual load location) we can fill in the `bias` // (difference between the actual and desired) and then the stated // address of each segment is the `image_base` since that's what the // file says. // // For now it appears that unlike ELF/MachO we can make do with one // segment per library, using `modBaseSize` as the whole size. let mmap = mmap(name.as_ref())?; let image_base = coff::get_image_base(&mmap)?; let base_addr = me.modBaseAddr as usize; Some(Library { name, bias: base_addr.wrapping_sub(image_base), segments: vec![LibrarySegment { stated_virtual_memory_address: image_base, len: me.modBaseSize as usize, }], }) }