Files
wasmtime/crates/wasi-common/winx/src/ntdll.rs
whitequark e5635f4bc9 winx: do not link directly to ntdll.dll. (#1739)
The documentation for RtlNtStatusToDosError explicitly tells to call
it via GetProcAddress. The documentation for NtQueryInformationFile
does not, but similar considerations apply because there is normally
no import library for ntdll.

The main reason to use GetProcAddress though is because MinGW does
include an import library for ntdll, this import library contains
a definition of setjmp, and because of the way rustc orders linker
arguments, this definition of setjmp conflicts with and gets picked
over the one in msvcrt. Using setjmp from ntdll is undesirable as it
is an undocumented API and it is missing from wine, making it harder
to develop wasmtime using a cross-compiler.

Fixes #1738.
2020-05-21 13:56:20 -05:00

91 lines
2.6 KiB
Rust

//! Module for importing functions from ntdll.dll.
//! The winapi crate does not expose these Windows API functions.
#![allow(nonstandard_style)]
use std::ffi::c_void;
use std::os::raw::c_ulong;
use std::os::windows::prelude::RawHandle;
use std::sync::atomic::{AtomicUsize, Ordering};
use winapi::shared::ntdef::NTSTATUS;
use winapi::um::libloaderapi::{GetModuleHandleA, GetProcAddress};
use winapi::um::winnt::ACCESS_MASK;
#[repr(C)]
#[derive(Copy, Clone)]
pub(crate) enum FILE_INFORMATION_CLASS {
FileAccessInformation = 8,
FileModeInformation = 16,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub(crate) union IO_STATUS_BLOCK_u {
pub Status: NTSTATUS,
pub Pointer: *mut c_void,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub(crate) struct IO_STATUS_BLOCK {
pub u: IO_STATUS_BLOCK_u,
pub Information: *mut c_void,
}
#[repr(C)]
#[derive(Copy, Clone, Default)]
pub(crate) struct FILE_ACCESS_INFORMATION {
pub AccessFlags: ACCESS_MASK,
}
#[repr(C)]
#[derive(Copy, Clone, Default)]
pub(crate) struct FILE_MODE_INFORMATION {
pub Mode: c_ulong,
}
impl Default for IO_STATUS_BLOCK {
#[inline]
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
macro_rules! ntdll_import {
{ fn $name:ident($($arg:ident: $argty:ty),*) -> $retty:ty; $($tail:tt)* } => {
pub(crate) unsafe fn $name($($arg: $argty),*) -> $retty {
static ADDRESS: AtomicUsize = AtomicUsize::new(0);
let address = match ADDRESS.load(Ordering::Relaxed) {
0 => {
let ntdll = GetModuleHandleA("ntdll\0".as_ptr() as *const i8);
let address = GetProcAddress(
ntdll,
concat!(stringify!($name), "\0").as_ptr() as *const i8,
) as usize;
assert!(address != 0);
ADDRESS.store(address, Ordering::Relaxed);
address
}
address => address
};
let func: unsafe fn($($argty),*) -> $retty = std::mem::transmute(address);
func($($arg),*)
}
ntdll_import! { $($tail)* }
};
{} => {};
}
ntdll_import! {
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationfile
fn NtQueryInformationFile(
FileHandle: RawHandle,
IoStatusBlock: *mut IO_STATUS_BLOCK,
FileInformation: *mut c_void,
Length: c_ulong,
FileInformationClass: FILE_INFORMATION_CLASS
) -> NTSTATUS;
// https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-rtlntstatustodoserror
fn RtlNtStatusToDosError(status: NTSTATUS) -> c_ulong;
}